Optimize merkle tree computations gas usage by minimizing vector movements (#1069)

This commit is contained in:
Amin Moghaddam 2023-09-28 16:47:05 +02:00 committed by GitHub
parent 9714a851eb
commit 345a6081c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 37 additions and 22 deletions

View File

@ -3,7 +3,6 @@
module pyth::merkle_tree {
use std::vector::{Self};
use sui::hash::{keccak256};
use wormhole::bytes::{Self};
use wormhole::bytes20::{Self, Bytes20, data};
use wormhole::cursor::{Self, Cursor};
use pyth::deserialize::{Self};
@ -17,10 +16,13 @@ module pyth::merkle_tree {
// take keccak256 of input data, then return 20 leftmost bytes of result
fun hash(bytes: &vector<u8>): Bytes20 {
let hashed_bytes = keccak256(bytes);
let cursor = cursor::new(hashed_bytes);
let bytes20 = bytes::take_bytes(&mut cursor, 20);
cursor::take_rest(cursor);
bytes20::from_bytes(bytes20)
let hash_prefix = vector::empty<u8>();
let i = 0;
while (i < 20) {
vector::push_back(&mut hash_prefix, *vector::borrow(&hashed_bytes, i));
i = i + 1;
};
bytes20::new(hash_prefix)
}
fun empty_leaf_hash(): Bytes20 {
@ -30,7 +32,11 @@ module pyth::merkle_tree {
fun leaf_hash(data: &vector<u8>): Bytes20 {
let v = vector<u8>[MERKLE_LEAF_PREFIX];
vector::append(&mut v, *data);
let i = 0;
while (i < vector::length(data)) {
vector::push_back(&mut v, *vector::borrow(data, i));
i = i + 1;
};
hash(&v)
}
@ -38,32 +44,41 @@ module pyth::merkle_tree {
childA: Bytes20,
childB: Bytes20
): Bytes20 {
if (greater_than(childA, childB)) {
if (greater_than(&childA, &childB)) {
(childA, childB) = (childB, childA);
};
// append data_B to data_A
let data_A = bytes20::data(&childA);
let data_B = bytes20::data(&childB);
vector::append(&mut data_A, data_B);
// create a vector containing MERKLE_NODE_PREFIX and append data_A to back
let v = vector::empty<u8>();
vector::push_back(&mut v, MERKLE_NODE_PREFIX);
vector::append(&mut v, data_A);
// create a vector containing MERKLE_NODE_PREFIX + data_A + data_B
let v = vector<u8>[MERKLE_NODE_PREFIX];
let i = 0;
while (i < 20) {
vector::push_back(&mut v, *vector::borrow(&data_A, i));
i = i + 1;
};
let i = 0;
while (i < 20) {
vector::push_back(&mut v, *vector::borrow(&data_B, i));
i = i + 1;
};
hash(&v)
}
// greater_than returns whether a is strictly greater than b
// note that data(&a) and data(&b) are both vector<u8>s of length 20
fun greater_than(a: Bytes20, b: Bytes20): bool{
fun greater_than(a: &Bytes20, b: &Bytes20): bool {
// aa and bb both have length 20
let aa = data(&a);
let bb = data(&b);
let a_vector = data(a);
let b_vector = data(b);
let i = 0;
while (i < 20){
if (*vector::borrow(&aa, i) > *vector::borrow(&bb, i)){
while (i < 20) {
let a_value = *vector::borrow(&a_vector, i);
let b_value = *vector::borrow(&b_vector, i);
if (a_value > b_value) {
return true
} else if (*vector::borrow(&bb, i) > *vector::borrow(&aa, i)){
} else if (b_value > a_value) {
return false
};
i = i + 1;
@ -183,21 +198,21 @@ module pyth::merkle_tree {
// test 1
let x = bytes20::new(x"0000000000000000000000000000000000001000");
let y = bytes20::new(x"0000000000000000000000000000000000000001");
let res = greater_than(x, y);
let res = greater_than(&x, &y);
assert!(res==true, 0);
res = greater_than(y, x);
res = greater_than(&y, &x);
assert!(res==false, 0);
// test 2
x = bytes20::new(x"1100000000000000000000000000000000001000");
y = bytes20::new(x"1100000000000000000000000000000000000001");
res = greater_than(x, y);
res = greater_than(&x, &y);
assert!(res==true, 0);
// equality case
x = bytes20::new(x"1100000000000000000000000000000000001001");
y = bytes20::new(x"1100000000000000000000000000000000001001");
res = greater_than(x, y);
res = greater_than(&x, &y);
assert!(res==false, 0);
}