mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
refactor: adapt to standalone zktrie module (#165)
* adapt zktrie: zktrie part * adapt unittests * pass tests * refactor for new zktrie module * run go imports
This commit is contained in:
parent
b3a7c9b691
commit
e6500918a0
18 changed files with 234 additions and 1956 deletions
|
|
@ -24,6 +24,8 @@ import (
|
|||
"sort"
|
||||
"time"
|
||||
|
||||
zkt "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
||||
"github.com/scroll-tech/go-ethereum/core/state/snapshot"
|
||||
|
|
@ -316,18 +318,14 @@ func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
|
|||
// GetProof returns the Merkle proof for a given account.
|
||||
func (s *StateDB) GetProof(addr common.Address) ([][]byte, error) {
|
||||
if s.IsZktrie() {
|
||||
var proof proofList
|
||||
err := s.trie.Prove(addr.Bytes32(), 0, &proof)
|
||||
return proof, err
|
||||
addr_s, _ := zkt.ToSecureKeyBytes(addr.Bytes())
|
||||
return s.GetProofByHash(common.BytesToHash(addr_s.Bytes()))
|
||||
}
|
||||
return s.GetProofByHash(crypto.Keccak256Hash(addr.Bytes()))
|
||||
}
|
||||
|
||||
// GetProofByHash returns the Merkle proof for a given account.
|
||||
func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) {
|
||||
if s.IsZktrie() {
|
||||
panic("unimplemented")
|
||||
}
|
||||
var proof proofList
|
||||
err := s.trie.Prove(addrHash[:], 0, &proof)
|
||||
return proof, err
|
||||
|
|
@ -366,7 +364,8 @@ func (s *StateDB) GetStorageTrieProof(a common.Address, key common.Hash) ([][]by
|
|||
|
||||
var proof proofList
|
||||
if s.IsZktrie() {
|
||||
err = trie.Prove(key.Bytes(), 0, &proof)
|
||||
key_s, _ := zkt.ToSecureKeyBytes(key.Bytes())
|
||||
err = trie.Prove(key_s.Bytes(), 0, &proof)
|
||||
} else {
|
||||
err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
|
||||
}
|
||||
|
|
@ -382,7 +381,8 @@ func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte,
|
|||
}
|
||||
var err error
|
||||
if s.IsZktrie() {
|
||||
err = trie.Prove(key.Bytes(), 0, &proof)
|
||||
key_s, _ := zkt.ToSecureKeyBytes(key.Bytes())
|
||||
err = trie.Prove(key_s.Bytes(), 0, &proof)
|
||||
} else {
|
||||
err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ import (
|
|||
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||
"github.com/iden3/go-iden3-crypto/utils"
|
||||
|
||||
zkt "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -56,10 +57,7 @@ func (s *StateAccount) Hash() (*big.Int, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
rootHash, err := zkt.NewHashFromBytes(s.Root.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rootHash := zkt.NewHashFromBytes(s.Root.Bytes())
|
||||
hash3, err := poseidon.Hash([]*big.Int{hash2, rootHash.BigInt()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
zktrie "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
)
|
||||
|
||||
func TestAccountMarshalling(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -1,143 +0,0 @@
|
|||
# Type for zktrie
|
||||
|
||||
## Data Format in stateDb
|
||||
|
||||
All data node being stored via stateDb are encoded by following syntax:
|
||||
|
||||
``` EBNF
|
||||
node = magic string | node data ;
|
||||
|
||||
magic string = "THIS IS SOME MAGIC BYTES FOR SMT m1rRXgP2xpDI" ;
|
||||
|
||||
node data = middle node | leaf node | empty node ;
|
||||
|
||||
empty node = '0x2' ;
|
||||
|
||||
middle node = '0x0', left hash, right hash ;
|
||||
|
||||
field = 32 * hex char ;
|
||||
|
||||
left hash = field ;
|
||||
|
||||
right hash = field ;
|
||||
|
||||
leaf node = node key , value len , compress flag , <value len> * value field, key preimage ;
|
||||
|
||||
node key = field ;
|
||||
|
||||
compress flag = 3 * byte ;
|
||||
|
||||
value len = byte ;
|
||||
|
||||
value field = field | compressed field, compressed field ;
|
||||
|
||||
compressed field = 16 * hex char ;
|
||||
|
||||
key preimage = '0x0' | preimage bytes ;
|
||||
|
||||
preimage bytes = len, <len> * byte ;
|
||||
|
||||
len = byte ;
|
||||
```
|
||||
|
||||
A `field` is an element in prime field of BN256 represented by **big endian** integer and contained in fixed length (32) bytes;
|
||||
|
||||
A `compressed field` is a field represented by **big endian** integer which could be contained in 16 bytes;
|
||||
|
||||
For the total `value len` items of `value field` (maximum 255), the first 24 `value field`s can be recorded as `field` or 2x `compressed field` (i.e. a byte32). The corresonpdoing bit in `compress flag` is set to 1 if it was recorded as byte32, or 0 for a field.
|
||||
|
||||
## Key scheme
|
||||
|
||||
The key of data node is obtained from one or more poseidon hash calculation: `poseidon := (field, field) => field`.
|
||||
|
||||
For middle node:
|
||||
|
||||
```
|
||||
key = poseidon(<left hash>, <right hash>)
|
||||
```
|
||||
|
||||
For leaf node:
|
||||
|
||||
```
|
||||
key = poseidon(<pre key>, <value hash>)
|
||||
|
||||
pre key = poseidon(field(1), <node key>)
|
||||
|
||||
value hash = poseidon(<leaf element>, <leaf element>) | poseidon(<value hash>, <value hash>)
|
||||
|
||||
leaf element = <value field as field> | poseidon(<compressed field as field>, <compressed field as field>) | field(0)
|
||||
|
||||
```
|
||||
|
||||
That is, to calculate the key of a leaf node:
|
||||
|
||||
1. In the sequence of `value field`s, take which is recorded as 'compressed' and calculate the 2x `compressed field` for its poseidon hash, replace the corresponding `value field` ad-hoc in the sequence;
|
||||
|
||||
2. Consider the sequence from 1 as the leafs of a binary merkle tree (append a 0 field for odd leafs) and calculate its root by poseidon hash;
|
||||
|
||||
For empty node:
|
||||
|
||||
```
|
||||
key = field(0)
|
||||
```
|
||||
|
||||
## Account data
|
||||
|
||||
Each account data is saved in one leaf node of account zktrie as 4 `value field`s:
|
||||
|
||||
1. Nonce as `field`
|
||||
2. Balance as `field`
|
||||
3. CodeHash as `compressed field` (byte32)
|
||||
4. Storage root as `field`
|
||||
|
||||
The key for an account data is calculated from the 20-bit account address as following:
|
||||
|
||||
```
|
||||
|
||||
32-byte-zero-end-padding-addr := address, 16 * bytes (0)
|
||||
|
||||
key = poseidon(<first 16 byte of 32-byte-zero-end-padding-addr as field>, <last 16 byte of 32-byte-zero-end-padding-addr as field>)
|
||||
|
||||
```
|
||||
|
||||
## Data examples
|
||||
|
||||
### A leaf node in account trie:
|
||||
|
||||
> 0x017f9d3bbc51d12566ecc6049ca6bf76e32828c22b197405f63a833b566fe7da0a040400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000029b74e075daad9f17eb39cd893c2dd32f52ecd99084d63964842defd00ebcbe208a2f471d50e56ac5000ab9e82f871e36b5a636b19bd02f70aa666a3bd03142f00
|
||||
|
||||
Can be decompose to:
|
||||
|
||||
+ `0x01`: node type prefix for leaf node
|
||||
+ `7f9d3bbc51d12566ecc6049ca6bf76e32828c22b197405f63a833b566fe7da0a`: node key as field
|
||||
+ `04`: value len (4 value fields)
|
||||
+ `040000`: compress flag, a 24 bit array, indicating the third field is compressed
|
||||
+ `0000000000000000000000000000000000000000000000000000000000000001`: value field 0 (nonce)
|
||||
+ `0000000000000000000000000000000000000000000000000000000000000000`: value field 1 (balance)
|
||||
+ `29b74e075daad9f17eb39cd893c2dd32f52ecd99084d63964842defd00ebcbe2`: value field 2 (codeHash, as byte32)
|
||||
+ `08a2f471d50e56ac5000ab9e82f871e36b5a636b19bd02f70aa666a3bd03142f`: value field 3 (storage root)
|
||||
+ `00`: key preimage is not avaliable
|
||||
|
||||
The key calculation for this node is:
|
||||
|
||||
```
|
||||
|
||||
arr = [<value field 0>, <value field 1>, <value field 2>, <value field 3>]
|
||||
|
||||
hash_pre = poseidon(<first 16 byte for value field 2>, <last 16 byte for value field 2>)
|
||||
|
||||
arr[2] = hash_pre
|
||||
|
||||
layer1 = [poseidon(arr[0], arr[1]), poseidon(arr[2], arr[3])]
|
||||
|
||||
key = poseidon(layer1[0], layer1[1])
|
||||
|
||||
```
|
||||
|
||||
Notice all field and compressed field are represented as **big endian** integer.
|
||||
|
||||
### A middle node in account trie:
|
||||
|
||||
> 0x00000000000000000000000000000000000000000000000000000000000000000004470b58d80eeb26da85b2c2db5c254900656fb459c07729f556ff02534ab32a
|
||||
|
||||
Notice the left child of this node is an empty node (so its key is field(0))
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package zktrie
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||
)
|
||||
|
||||
type Byte32 [32]byte
|
||||
|
||||
func (b *Byte32) Hash() (*big.Int, error) {
|
||||
first16 := new(big.Int).SetBytes(b[0:16])
|
||||
last16 := new(big.Int).SetBytes(b[16:32])
|
||||
hash, err := poseidon.Hash([]*big.Int{first16, last16})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func (b *Byte32) Bytes() []byte { return b[:] }
|
||||
|
||||
// same action as common.Hash (truncate bytes longer than 32 bytes FROM beginning,
|
||||
// and padding 0 at the beginning for shorter bytes)
|
||||
func NewByte32FromBytes(b []byte) *Byte32 {
|
||||
|
||||
byte32 := new(Byte32)
|
||||
|
||||
if len(b) > 32 {
|
||||
b = b[len(b)-32:]
|
||||
}
|
||||
|
||||
copy(byte32[32-len(b):], b)
|
||||
return byte32
|
||||
}
|
||||
|
||||
func NewByte32FromBytesPaddingZero(b []byte) *Byte32 {
|
||||
if len(b) != 32 && len(b) != 20 {
|
||||
panic(fmt.Errorf("do not support length except for 120bit and 256bit now. data: %v len: %v", b, len(b)))
|
||||
}
|
||||
byte32 := new(Byte32)
|
||||
copy(byte32[:], b)
|
||||
return byte32
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
package zktrie
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/iden3/go-iden3-crypto/utils"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
)
|
||||
|
||||
const numCharPrint = 8
|
||||
|
||||
// ElemBytesLen is the length of the Hash byte array
|
||||
const ElemBytesLen = 32
|
||||
|
||||
var HashZero = Hash{}
|
||||
|
||||
// Hash is the generic type stored in the MerkleTree
|
||||
type Hash [32]byte
|
||||
|
||||
// MarshalText implements the marshaler for the Hash type
|
||||
func (h Hash) MarshalText() ([]byte, error) {
|
||||
return []byte(h.BigInt().String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the unmarshaler for the Hash type
|
||||
func (h *Hash) UnmarshalText(b []byte) error {
|
||||
ha, err := NewHashFromString(string(b))
|
||||
copy(h[:], ha[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// String returns decimal representation in string format of the Hash
|
||||
func (h Hash) String() string {
|
||||
s := h.BigInt().String()
|
||||
if len(s) < numCharPrint {
|
||||
return s
|
||||
}
|
||||
return s[0:numCharPrint] + "..."
|
||||
}
|
||||
|
||||
// Hex returns the hexadecimal representation of the Hash
|
||||
func (h Hash) Hex() string {
|
||||
return hex.EncodeToString(h[:])
|
||||
}
|
||||
|
||||
// BigInt returns the *big.Int representation of the *Hash
|
||||
func (h *Hash) BigInt() *big.Int {
|
||||
if new(big.Int).SetBytes(ReverseByteOrder(h[:])) == nil {
|
||||
return big.NewInt(0)
|
||||
}
|
||||
return new(big.Int).SetBytes(ReverseByteOrder(h[:]))
|
||||
}
|
||||
|
||||
// Bytes returns the little endian []byte representation of the *Hash, which always is 32
|
||||
// bytes length.
|
||||
func (h *Hash) Bytes() []byte {
|
||||
b := [32]byte{}
|
||||
copy(b[:], h[:])
|
||||
return ReverseByteOrder(b[:])
|
||||
}
|
||||
|
||||
// NewBigIntFromHashBytes returns a *big.Int from a byte array, swapping the
|
||||
// endianness in the process. This is the intended method to get a *big.Int
|
||||
// from a byte array that previously has ben generated by the Hash.Bytes()
|
||||
// method.
|
||||
func NewBigIntFromHashBytes(b []byte) (*big.Int, error) {
|
||||
if len(b) != ElemBytesLen {
|
||||
return nil, fmt.Errorf("expected 32 bytes, found %d bytes", len(b))
|
||||
}
|
||||
bi := new(big.Int).SetBytes(b[:ElemBytesLen])
|
||||
if !utils.CheckBigIntInField(bi) {
|
||||
return nil, fmt.Errorf("NewBigIntFromHashBytes: Value not inside the Finite Field")
|
||||
}
|
||||
return bi, nil
|
||||
}
|
||||
|
||||
// NewHashFromBigInt returns a *Hash representation of the given *big.Int
|
||||
func NewHashFromBigInt(b *big.Int) *Hash {
|
||||
r := &Hash{}
|
||||
copy(r[:], ReverseByteOrder(b.Bytes()))
|
||||
return r
|
||||
}
|
||||
|
||||
// NewHashFromBytes returns a *Hash from a byte array, swapping the endianness
|
||||
// in the process. This is the intended method to get a *Hash from a byte array
|
||||
// that previously has ben generated by the Hash.Bytes() method.
|
||||
func NewHashFromBytes(b []byte) (*Hash, error) {
|
||||
if len(b) != ElemBytesLen {
|
||||
return nil, fmt.Errorf("expected 32 bytes, found %d bytes", len(b))
|
||||
}
|
||||
var h Hash
|
||||
copy(h[:], ReverseByteOrder(b))
|
||||
return &h, nil
|
||||
}
|
||||
|
||||
// NewHashFromHex returns a *Hash representation of the given hex string
|
||||
func NewHashFromHex(h string) (*Hash, error) {
|
||||
return NewHashFromBytes(ReverseByteOrder(common.FromHex(h)))
|
||||
}
|
||||
|
||||
// NewHashFromString returns a *Hash representation of the given decimal string
|
||||
func NewHashFromString(s string) (*Hash, error) {
|
||||
bi, ok := new(big.Int).SetString(s, 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("can not parse string to Hash")
|
||||
}
|
||||
return NewHashFromBigInt(bi), nil
|
||||
}
|
||||
|
||||
// ReverseByteOrder swaps the order of the bytes in the slice.
|
||||
func ReverseByteOrder(b []byte) []byte {
|
||||
o := make([]byte, len(b))
|
||||
for i := range b {
|
||||
o[len(b)-1-i] = b[i]
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
package zktrie
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/crypto/poseidon"
|
||||
)
|
||||
|
||||
// HashElems performs a recursive poseidon hash over the array of ElemBytes, each hash
|
||||
// reduce 2 fieds into one
|
||||
func HashElems(fst, snd *big.Int, elems ...*big.Int) (*Hash, error) {
|
||||
|
||||
l := len(elems)
|
||||
baseH, err := poseidon.HashFixed([]*big.Int{fst, snd})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if l == 0 {
|
||||
return NewHashFromBigInt(baseH), nil
|
||||
} else if l == 1 {
|
||||
return HashElems(baseH, elems[0])
|
||||
}
|
||||
|
||||
tmp := make([]*big.Int, l/2)
|
||||
for i := range tmp {
|
||||
if (i+1)*2 > l {
|
||||
tmp[i] = elems[i*2+1]
|
||||
} else {
|
||||
h, err := poseidon.HashFixed(elems[i*2 : (i+1)*2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmp[i] = h
|
||||
}
|
||||
}
|
||||
|
||||
return HashElems(baseH, tmp[0], tmp[1:]...)
|
||||
}
|
||||
|
||||
// PreHandlingElems turn persisted byte32 elements into field arrays for our hashElem
|
||||
// it also has the compressed byte32
|
||||
func PreHandlingElems(flagArray uint32, elems []Byte32) (*Hash, error) {
|
||||
|
||||
ret := make([]*big.Int, len(elems))
|
||||
var err error
|
||||
|
||||
for i, elem := range elems {
|
||||
if flagArray&(1<<i) != 0 {
|
||||
ret[i], err = elem.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ret[i] = new(big.Int).SetBytes(elem[:])
|
||||
}
|
||||
}
|
||||
|
||||
if len(ret) < 2 {
|
||||
return NewHashFromBigInt(ret[0]), nil
|
||||
}
|
||||
|
||||
return HashElems(ret[0], ret[1], ret[2:]...)
|
||||
|
||||
}
|
||||
|
||||
// SetBitBigEndian sets the bit n in the bitmap to 1, in Big Endian.
|
||||
func SetBitBigEndian(bitmap []byte, n uint) {
|
||||
bitmap[uint(len(bitmap))-n/8-1] |= 1 << (n % 8)
|
||||
}
|
||||
|
||||
// TestBit tests whether the bit n in bitmap is 1.
|
||||
func TestBit(bitmap []byte, n uint) bool {
|
||||
return bitmap[n/8]&(1<<(n%8)) != 0
|
||||
}
|
||||
|
||||
// TestBitBigEndian tests whether the bit n in bitmap is 1, in Big Endian.
|
||||
func TestBitBigEndian(bitmap []byte, n uint) bool {
|
||||
return bitmap[uint(len(bitmap))-n/8-1]&(1<<(n%8)) != 0
|
||||
}
|
||||
|
||||
var BigOne = big.NewInt(1)
|
||||
var BigZero = big.NewInt(0)
|
||||
|
||||
func BigEndianBitsToBigInt(bits []bool) *big.Int {
|
||||
result := big.NewInt(0)
|
||||
for _, bit := range bits {
|
||||
result.Mul(result, big.NewInt(2))
|
||||
if bit {
|
||||
result.Add(result, BigOne)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
1
go.mod
1
go.mod
|
|
@ -49,6 +49,7 @@ require (
|
|||
github.com/prometheus/tsdb v0.7.1
|
||||
github.com/rjeczalik/notify v0.9.1
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/scroll-tech/zktrie v0.2.0
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
||||
github.com/stretchr/testify v1.7.0
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -380,6 +380,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
|||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/scroll-tech/zktrie v0.2.0 h1:Q0ieI5tKaexihFkNfhSEjiyza2lkQ8LbyKCMMdepKmA=
|
||||
github.com/scroll-tech/zktrie v0.2.0/go.mod h1:CuJFlG1/soTJJBAySxCZgTF7oPvd5qF6utHOEciC43Q=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
|
|
|
|||
179
trie/zk_trie.go
179
trie/zk_trie.go
|
|
@ -18,49 +18,50 @@ package trie
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
zktrie "github.com/scroll-tech/zktrie/trie"
|
||||
zkt "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
"github.com/scroll-tech/go-ethereum/crypto/poseidon"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
)
|
||||
|
||||
// ZkTrie wraps a trie with key hashing. In a secure trie, all
|
||||
// access operations hash the key using keccak256. This prevents
|
||||
// calling code from creating long chains of nodes that
|
||||
// increase the access time.
|
||||
//
|
||||
// Contrary to a regular trie, a ZkTrie can only be created with
|
||||
// New and must have an attached database. The database also stores
|
||||
// the preimage of each key.
|
||||
//
|
||||
// ZkTrie is not safe for concurrent use.
|
||||
var magicHash []byte = []byte("THIS IS THE MAGIC INDEX FOR ZKTRIE")
|
||||
|
||||
// wrap zktrie for trie interface
|
||||
type ZkTrie struct {
|
||||
tree *ZkTrieImpl
|
||||
*zktrie.ZkTrie
|
||||
db *ZktrieDatabase
|
||||
}
|
||||
|
||||
func init() {
|
||||
zkt.InitHashScheme(poseidon.HashFixed)
|
||||
}
|
||||
|
||||
func santiyCheckByte32Key(b []byte) {
|
||||
if len(b) != 32 && len(b) != 20 {
|
||||
panic(fmt.Errorf("do not support length except for 120bit and 256bit now. data: %v len: %v", b, len(b)))
|
||||
}
|
||||
}
|
||||
|
||||
// NewSecure creates a trie
|
||||
// SecureBinaryTrie bypasses all the buffer mechanism in *Database, it directly uses the
|
||||
// underlying diskdb
|
||||
func NewZkTrie(root common.Hash, db *ZktrieDatabase) (*ZkTrie, error) {
|
||||
rootHash, err := zkt.NewHashFromBytes(root.Bytes())
|
||||
tr, err := zktrie.NewZkTrie(*zkt.NewByte32FromBytes(root.Bytes()), db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tree, err := NewZkTrieImplWithRoot((db), rootHash, 256)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ZkTrie{
|
||||
tree: tree,
|
||||
}, nil
|
||||
return &ZkTrie{tr, db}, nil
|
||||
}
|
||||
|
||||
// Get returns the value for key stored in the trie.
|
||||
// The value bytes must not be modified by the caller.
|
||||
func (t *ZkTrie) Get(key []byte) []byte {
|
||||
santiyCheckByte32Key(key)
|
||||
res, err := t.TryGet(key)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
||||
|
|
@ -68,45 +69,12 @@ func (t *ZkTrie) Get(key []byte) []byte {
|
|||
return res
|
||||
}
|
||||
|
||||
// TryGet returns the value for key stored in the trie.
|
||||
// The value bytes must not be modified by the caller.
|
||||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (t *ZkTrie) TryGet(key []byte) ([]byte, error) {
|
||||
word := zkt.NewByte32FromBytesPaddingZero(key)
|
||||
k, err := word.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return t.tree.TryGet(k.Bytes())
|
||||
}
|
||||
|
||||
// TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not
|
||||
// possible to use keybyte-encoding as the path might contain odd nibbles.
|
||||
func (t *ZkTrie) TryGetNode(path []byte) ([]byte, int, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (t *ZkTrie) updatePreimage(preimage []byte, hashField *big.Int) {
|
||||
db := t.tree.db.db
|
||||
if db.preimages != nil { // Ugly direct check but avoids the below write lock
|
||||
db.lock.Lock()
|
||||
// we must copy the input key
|
||||
db.insertPreimage(common.BytesToHash(hashField.Bytes()), common.CopyBytes(preimage))
|
||||
db.lock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// TryUpdateAccount will abstract the write of an account to the
|
||||
// secure trie.
|
||||
func (t *ZkTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error {
|
||||
keyPreimage := zkt.NewByte32FromBytesPaddingZero(key)
|
||||
k, err := keyPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.updatePreimage(key, k)
|
||||
return t.tree.TryUpdateAccount(k.Bytes(), acc)
|
||||
santiyCheckByte32Key(key)
|
||||
value, flag := acc.MarshalFields()
|
||||
return t.ZkTrie.TryUpdate(key, flag, value)
|
||||
}
|
||||
|
||||
// Update associates key with value in the trie. Subsequent calls to
|
||||
|
|
@ -121,51 +89,21 @@ func (t *ZkTrie) Update(key, value []byte) {
|
|||
}
|
||||
}
|
||||
|
||||
// TryUpdate associates key with value in the trie. Subsequent calls to
|
||||
// Get will return value. If value has length zero, any existing value
|
||||
// is deleted from the trie and calls to Get will return nil.
|
||||
//
|
||||
// The value bytes must not be modified by the caller while they are
|
||||
// stored in the trie.
|
||||
//
|
||||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
//
|
||||
// NOTE: value is restricted to length of bytes32.
|
||||
// we override the underlying zktrie's TryUpdate method
|
||||
func (t *ZkTrie) TryUpdate(key, value []byte) error {
|
||||
keyPreimage := zkt.NewByte32FromBytesPaddingZero(key)
|
||||
k, err := keyPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.updatePreimage(key, k)
|
||||
return t.tree.TryUpdate(k.Bytes(), value)
|
||||
santiyCheckByte32Key(key)
|
||||
return t.ZkTrie.TryUpdate(key, 1, []zkt.Byte32{*zkt.NewByte32FromBytes(value)})
|
||||
}
|
||||
|
||||
// Delete removes any existing value for key from the trie.
|
||||
func (t *ZkTrie) Delete(key []byte) {
|
||||
santiyCheckByte32Key(key)
|
||||
if err := t.TryDelete(key); err != nil {
|
||||
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// TryDelete removes any existing value for key from the trie.
|
||||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (t *ZkTrie) TryDelete(key []byte) error {
|
||||
keyPreimage := zkt.NewByte32FromBytesPaddingZero(key)
|
||||
k, err := keyPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//mitigate the create-delete issue: do not delete unexisted key
|
||||
if r := t.tree.Get(k.Bytes()); r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: when tryDelete get more solid test, use it instead
|
||||
return t.tree.tryDeleteLite(zkt.NewHashFromBigInt(k))
|
||||
}
|
||||
|
||||
// GetKey returns the preimage of a hashed key that was
|
||||
// previously used to store a value.
|
||||
func (t *ZkTrie) GetKey(kHashBytes []byte) []byte {
|
||||
|
|
@ -175,7 +113,7 @@ func (t *ZkTrie) GetKey(kHashBytes []byte) []byte {
|
|||
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
||||
}
|
||||
|
||||
return t.tree.db.db.preimage(common.BytesToHash(k.Bytes()))
|
||||
return t.db.db.preimage(common.BytesToHash(k.Bytes()))
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -194,19 +132,13 @@ func (t *ZkTrie) Commit(LeafCallback) (common.Hash, int, error) {
|
|||
// database and can be used even if the trie doesn't have one.
|
||||
func (t *ZkTrie) Hash() common.Hash {
|
||||
var hash common.Hash
|
||||
hash.SetBytes(t.tree.rootKey.Bytes())
|
||||
hash.SetBytes(t.ZkTrie.Hash())
|
||||
return hash
|
||||
}
|
||||
|
||||
// Copy returns a copy of SecureBinaryTrie.
|
||||
func (t *ZkTrie) Copy() *ZkTrie {
|
||||
cpy, err := NewZkTrieImplWithRoot(t.tree.db, t.tree.rootKey, t.tree.maxLevels)
|
||||
if err != nil {
|
||||
panic("clone trie failed")
|
||||
}
|
||||
return &ZkTrie{
|
||||
tree: cpy,
|
||||
}
|
||||
return &ZkTrie{t.ZkTrie.Copy(), t.db}
|
||||
}
|
||||
|
||||
// NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration
|
||||
|
|
@ -241,18 +173,13 @@ func (t *ZkTrie) NodeIterator(start []byte) NodeIterator {
|
|||
// nodes of the longest existing prefix of the key (at least the root node), ending
|
||||
// with the node that proves the absence of the key.
|
||||
func (t *ZkTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error {
|
||||
word := zkt.NewByte32FromBytesPaddingZero(key)
|
||||
k, err := word.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = t.tree.prove(zkt.NewHashFromBigInt(k), fromLevel, func(n *Node) error {
|
||||
err := t.ZkTrie.Prove(key, fromLevel, func(n *zktrie.Node) error {
|
||||
key, err := n.Key()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.Type == NodeTypeLeaf {
|
||||
if n.Type == zktrie.NodeTypeLeaf {
|
||||
preImage := t.GetKey(n.NodeKey.Bytes())
|
||||
if len(preImage) > 0 {
|
||||
n.KeyPreimage = &zkt.Byte32{}
|
||||
|
|
@ -260,7 +187,7 @@ func (t *ZkTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter)
|
|||
//return fmt.Errorf("key preimage not found for [%x] ref %x", n.NodeKey.Bytes(), k.Bytes())
|
||||
}
|
||||
}
|
||||
return proofDb.Put(key.Bytes(), n.Value())
|
||||
return proofDb.Put(key[:], n.Value())
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -268,5 +195,39 @@ func (t *ZkTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter)
|
|||
|
||||
// we put this special kv pair in db so we can distinguish the type and
|
||||
// make suitable Proof
|
||||
return proofDb.Put(magicHash, magicSMTBytes)
|
||||
return proofDb.Put(magicHash, zktrie.ProofMagicBytes())
|
||||
}
|
||||
|
||||
// VerifyProof checks merkle proofs. The given proof must contain the value for
|
||||
// key in a trie with the given root hash. VerifyProof returns an error if the
|
||||
// proof contains invalid trie nodes or the wrong value.
|
||||
func VerifyProofSMT(rootHash common.Hash, key []byte, proofDb ethdb.KeyValueReader) (value []byte, err error) {
|
||||
|
||||
h := zkt.NewHashFromBytes(rootHash.Bytes())
|
||||
k, err := zkt.ToSecureKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proof, n, err := zktrie.BuildZkTrieProof(h, k, len(key)*8, func(key *zkt.Hash) (*zktrie.Node, error) {
|
||||
buf, _ := proofDb.Get(key[:])
|
||||
if buf == nil {
|
||||
return nil, zktrie.ErrKeyNotFound
|
||||
}
|
||||
n, err := zktrie.NewNodeFromBytes(buf)
|
||||
return n, err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// do not contain the key
|
||||
return nil, err
|
||||
} else if !proof.Existence {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if zktrie.VerifyProofZkTrie(h, proof, n) {
|
||||
return n.Data(), nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("bad proof node %v", proof)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
package trie
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
// TODO: we should refactor codes, so ZktrieDatabase and Database become two implementation of a
|
||||
// interface later, making codes less surprising..
|
||||
// ZktrieDatabase Database adaptor
|
||||
// ZktrieDatabase Database adaptor imple zktrie.ZktrieDatbase
|
||||
type ZktrieDatabase struct {
|
||||
db *Database
|
||||
prefix []byte
|
||||
|
|
@ -48,6 +49,16 @@ func (l *ZktrieDatabase) Get(key []byte) ([]byte, error) {
|
|||
return v, err
|
||||
}
|
||||
|
||||
func (l *ZktrieDatabase) UpdatePreimage(preimage []byte, hashField *big.Int) {
|
||||
db := l.db
|
||||
if db.preimages != nil { // Ugly direct check but avoids the below write lock
|
||||
db.lock.Lock()
|
||||
// we must copy the input key
|
||||
db.insertPreimage(common.BytesToHash(hashField.Bytes()), common.CopyBytes(preimage))
|
||||
db.lock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate implements the method Iterate of the interface Storage
|
||||
func (l *ZktrieDatabase) Iterate(f func([]byte, []byte) (bool, error)) error {
|
||||
iter := l.db.diskdb.NewIterator(l.prefix, nil)
|
||||
|
|
|
|||
|
|
@ -1,970 +0,0 @@
|
|||
package trie
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// proofFlagsLen is the byte length of the flags in the proof header
|
||||
// (first 32 bytes).
|
||||
proofFlagsLen = 2
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNodeKeyAlreadyExists is used when a node key already exists.
|
||||
ErrNodeKeyAlreadyExists = errors.New("key already exists")
|
||||
// ErrKeyNotFound is used when a key is not found in the ZkTrieImpl.
|
||||
ErrKeyNotFound = errors.New("key not found in ZkTrieImpl")
|
||||
// ErrNodeBytesBadSize is used when the data of a node has an incorrect
|
||||
// size and can't be parsed.
|
||||
ErrNodeBytesBadSize = errors.New("node data has incorrect size in the DB")
|
||||
// ErrReachedMaxLevel is used when a traversal of the MT reaches the
|
||||
// maximum level.
|
||||
ErrReachedMaxLevel = errors.New("reached maximum level of the merkle tree")
|
||||
// ErrInvalidNodeFound is used when an invalid node is found and can't
|
||||
// be parsed.
|
||||
ErrInvalidNodeFound = errors.New("found an invalid node in the DB")
|
||||
// ErrInvalidProofBytes is used when a serialized proof is invalid.
|
||||
ErrInvalidProofBytes = errors.New("the serialized proof is invalid")
|
||||
// ErrEntryIndexAlreadyExists is used when the entry index already
|
||||
// exists in the tree.
|
||||
ErrEntryIndexAlreadyExists = errors.New("the entry index already exists in the tree")
|
||||
// ErrNotWritable is used when the ZkTrieImpl is not writable and a
|
||||
// write function is called
|
||||
ErrNotWritable = errors.New("merkle Tree not writable")
|
||||
|
||||
dbKeyRootNode = []byte("currentroot")
|
||||
)
|
||||
|
||||
// ZkTrieImpl is the struct with the main elements of the ZkTrieImpl
|
||||
type ZkTrieImpl struct {
|
||||
db *ZktrieDatabase
|
||||
rootKey *zkt.Hash
|
||||
writable bool
|
||||
maxLevels int
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func NewZkTrieImpl(storage *ZktrieDatabase, maxLevels int) (*ZkTrieImpl, error) {
|
||||
return NewZkTrieImplWithRoot(storage, &zkt.HashZero, maxLevels)
|
||||
}
|
||||
|
||||
// NewZkTrieImplWithRoot loads a new ZkTrieImpl. If in the storage already exists one
|
||||
// will open that one, if not, will create a new one.
|
||||
func NewZkTrieImplWithRoot(storage *ZktrieDatabase, root *zkt.Hash, maxLevels int) (*ZkTrieImpl, error) {
|
||||
mt := ZkTrieImpl{db: storage, maxLevels: maxLevels, writable: true}
|
||||
mt.rootKey = root
|
||||
if *root != zkt.HashZero {
|
||||
_, err := mt.GetNode(mt.rootKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &mt, nil
|
||||
}
|
||||
|
||||
// DB returns the ZkTrieImpl.DB()
|
||||
func (mt *ZkTrieImpl) DB() *ZktrieDatabase {
|
||||
return mt.db
|
||||
}
|
||||
|
||||
// Root returns the MerkleRoot
|
||||
func (mt *ZkTrieImpl) Root() *zkt.Hash {
|
||||
if mt.Debug {
|
||||
_, err := mt.GetNode(mt.rootKey)
|
||||
if err != nil {
|
||||
var hash common.Hash
|
||||
hash.SetBytes(mt.rootKey.Bytes())
|
||||
panic(fmt.Errorf("load trie root failed hash %v", hash))
|
||||
}
|
||||
}
|
||||
return mt.rootKey
|
||||
}
|
||||
|
||||
// MaxLevels returns the MT maximum level
|
||||
func (mt *ZkTrieImpl) MaxLevels() int {
|
||||
return mt.maxLevels
|
||||
}
|
||||
|
||||
// tryUpdate update a Key & Value into the ZkTrieImpl. Where the `k` determines the
|
||||
// path from the Root to the Leaf. This also return the updated leaf node
|
||||
func (mt *ZkTrieImpl) tryUpdate(kHash *zkt.Hash, vFlag uint32, vPreimage []zkt.Byte32) error {
|
||||
// verify that the ZkTrieImpl is writable
|
||||
if !mt.writable {
|
||||
return ErrNotWritable
|
||||
}
|
||||
|
||||
// verify that k are valid and fit inside the Finite Field.
|
||||
if !cryptoUtils.CheckBigIntInField(kHash.BigInt()) {
|
||||
return errors.New("Key not inside the Finite Field")
|
||||
}
|
||||
|
||||
newNodeLeaf := NewNodeLeaf(kHash, vFlag, vPreimage)
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
|
||||
// precalc Key of new leaf here
|
||||
if _, err := newNodeLeaf.Key(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newRootKey, err := mt.addLeaf(newNodeLeaf, mt.rootKey, 0, path, true)
|
||||
// sanity check
|
||||
if err == ErrEntryIndexAlreadyExists {
|
||||
panic("Encounter unexpected errortype: ErrEntryIndexAlreadyExists")
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
mt.rootKey = newRootKey
|
||||
err = mt.dbInsert(dbKeyRootNode, DBEntryTypeRoot, mt.rootKey[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddWord
|
||||
// Deprecated: Add a Bytes32 kv to ZkTrieImpl, only for testing
|
||||
func (mt *ZkTrieImpl) AddWord(kPreimage, vPreimage *zkt.Byte32) error {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kHash := zkt.NewHashFromBigInt(k)
|
||||
newNodeLeaf := NewNodeLeaf(kHash, 1, []zkt.Byte32{*vPreimage})
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
|
||||
// precalc Key of new leaf here
|
||||
if _, err := newNodeLeaf.Key(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newRootKey, err := mt.addLeaf(newNodeLeaf, mt.rootKey, 0, path, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mt.rootKey = newRootKey
|
||||
err = mt.dbInsert(dbKeyRootNode, DBEntryTypeRoot, mt.rootKey[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pushLeaf recursively pushes an existing oldLeaf down until its path diverges
|
||||
// from newLeaf, at which point both leafs are stored, all while updating the
|
||||
// path.
|
||||
func (mt *ZkTrieImpl) pushLeaf(newLeaf *Node, oldLeaf *Node, lvl int,
|
||||
pathNewLeaf []bool, pathOldLeaf []bool) (*zkt.Hash, error) {
|
||||
if lvl > mt.maxLevels-2 {
|
||||
return nil, ErrReachedMaxLevel
|
||||
}
|
||||
var newNodeMiddle *Node
|
||||
if pathNewLeaf[lvl] == pathOldLeaf[lvl] { // We need to go deeper!
|
||||
nextKey, err := mt.pushLeaf(newLeaf, oldLeaf, lvl+1, pathNewLeaf, pathOldLeaf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pathNewLeaf[lvl] { // go right
|
||||
newNodeMiddle = NewNodeMiddle(&zkt.HashZero, nextKey)
|
||||
} else { // go left
|
||||
newNodeMiddle = NewNodeMiddle(nextKey, &zkt.HashZero)
|
||||
}
|
||||
return mt.addNode(newNodeMiddle)
|
||||
}
|
||||
oldLeafKey, err := oldLeaf.Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newLeafKey, err := newLeaf.Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pathNewLeaf[lvl] {
|
||||
newNodeMiddle = NewNodeMiddle(oldLeafKey, newLeafKey)
|
||||
} else {
|
||||
newNodeMiddle = NewNodeMiddle(newLeafKey, oldLeafKey)
|
||||
}
|
||||
// We can add newLeaf now. We don't need to add oldLeaf because it's
|
||||
// already in the tree.
|
||||
_, err = mt.addNode(newLeaf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mt.addNode(newNodeMiddle)
|
||||
}
|
||||
|
||||
// addLeaf recursively adds a newLeaf in the MT while updating the path.
|
||||
func (mt *ZkTrieImpl) addLeaf(newLeaf *Node, key *zkt.Hash,
|
||||
lvl int, path []bool, forceUpdate bool) (*zkt.Hash, error) {
|
||||
var err error
|
||||
var nextKey *zkt.Hash
|
||||
if lvl > mt.maxLevels-1 {
|
||||
return nil, ErrReachedMaxLevel
|
||||
}
|
||||
n, err := mt.GetNode(key)
|
||||
if err != nil {
|
||||
fmt.Printf("addLeaf:GetNode err %v key %v root %v level %v\n", err, key, mt.rootKey, lvl)
|
||||
fmt.Printf("root %v\n", mt.Root())
|
||||
return nil, err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
// We can add newLeaf now
|
||||
{
|
||||
r, e := mt.addNode(newLeaf)
|
||||
if e != nil {
|
||||
fmt.Println("err on NodeTypeEmpty mt.addNode ", e)
|
||||
}
|
||||
return r, e
|
||||
}
|
||||
case NodeTypeLeaf:
|
||||
// Check if leaf node found contains the leaf node we are
|
||||
// trying to add
|
||||
if bytes.Equal(n.NodeKey[:], newLeaf.NodeKey[:]) {
|
||||
k, err := n.Key()
|
||||
if err != nil {
|
||||
fmt.Println("err on obtain key of duplicated entry", err)
|
||||
return nil, err
|
||||
}
|
||||
if bytes.Equal(k[:], newLeaf.key[:]) {
|
||||
// do nothing, duplicate entry
|
||||
// FIXME more optimization may needed here
|
||||
return k, nil
|
||||
} else if forceUpdate {
|
||||
return mt.updateNode(newLeaf)
|
||||
}
|
||||
|
||||
fmt.Printf("ErrEntryIndexAlreadyExists nodeKey %v n.Key() %v newLeaf.Key() %v\n",
|
||||
n.NodeKey, k, newLeaf.key)
|
||||
return nil, ErrEntryIndexAlreadyExists
|
||||
|
||||
}
|
||||
pathOldLeaf := getPath(mt.maxLevels, n.NodeKey[:])
|
||||
// We need to push newLeaf down until its path diverges from
|
||||
// n's path
|
||||
return mt.pushLeaf(newLeaf, n, lvl, path, pathOldLeaf)
|
||||
case NodeTypeMiddle:
|
||||
// We need to go deeper, continue traversing the tree, left or
|
||||
// right depending on path
|
||||
var newNodeMiddle *Node
|
||||
if path[lvl] { // go right
|
||||
nextKey, err = mt.addLeaf(newLeaf, n.ChildR, lvl+1, path, forceUpdate)
|
||||
newNodeMiddle = NewNodeMiddle(n.ChildL, nextKey)
|
||||
} else { // go left
|
||||
nextKey, err = mt.addLeaf(newLeaf, n.ChildL, lvl+1, path, forceUpdate)
|
||||
newNodeMiddle = NewNodeMiddle(nextKey, n.ChildR)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Printf("addLeaf:GetNode err %v level %v\n", err, lvl)
|
||||
return nil, err
|
||||
}
|
||||
// Update the node to reflect the modified child
|
||||
return mt.addNode(newNodeMiddle)
|
||||
default:
|
||||
return nil, ErrInvalidNodeFound
|
||||
}
|
||||
}
|
||||
|
||||
// addNode adds a node into the MT. Empty nodes are not stored in the tree;
|
||||
// they are all the same and assumed to always exist.
|
||||
func (mt *ZkTrieImpl) addNode(n *Node) (*zkt.Hash, error) {
|
||||
// verify that the ZkTrieImpl is writable
|
||||
if !mt.writable {
|
||||
return nil, ErrNotWritable
|
||||
}
|
||||
if n.Type == NodeTypeEmpty {
|
||||
return n.Key()
|
||||
}
|
||||
k, err := n.Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := n.Value()
|
||||
// Check that the node key doesn't already exist
|
||||
oldV, err := mt.db.Get(k[:])
|
||||
if err == nil {
|
||||
if !bytes.Equal(oldV, v) {
|
||||
return nil, ErrNodeKeyAlreadyExists
|
||||
} else {
|
||||
// duplicated
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
err = mt.db.Put(k[:], v)
|
||||
return k, err
|
||||
}
|
||||
|
||||
// updateNode updates an existing node in the MT. Empty nodes are not stored
|
||||
// in the tree; they are all the same and assumed to always exist.
|
||||
func (mt *ZkTrieImpl) updateNode(n *Node) (*zkt.Hash, error) {
|
||||
// verify that the ZkTrieImpl is writable
|
||||
if !mt.writable {
|
||||
return nil, ErrNotWritable
|
||||
}
|
||||
if n.Type == NodeTypeEmpty {
|
||||
return n.Key()
|
||||
}
|
||||
k, err := n.Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := n.Value()
|
||||
err = mt.db.Put(k[:], v)
|
||||
return k, err
|
||||
}
|
||||
|
||||
/*
|
||||
// Get returns the value of the leaf for the given key
|
||||
func (mt *ZkTrieImpl) Get(k *big.Int) (*big.Int, *big.Int, []*zkt.Hash, error) {
|
||||
// verify that k is valid and fit inside the Finite Field.
|
||||
if !cryptoUtils.CheckBigIntInField(k) {
|
||||
return nil, nil, nil, errors.New("Key not inside the Finite Field")
|
||||
}
|
||||
|
||||
kHash := zkt.NewHashFromBigInt(k)
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
|
||||
nextKey := mt.rootKey
|
||||
siblings := []*zkt.Hash{}
|
||||
for i := 0; i < mt.maxLevels; i++ {
|
||||
n, err := mt.GetNode(nextKey)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
return big.NewInt(0), big.NewInt(0), siblings, ErrKeyNotFound
|
||||
case NodeTypeLeaf:
|
||||
if bytes.Equal(kHash[:], n.NodeKey[:]) {
|
||||
return n.Entry[0].BigInt(), n.Entry[1].BigInt(), siblings, nil
|
||||
}
|
||||
return n.Entry[0].BigInt(), n.Entry[1].BigInt(), siblings, ErrKeyNotFound
|
||||
case NodeTypeMiddle:
|
||||
if path[i] {
|
||||
nextKey = n.ChildR
|
||||
siblings = append(siblings, n.ChildL)
|
||||
} else {
|
||||
nextKey = n.ChildL
|
||||
siblings = append(siblings, n.ChildR)
|
||||
}
|
||||
default:
|
||||
return nil, nil, nil, ErrInvalidNodeFound
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil, nil, ErrReachedMaxLevel
|
||||
}
|
||||
*/
|
||||
|
||||
func (mt *ZkTrieImpl) tryGet(kHash *zkt.Hash) (*Node, []*zkt.Hash, error) {
|
||||
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
nextKey := mt.rootKey
|
||||
var siblings []*zkt.Hash
|
||||
for i := 0; i < mt.maxLevels; i++ {
|
||||
n, err := mt.GetNode(nextKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
return NewNodeEmpty(), siblings, ErrKeyNotFound
|
||||
case NodeTypeLeaf:
|
||||
if bytes.Equal(kHash[:], n.NodeKey[:]) {
|
||||
return n, siblings, nil
|
||||
}
|
||||
return n, siblings, ErrKeyNotFound
|
||||
case NodeTypeMiddle:
|
||||
if path[i] {
|
||||
nextKey = n.ChildR
|
||||
siblings = append(siblings, n.ChildL)
|
||||
} else {
|
||||
nextKey = n.ChildL
|
||||
siblings = append(siblings, n.ChildR)
|
||||
}
|
||||
default:
|
||||
return nil, nil, ErrInvalidNodeFound
|
||||
}
|
||||
}
|
||||
|
||||
return nil, siblings, ErrReachedMaxLevel
|
||||
}
|
||||
|
||||
// Get returns the value for key stored in the trie.
|
||||
// The value bytes must not be modified by the caller.
|
||||
func (mt *ZkTrieImpl) Get(key []byte) []byte {
|
||||
res, err := mt.TryGet(key)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// TryGet returns the value for key stored in the trie.
|
||||
// The value bytes must not be modified by the caller.
|
||||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (mt *ZkTrieImpl) TryGet(key []byte) ([]byte, error) {
|
||||
kHash, err := zkt.NewHashFromBytes(common.BytesToHash(key).Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node, _, err := mt.tryGet(kHash)
|
||||
if err == ErrKeyNotFound {
|
||||
// according to https://github.com/ethereum/go-ethereum/blob/37f9d25ba027356457953eab5f181c98b46e9988/trie/trie.go#L135
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return node.Data(), nil
|
||||
}
|
||||
|
||||
// GetLeafNodeByWord
|
||||
// Deprecated: Get a Bytes32 kv to ZkTrieImpl, only for testing
|
||||
func (mt *ZkTrieImpl) GetLeafNodeByWord(kPreimage *zkt.Byte32) (*Node, error) {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n, _, err := mt.tryGet(zkt.NewHashFromBigInt(k))
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Deprecated: only for testing
|
||||
func (mt *ZkTrieImpl) UpdateWord(kPreimage, vPreimage *zkt.Byte32) error {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mt.tryUpdate(zkt.NewHashFromBigInt(k), 1, []zkt.Byte32{*vPreimage})
|
||||
return err
|
||||
}
|
||||
|
||||
// TryUpdateAccount will abstract the write of an account to the trie
|
||||
func (mt *ZkTrieImpl) TryUpdateAccount(key []byte, acc *types.StateAccount) error {
|
||||
kHash, err := zkt.NewHashFromBytes(common.BytesToHash(key).Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value, flag := acc.MarshalFields()
|
||||
return mt.tryUpdate(kHash, flag, value)
|
||||
}
|
||||
|
||||
// Update associates key with value in the trie. Subsequent calls to
|
||||
// Get will return value.
|
||||
// TODO: If value has length zero, any existing value
|
||||
// is deleted from the trie and calls to Get will return nil.
|
||||
//
|
||||
// The value bytes must not be modified by the caller while they are
|
||||
// stored in the trie.
|
||||
func (mt *ZkTrieImpl) Update(key, value []byte) {
|
||||
if err := mt.TryUpdate(key, value); err != nil {
|
||||
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// TryUpdate associates key with value in the trie. Subsequent calls to
|
||||
// Get will return value.
|
||||
// TODO: If value has length zero, any existing value
|
||||
// is deleted from the trie and calls to Get will return nil.
|
||||
//
|
||||
// The value bytes must not be modified by the caller while they are
|
||||
// stored in the trie.
|
||||
//
|
||||
// Currently the value must shorter than 32 bytes
|
||||
//
|
||||
// NOTE: value is restricted to length of bytes32.
|
||||
func (mt *ZkTrieImpl) TryUpdate(key, value []byte) error {
|
||||
kHash, err := zkt.NewHashFromBytes(common.BytesToHash(key).Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vPreimage := zkt.NewByte32FromBytesPaddingZero(value)
|
||||
return mt.tryUpdate(kHash, 1, []zkt.Byte32{*vPreimage})
|
||||
}
|
||||
|
||||
/*
|
||||
func (mt *ZkTrieImpl) UpdateVarWord(kPreimage *zkt.Byte32, vHash *big.Int, vPreimage []byte) error {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = mt.Update(k, vHash, kPreimage, vPreimage[:])
|
||||
if err == ErrKeyNotFound {
|
||||
err = mt.Add(k, vHash, kPreimage, vPreimage[:])
|
||||
if err != nil {
|
||||
log.Error("UpdateVarWord, inset still failed %v root %v", err, mt.rootKey)
|
||||
}
|
||||
return err
|
||||
} else if err != nil {
|
||||
log.Error("UpdateVarWord err %v %v", err, reflect.TypeOf(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
*/
|
||||
|
||||
// only update the corresponding leaf for
|
||||
func (mt *ZkTrieImpl) tryDeleteLite(kHash *zkt.Hash) error {
|
||||
// verify that the ZkTrieImpl is writable
|
||||
if !mt.writable {
|
||||
return ErrNotWritable
|
||||
}
|
||||
|
||||
// verify that k is valid and fit inside the Finite Field.
|
||||
if !cryptoUtils.CheckBigIntInField(kHash.BigInt()) {
|
||||
return errors.New("Key not inside the Finite Field")
|
||||
}
|
||||
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
|
||||
nextKey := mt.rootKey
|
||||
siblings := []*zkt.Hash{}
|
||||
for i := 0; i < mt.maxLevels; i++ {
|
||||
n, err := mt.GetNode(nextKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
return ErrKeyNotFound
|
||||
case NodeTypeLeaf:
|
||||
if bytes.Equal(kHash[:], n.NodeKey[:]) {
|
||||
// remove and go up with the sibling
|
||||
newRootKey, err := mt.recalculatePathUntilRoot(path, NewNodeEmpty(), siblings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mt.rootKey = newRootKey
|
||||
return mt.dbInsert(dbKeyRootNode, DBEntryTypeRoot, mt.rootKey[:])
|
||||
}
|
||||
return ErrKeyNotFound
|
||||
case NodeTypeMiddle:
|
||||
if path[i] {
|
||||
nextKey = n.ChildR
|
||||
siblings = append(siblings, n.ChildL)
|
||||
} else {
|
||||
nextKey = n.ChildL
|
||||
siblings = append(siblings, n.ChildR)
|
||||
}
|
||||
default:
|
||||
return ErrInvalidNodeFound
|
||||
}
|
||||
}
|
||||
|
||||
return ErrKeyNotFound
|
||||
}
|
||||
|
||||
// Delete removes the specified Key from the ZkTrieImpl and updates the path
|
||||
// from the deleted key to the Root with the new values. This method removes
|
||||
// the key from the ZkTrieImpl, but does not remove the old nodes from the
|
||||
// key-value database; this means that if the tree is accessed by an old Root
|
||||
// where the key was not deleted yet, the key will still exist. If is desired
|
||||
// to remove the key-values from the database that are not under the current
|
||||
// Root, an option could be to dump all the leafs (using mt.DumpLeafs) and
|
||||
// import them in a new ZkTrieImpl in a new database (using
|
||||
// mt.ImportDumpedLeafs), but this will lose all the Root history of the
|
||||
// ZkTrieImpl
|
||||
func (mt *ZkTrieImpl) tryDelete(kHash *zkt.Hash) error {
|
||||
// verify that the ZkTrieImpl is writable
|
||||
if !mt.writable {
|
||||
return ErrNotWritable
|
||||
}
|
||||
|
||||
// verify that k is valid and fit inside the Finite Field.
|
||||
if !cryptoUtils.CheckBigIntInField(kHash.BigInt()) {
|
||||
return errors.New("Key not inside the Finite Field")
|
||||
}
|
||||
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
|
||||
nextKey := mt.rootKey
|
||||
siblings := []*zkt.Hash{}
|
||||
for i := 0; i < mt.maxLevels; i++ {
|
||||
n, err := mt.GetNode(nextKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
return ErrKeyNotFound
|
||||
case NodeTypeLeaf:
|
||||
if bytes.Equal(kHash[:], n.NodeKey[:]) {
|
||||
// remove and go up with the sibling
|
||||
err = mt.rmAndUpload(path, kHash, siblings)
|
||||
return err
|
||||
}
|
||||
return ErrKeyNotFound
|
||||
case NodeTypeMiddle:
|
||||
if path[i] {
|
||||
nextKey = n.ChildR
|
||||
siblings = append(siblings, n.ChildL)
|
||||
} else {
|
||||
nextKey = n.ChildL
|
||||
siblings = append(siblings, n.ChildR)
|
||||
}
|
||||
default:
|
||||
return ErrInvalidNodeFound
|
||||
}
|
||||
}
|
||||
|
||||
return ErrKeyNotFound
|
||||
}
|
||||
|
||||
// Delete removes the specified Key from the ZkTrieImpl and updates the path
|
||||
// from the deleted key to the Root with the new values. This method removes
|
||||
// the key from the ZkTrieImpl, but does not remove the old nodes from the
|
||||
// key-value database; this means that if the tree is accessed by an old Root
|
||||
// where the key was not deleted yet, the key will still exist. If is desired
|
||||
// to remove the key-values from the database that are not under the current
|
||||
// Root, an option could be to dump all the leafs (using mt.DumpLeafs) and
|
||||
// import them in a new ZkTrieImpl in a new database (using
|
||||
// mt.ImportDumpedLeafs), but this will lose all the Root history of the
|
||||
// ZkTrieImpl
|
||||
// Delete removes any existing value for key from the trie.
|
||||
func (t *ZkTrieImpl) Delete(key []byte) {
|
||||
if err := t.TryDelete(key); err != nil {
|
||||
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// TryDelete removes any existing value for key from the trie.
|
||||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (mt *ZkTrieImpl) TryDelete(key []byte) error {
|
||||
kHash, err := zkt.NewHashFromBytes(common.BytesToHash(key).Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mt.tryDelete(kHash)
|
||||
}
|
||||
|
||||
// Deprecated: only for testing
|
||||
func (mt *ZkTrieImpl) DeleteWord(kPreimage *zkt.Byte32) error {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mt.tryDelete(zkt.NewHashFromBigInt(k))
|
||||
}
|
||||
|
||||
// rmAndUpload removes the key, and goes up until the root updating all the
|
||||
// nodes with the new values.
|
||||
func (mt *ZkTrieImpl) rmAndUpload(path []bool, kHash *zkt.Hash, siblings []*zkt.Hash) error {
|
||||
if len(siblings) == 0 {
|
||||
mt.rootKey = &zkt.HashZero
|
||||
err := mt.dbInsert(dbKeyRootNode, DBEntryTypeRoot, mt.rootKey[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
toUpload := siblings[len(siblings)-1]
|
||||
if len(siblings) < 2 { //nolint:gomnd
|
||||
mt.rootKey = siblings[0]
|
||||
err := mt.dbInsert(dbKeyRootNode, DBEntryTypeRoot, mt.rootKey[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for i := len(siblings) - 2; i >= 0; i-- { //nolint:gomnd
|
||||
if !bytes.Equal(siblings[i][:], zkt.HashZero[:]) {
|
||||
var newNode *Node
|
||||
if path[i] {
|
||||
newNode = NewNodeMiddle(siblings[i], toUpload)
|
||||
} else {
|
||||
newNode = NewNodeMiddle(toUpload, siblings[i])
|
||||
}
|
||||
_, err := mt.addNode(newNode)
|
||||
if err != ErrNodeKeyAlreadyExists && err != nil {
|
||||
return err
|
||||
}
|
||||
// go up until the root
|
||||
newRootKey, err := mt.recalculatePathUntilRoot(path, newNode,
|
||||
siblings[:i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mt.rootKey = newRootKey
|
||||
err = mt.dbInsert(dbKeyRootNode, DBEntryTypeRoot, mt.rootKey[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
// if i==0 (root position), stop and store the sibling of the
|
||||
// deleted leaf as root
|
||||
if i == 0 {
|
||||
mt.rootKey = toUpload
|
||||
err := mt.dbInsert(dbKeyRootNode, DBEntryTypeRoot, mt.rootKey[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// recalculatePathUntilRoot recalculates the nodes until the Root
|
||||
func (mt *ZkTrieImpl) recalculatePathUntilRoot(path []bool, node *Node,
|
||||
siblings []*zkt.Hash) (*zkt.Hash, error) {
|
||||
for i := len(siblings) - 1; i >= 0; i-- {
|
||||
nodeKey, err := node.Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if path[i] {
|
||||
node = NewNodeMiddle(siblings[i], nodeKey)
|
||||
} else {
|
||||
node = NewNodeMiddle(nodeKey, siblings[i])
|
||||
}
|
||||
_, err = mt.addNode(node)
|
||||
if err != ErrNodeKeyAlreadyExists && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// return last node added, which is the root
|
||||
nodeKey, err := node.Key()
|
||||
return nodeKey, err
|
||||
}
|
||||
|
||||
// dbInsert is a helper function to insert a node into a key in an open db
|
||||
// transaction.
|
||||
func (mt *ZkTrieImpl) dbInsert(k []byte, t NodeType, data []byte) error {
|
||||
v := append([]byte{byte(t)}, data...)
|
||||
return mt.db.Put(k, v)
|
||||
}
|
||||
|
||||
// GetNode gets a node by key from the MT. Empty nodes are not stored in the
|
||||
// tree; they are all the same and assumed to always exist.
|
||||
// <del>for non exist key, return (NewNodeEmpty(), nil)</del>
|
||||
func (mt *ZkTrieImpl) GetNode(key *zkt.Hash) (*Node, error) {
|
||||
if bytes.Equal(key[:], zkt.HashZero[:]) {
|
||||
return NewNodeEmpty(), nil
|
||||
}
|
||||
nBytes, err := mt.db.Get(key[:])
|
||||
if err == ErrNotFound {
|
||||
//return NewNodeEmpty(), nil
|
||||
return nil, ErrKeyNotFound
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewNodeFromBytes(nBytes)
|
||||
}
|
||||
|
||||
// getPath returns the binary path, from the root to the leaf.
|
||||
func getPath(numLevels int, k []byte) []bool {
|
||||
path := make([]bool, numLevels)
|
||||
for n := 0; n < numLevels; n++ {
|
||||
path[n] = zkt.TestBit(k[:], uint(n))
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// NodeAux contains the auxiliary node used in a non-existence proof.
|
||||
type NodeAux struct {
|
||||
Key *zkt.Hash
|
||||
Value *zkt.Hash
|
||||
}
|
||||
|
||||
// Proof defines the required elements for a MT proof of existence or
|
||||
// non-existence.
|
||||
type Proof struct {
|
||||
// existence indicates wether this is a proof of existence or
|
||||
// non-existence.
|
||||
Existence bool
|
||||
// depth indicates how deep in the tree the proof goes.
|
||||
depth uint
|
||||
// notempties is a bitmap of non-empty Siblings found in Siblings.
|
||||
notempties [zkt.ElemBytesLen - proofFlagsLen]byte
|
||||
// Siblings is a list of non-empty sibling keys.
|
||||
Siblings []*zkt.Hash
|
||||
// Key is the key of leaf in existence case
|
||||
Key *zkt.Hash
|
||||
NodeAux *NodeAux
|
||||
}
|
||||
|
||||
// VerifyProof verifies the Merkle Proof for the entry and root.
|
||||
func VerifyProofZkTrie(rootKey *zkt.Hash, proof *Proof, node *Node) bool {
|
||||
key, err := node.Key()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
rootFromProof, err := proof.Verify(key, node.NodeKey)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(rootKey[:], rootFromProof[:])
|
||||
}
|
||||
|
||||
// Verify the proof and calculate the root, key can be nil when try to verify
|
||||
// an nonexistent proof
|
||||
func (proof *Proof) Verify(key, kHash *zkt.Hash) (*zkt.Hash, error) {
|
||||
|
||||
if proof.Existence {
|
||||
if key == nil {
|
||||
return nil, ErrKeyNotFound
|
||||
}
|
||||
return proof.rootFromProof(key, kHash)
|
||||
} else {
|
||||
|
||||
if proof.NodeAux == nil {
|
||||
return proof.rootFromProof(&zkt.HashZero, kHash)
|
||||
} else {
|
||||
if bytes.Equal(kHash[:], proof.NodeAux.Key[:]) {
|
||||
return nil, fmt.Errorf("non-existence proof being checked against hIndex equal to nodeAux")
|
||||
}
|
||||
midKey, err := LeafKey(proof.NodeAux.Key, proof.NodeAux.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proof.rootFromProof(midKey, kHash)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (proof *Proof) rootFromProof(key, kHash *zkt.Hash) (*zkt.Hash, error) {
|
||||
midKey := key
|
||||
var err error
|
||||
|
||||
sibIdx := len(proof.Siblings) - 1
|
||||
path := getPath(int(proof.depth), kHash[:])
|
||||
var siblingKey *zkt.Hash
|
||||
for lvl := int(proof.depth) - 1; lvl >= 0; lvl-- {
|
||||
if zkt.TestBitBigEndian(proof.notempties[:], uint(lvl)) {
|
||||
siblingKey = proof.Siblings[sibIdx]
|
||||
sibIdx--
|
||||
} else {
|
||||
siblingKey = &zkt.HashZero
|
||||
}
|
||||
if path[lvl] {
|
||||
midKey, err = NewNodeMiddle(siblingKey, midKey).Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
midKey, err = NewNodeMiddle(midKey, siblingKey).Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return midKey, nil
|
||||
}
|
||||
|
||||
// walk is a helper recursive function to iterate over all tree branches
|
||||
func (mt *ZkTrieImpl) walk(key *zkt.Hash, f func(*Node)) error {
|
||||
n, err := mt.GetNode(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
f(n)
|
||||
case NodeTypeLeaf:
|
||||
f(n)
|
||||
case NodeTypeMiddle:
|
||||
f(n)
|
||||
if err := mt.walk(n.ChildL, f); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mt.walk(n.ChildR, f); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return ErrInvalidNodeFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Walk iterates over all the branches of a ZkTrieImpl with the given rootKey
|
||||
// if rootKey is nil, it will get the current RootKey of the current state of
|
||||
// the ZkTrieImpl. For each node, it calls the f function given in the
|
||||
// parameters. See some examples of the Walk function usage in the
|
||||
// ZkTrieImpl.go and merkletree_test.go
|
||||
func (mt *ZkTrieImpl) Walk(rootKey *zkt.Hash, f func(*Node)) error {
|
||||
if rootKey == nil {
|
||||
rootKey = mt.Root()
|
||||
}
|
||||
err := mt.walk(rootKey, f)
|
||||
return err
|
||||
}
|
||||
|
||||
// GraphViz uses Walk function to generate a string GraphViz representation of
|
||||
// the tree and writes it to w
|
||||
func (mt *ZkTrieImpl) GraphViz(w io.Writer, rootKey *zkt.Hash) error {
|
||||
fmt.Fprintf(w, `digraph hierarchy {
|
||||
node [fontname=Monospace,fontsize=10,shape=box]
|
||||
`)
|
||||
cnt := 0
|
||||
var errIn error
|
||||
err := mt.Walk(rootKey, func(n *Node) {
|
||||
k, err := n.Key()
|
||||
if err != nil {
|
||||
errIn = err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
case NodeTypeLeaf:
|
||||
fmt.Fprintf(w, "\"%v\" [style=filled];\n", k.String())
|
||||
case NodeTypeMiddle:
|
||||
lr := [2]string{n.ChildL.String(), n.ChildR.String()}
|
||||
emptyNodes := ""
|
||||
for i := range lr {
|
||||
if lr[i] == "0" {
|
||||
lr[i] = fmt.Sprintf("empty%v", cnt)
|
||||
emptyNodes += fmt.Sprintf("\"%v\" [style=dashed,label=0];\n", lr[i])
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "\"%v\" -> {\"%v\" \"%v\"}\n", k.String(), lr[0], lr[1])
|
||||
fmt.Fprint(w, emptyNodes)
|
||||
default:
|
||||
}
|
||||
})
|
||||
fmt.Fprintf(w, "}\n")
|
||||
if errIn != nil {
|
||||
return errIn
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// PrintGraphViz prints directly the GraphViz() output
|
||||
func (mt *ZkTrieImpl) PrintGraphViz(rootKey *zkt.Hash) error {
|
||||
if rootKey == nil {
|
||||
rootKey = mt.Root()
|
||||
}
|
||||
w := bytes.NewBufferString("")
|
||||
fmt.Fprintf(w,
|
||||
"--------\nGraphViz of the ZkTrieImpl with RootKey "+rootKey.BigInt().String()+"\n")
|
||||
err := mt.GraphViz(w, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(w,
|
||||
"End of GraphViz of the ZkTrieImpl with RootKey "+rootKey.BigInt().String()+"\n--------\n")
|
||||
|
||||
fmt.Println(w)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -9,18 +9,100 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
zktrie "github.com/scroll-tech/zktrie/trie"
|
||||
zkt "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb/memorydb"
|
||||
)
|
||||
|
||||
// we do not need zktrie impl anymore, only made a wrapper for adapting testing
|
||||
type zkTrieImplTestWrapper struct {
|
||||
*zktrie.ZkTrieImpl
|
||||
}
|
||||
|
||||
func newZkTrieImpl(storage *ZktrieDatabase, maxLevels int) (*zkTrieImplTestWrapper, error) {
|
||||
return newZkTrieImplWithRoot(storage, &zkt.HashZero, maxLevels)
|
||||
}
|
||||
|
||||
// NewZkTrieImplWithRoot loads a new ZkTrieImpl. If in the storage already exists one
|
||||
// will open that one, if not, will create a new one.
|
||||
func newZkTrieImplWithRoot(storage *ZktrieDatabase, root *zkt.Hash, maxLevels int) (*zkTrieImplTestWrapper, error) {
|
||||
impl, err := zktrie.NewZkTrieImplWithRoot(storage, root, maxLevels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &zkTrieImplTestWrapper{impl}, nil
|
||||
}
|
||||
|
||||
// AddWord
|
||||
// Deprecated: Add a Bytes32 kv to ZkTrieImpl, only for testing
|
||||
func (mt *zkTrieImplTestWrapper) AddWord(kPreimage, vPreimage *zkt.Byte32) error {
|
||||
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v, _ := mt.TryGet(k.Bytes()); v != nil {
|
||||
return zktrie.ErrEntryIndexAlreadyExists
|
||||
}
|
||||
|
||||
return mt.ZkTrieImpl.TryUpdate(zkt.NewHashFromBigInt(k), 1, []zkt.Byte32{*vPreimage})
|
||||
}
|
||||
|
||||
// GetLeafNodeByWord
|
||||
// Deprecated: Get a Bytes32 kv to ZkTrieImpl, only for testing
|
||||
func (mt *zkTrieImplTestWrapper) GetLeafNodeByWord(kPreimage *zkt.Byte32) (*zktrie.Node, error) {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mt.ZkTrieImpl.GetLeafNode(zkt.NewHashFromBigInt(k))
|
||||
}
|
||||
|
||||
// Deprecated: only for testing
|
||||
func (mt *zkTrieImplTestWrapper) UpdateWord(kPreimage, vPreimage *zkt.Byte32) error {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mt.ZkTrieImpl.TryUpdate(zkt.NewHashFromBigInt(k), 1, []zkt.Byte32{*vPreimage})
|
||||
}
|
||||
|
||||
// Deprecated: only for testing
|
||||
func (mt *zkTrieImplTestWrapper) DeleteWord(kPreimage *zkt.Byte32) error {
|
||||
k, err := kPreimage.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mt.ZkTrieImpl.TryDelete(zkt.NewHashFromBigInt(k))
|
||||
}
|
||||
|
||||
func (mt *zkTrieImplTestWrapper) TryGet(key []byte) ([]byte, error) {
|
||||
return mt.ZkTrieImpl.TryGet(zkt.NewHashFromBytes(key))
|
||||
}
|
||||
|
||||
// TryUpdateAccount will abstract the write of an account to the trie
|
||||
func (mt *zkTrieImplTestWrapper) TryUpdateAccount(key []byte, acc *types.StateAccount) error {
|
||||
value, flag := acc.MarshalFields()
|
||||
return mt.ZkTrieImpl.TryUpdate(zkt.NewHashFromBytes(key), flag, value)
|
||||
}
|
||||
|
||||
// NewHashFromHex returns a *Hash representation of the given hex string
|
||||
func NewHashFromHex(h string) (*zkt.Hash, error) {
|
||||
return zkt.NewHashFromCheckedBytes(common.FromHex(h))
|
||||
}
|
||||
|
||||
type Fatalable interface {
|
||||
Fatal(args ...interface{})
|
||||
}
|
||||
|
||||
func newTestingMerkle(f Fatalable, numLevels int) *ZkTrieImpl {
|
||||
mt, err := NewZkTrieImpl(NewZktrieDatabase((memorydb.New())), numLevels)
|
||||
func newTestingMerkle(f Fatalable, numLevels int) *zkTrieImplTestWrapper {
|
||||
mt, err := newZkTrieImpl(NewZktrieDatabase((memorydb.New())), numLevels)
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
return nil
|
||||
|
|
@ -46,20 +128,20 @@ func TestHashParsers(t *testing.T) {
|
|||
h := zkt.NewHashFromBigInt(b)
|
||||
assert.Equal(t, "4932297968297298434239270129193057052722409868268166443802652458940273154854", h.BigInt().String()) //nolint:lll
|
||||
assert.Equal(t, "49322979...", h.String())
|
||||
assert.Equal(t, "265baaf161e875c372d08e50f52abddc01d32efc93e90290bb8b3d9ceb94e70a", h.Hex())
|
||||
assert.Equal(t, "0ae794eb9c3d8bbb9002e993fc2ed301dcbd2af5508ed072c375e861f1aa5b26", h.Hex())
|
||||
|
||||
b1, err := zkt.NewBigIntFromHashBytes(b.Bytes())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, new(big.Int).SetBytes(b.Bytes()).String(), b1.String())
|
||||
|
||||
b2, err := zkt.NewHashFromBytes(b.Bytes())
|
||||
b2, err := zkt.NewHashFromCheckedBytes(b.Bytes())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, b.String(), b2.BigInt().String())
|
||||
|
||||
h2, err := zkt.NewHashFromHex(h.Hex())
|
||||
h2, err := NewHashFromHex(h.Hex())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, h, h2)
|
||||
_, err = zkt.NewHashFromHex("0x12")
|
||||
_, err = NewHashFromHex("0x12")
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// check limits
|
||||
|
|
@ -73,12 +155,12 @@ func testHashParsers(t *testing.T, a *big.Int) {
|
|||
require.True(t, cryptoUtils.CheckBigIntInField(a))
|
||||
h := zkt.NewHashFromBigInt(a)
|
||||
assert.Equal(t, a, h.BigInt())
|
||||
hFromBytes, err := zkt.NewHashFromBytes(h.Bytes())
|
||||
hFromBytes, err := zkt.NewHashFromCheckedBytes(h.Bytes())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, h, hFromBytes)
|
||||
assert.Equal(t, a, hFromBytes.BigInt())
|
||||
assert.Equal(t, a.String(), hFromBytes.BigInt().String())
|
||||
hFromHex, err := zkt.NewHashFromHex(h.Hex())
|
||||
hFromHex, err := NewHashFromHex(h.Hex())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, h, hFromHex)
|
||||
|
||||
|
|
@ -97,7 +179,7 @@ func TestMerkleTree_AddUpdateGetWord(t *testing.T) {
|
|||
err = mt.AddWord(&zkt.Byte32{5}, &zkt.Byte32{6})
|
||||
assert.Nil(t, err)
|
||||
err = mt.AddWord(&zkt.Byte32{5}, &zkt.Byte32{7})
|
||||
assert.Equal(t, ErrEntryIndexAlreadyExists, err)
|
||||
assert.Equal(t, zktrie.ErrEntryIndexAlreadyExists, err)
|
||||
|
||||
node, err := mt.GetLeafNodeByWord(&zkt.Byte32{1})
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -132,7 +214,7 @@ func TestMerkleTree_AddUpdateGetWord(t *testing.T) {
|
|||
assert.Equal(t, len(node.ValuePreimage), 1)
|
||||
assert.Equal(t, (&zkt.Byte32{9})[:], node.ValuePreimage[0][:])
|
||||
_, err = mt.GetLeafNodeByWord(&zkt.Byte32{100})
|
||||
assert.Equal(t, ErrKeyNotFound, err)
|
||||
assert.Equal(t, zktrie.ErrKeyNotFound, err)
|
||||
}
|
||||
|
||||
func TestMerkleTree_UpdateAccount(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -1,222 +0,0 @@
|
|||
package trie
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
)
|
||||
|
||||
// NodeType defines the type of node in the MT.
|
||||
type NodeType byte
|
||||
|
||||
const (
|
||||
// NodeTypeMiddle indicates the type of middle Node that has children.
|
||||
NodeTypeMiddle NodeType = 0
|
||||
// NodeTypeLeaf indicates the type of a leaf Node that contains a key &
|
||||
// value.
|
||||
NodeTypeLeaf NodeType = 1
|
||||
// NodeTypeEmpty indicates the type of an empty Node.
|
||||
NodeTypeEmpty NodeType = 2
|
||||
|
||||
// DBEntryTypeRoot indicates the type of a DB entry that indicates the
|
||||
// current Root of a MerkleTree
|
||||
DBEntryTypeRoot NodeType = 3
|
||||
)
|
||||
|
||||
// Node is the struct that represents a node in the MT. The node should not be
|
||||
// modified after creation because the cached key won't be updated.
|
||||
type Node struct {
|
||||
// Type is the type of node in the tree.
|
||||
Type NodeType
|
||||
// ChildL is the left child of a middle node.
|
||||
ChildL *zkt.Hash
|
||||
// ChildR is the right child of a middle node.
|
||||
ChildR *zkt.Hash
|
||||
// NodeKey is the node's key stored in a leaf node.
|
||||
NodeKey *zkt.Hash
|
||||
// ValuePreimage can store at most 256 byte32 as fields (represnted by BIG-ENDIAN integer)
|
||||
// and the first 24 can be compressed (each bytes32 consider as 2 fields), in hashing the compressed
|
||||
// elemments would be calculated first
|
||||
ValuePreimage []zkt.Byte32
|
||||
// CompressedFlags use each bit for indicating the compressed flag for the first 24 fields
|
||||
CompressedFlags uint32
|
||||
// key is the cache of entry key used to avoid recalculating
|
||||
key *zkt.Hash
|
||||
// valueHash is the cache of hashes of valuePreimage, used to avoid recalculating
|
||||
valueHash *zkt.Hash
|
||||
// KeyPreimage is kept here only for proof
|
||||
KeyPreimage *zkt.Byte32
|
||||
}
|
||||
|
||||
// NewNodeLeaf creates a new leaf node.
|
||||
func NewNodeLeaf(k *zkt.Hash, valueFlags uint32, valuePreimage []zkt.Byte32) *Node {
|
||||
return &Node{Type: NodeTypeLeaf, NodeKey: k, CompressedFlags: valueFlags, ValuePreimage: valuePreimage}
|
||||
}
|
||||
|
||||
// NewNodeMiddle creates a new middle node.
|
||||
func NewNodeMiddle(childL *zkt.Hash, childR *zkt.Hash) *Node {
|
||||
return &Node{Type: NodeTypeMiddle, ChildL: childL, ChildR: childR}
|
||||
}
|
||||
|
||||
// NewNodeEmpty creates a new empty node.
|
||||
func NewNodeEmpty() *Node {
|
||||
return &Node{Type: NodeTypeEmpty}
|
||||
}
|
||||
|
||||
// NewNodeFromBytes creates a new node by parsing the input []byte.
|
||||
func NewNodeFromBytes(b []byte) (*Node, error) {
|
||||
if len(b) < 1 {
|
||||
return nil, ErrNodeBytesBadSize
|
||||
}
|
||||
n := Node{Type: NodeType(b[0])}
|
||||
b = b[1:]
|
||||
switch n.Type {
|
||||
case NodeTypeMiddle:
|
||||
if len(b) != 2*zkt.ElemBytesLen {
|
||||
return nil, ErrNodeBytesBadSize
|
||||
}
|
||||
n.ChildL, _ = zkt.NewHashFromBytes(b[:zkt.ElemBytesLen])
|
||||
n.ChildR, _ = zkt.NewHashFromBytes(b[zkt.ElemBytesLen : zkt.ElemBytesLen*2])
|
||||
case NodeTypeLeaf:
|
||||
if len(b) < zkt.ElemBytesLen+4 {
|
||||
return nil, ErrNodeBytesBadSize
|
||||
}
|
||||
n.NodeKey, _ = zkt.NewHashFromBytes(b[0:32])
|
||||
mark := binary.LittleEndian.Uint32(b[32:36])
|
||||
preimageLen := int(mark & 255)
|
||||
n.CompressedFlags = mark >> 8
|
||||
n.ValuePreimage = make([]zkt.Byte32, preimageLen)
|
||||
curPos := 36
|
||||
for i := 0; i < preimageLen; i++ {
|
||||
copy(n.ValuePreimage[i][:], b[i*32+curPos:(i+1)*32+curPos])
|
||||
}
|
||||
curPos = 36 + preimageLen*32
|
||||
preImageSize := int(b[curPos])
|
||||
curPos += 1
|
||||
if preImageSize != 0 {
|
||||
n.KeyPreimage = new(zkt.Byte32)
|
||||
copy(n.KeyPreimage[:], b[curPos:curPos+preImageSize])
|
||||
}
|
||||
case NodeTypeEmpty:
|
||||
break
|
||||
default:
|
||||
return nil, ErrInvalidNodeFound
|
||||
}
|
||||
return &n, nil
|
||||
}
|
||||
|
||||
// LeafKey computes the key of a leaf node given the hIndex and hValue of the
|
||||
// entry of the leaf.
|
||||
func LeafKey(k, v *zkt.Hash) (*zkt.Hash, error) {
|
||||
return zkt.HashElems(big.NewInt(1), k.BigInt(), v.BigInt())
|
||||
}
|
||||
|
||||
// Key computes the key of the node by hashing the content in a specific way
|
||||
// for each type of node. This key is used as the hash of the merklee tree for
|
||||
// each node.
|
||||
func (n *Node) Key() (*zkt.Hash, error) {
|
||||
if n.key == nil { // Cache the key to avoid repeated hash computations.
|
||||
// NOTE: We are not using the type to calculate the hash!
|
||||
switch n.Type {
|
||||
case NodeTypeMiddle: // H(ChildL || ChildR)
|
||||
var err error
|
||||
n.key, err = zkt.HashElems(n.ChildL.BigInt(), n.ChildR.BigInt())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case NodeTypeLeaf:
|
||||
var err error
|
||||
n.valueHash, err = zkt.PreHandlingElems(n.CompressedFlags, n.ValuePreimage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n.key, err = LeafKey(n.NodeKey, n.valueHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case NodeTypeEmpty: // Zero
|
||||
n.key = &zkt.HashZero
|
||||
default:
|
||||
n.key = &zkt.HashZero
|
||||
}
|
||||
}
|
||||
return n.key, nil
|
||||
}
|
||||
|
||||
func (n *Node) ValueKey() (*zkt.Hash, error) {
|
||||
if _, err := n.Key(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n.valueHash, nil
|
||||
}
|
||||
|
||||
// Data returns the wrapped data inside LeafNode and cast them into bytes
|
||||
// for other node type it just return nil
|
||||
func (n *Node) Data() []byte {
|
||||
switch n.Type {
|
||||
case NodeTypeLeaf:
|
||||
var data []byte
|
||||
hdata := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||
//TODO: uintptr(reflect.ValueOf(n.ValuePreimage).UnsafePointer()) should be more elegant but only available until go 1.18
|
||||
hdata.Data = uintptr(unsafe.Pointer(&n.ValuePreimage[0]))
|
||||
hdata.Len = 32 * len(n.ValuePreimage)
|
||||
hdata.Cap = hdata.Len
|
||||
return data
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Value returns the value of the node. This is the content that is stored in
|
||||
// the backend database.
|
||||
func (n *Node) Value() []byte {
|
||||
switch n.Type {
|
||||
case NodeTypeMiddle: // {Type || ChildL || ChildR}
|
||||
bytes := []byte{byte(n.Type)}
|
||||
bytes = append(bytes, n.ChildL.Bytes()...)
|
||||
bytes = append(bytes, n.ChildR.Bytes()...)
|
||||
return bytes
|
||||
case NodeTypeLeaf: // {Type || Data...}
|
||||
bytes := []byte{byte(n.Type)}
|
||||
bytes = append(bytes, n.NodeKey.Bytes()...)
|
||||
tmp := make([]byte, 4)
|
||||
compressedFlag := (n.CompressedFlags << 8) + uint32(len(n.ValuePreimage))
|
||||
binary.LittleEndian.PutUint32(tmp, compressedFlag)
|
||||
bytes = append(bytes, tmp...)
|
||||
for _, elm := range n.ValuePreimage {
|
||||
bytes = append(bytes, elm[:]...)
|
||||
}
|
||||
if n.KeyPreimage != nil {
|
||||
bytes = append(bytes, byte(len(n.KeyPreimage)))
|
||||
bytes = append(bytes, n.KeyPreimage[:]...)
|
||||
} else {
|
||||
bytes = append(bytes, 0)
|
||||
}
|
||||
|
||||
return bytes
|
||||
case NodeTypeEmpty: // { Type }
|
||||
return []byte{byte(n.Type)}
|
||||
default:
|
||||
return []byte{}
|
||||
}
|
||||
}
|
||||
|
||||
// String outputs a string representation of a node (different for each type).
|
||||
func (n *Node) String() string {
|
||||
switch n.Type {
|
||||
case NodeTypeMiddle: // {Type || ChildL || ChildR}
|
||||
return fmt.Sprintf("Middle L:%s R:%s", n.ChildL, n.ChildR)
|
||||
case NodeTypeLeaf: // {Type || Data...}
|
||||
return fmt.Sprintf("Leaf I:%v Items: %d, First:%v", n.NodeKey, len(n.ValuePreimage), n.ValuePreimage[0])
|
||||
case NodeTypeEmpty: // {}
|
||||
return "Empty"
|
||||
default:
|
||||
return "Invalid Node"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
package trie
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
// TODO: remove this hack
|
||||
var magicHash []byte
|
||||
var magicSMTBytes []byte
|
||||
|
||||
func init() {
|
||||
magicSMTBytes = []byte("THIS IS SOME MAGIC BYTES FOR SMT m1rRXgP2xpDI")
|
||||
hasher := newHasher(false)
|
||||
defer returnHasherToPool(hasher)
|
||||
magicHash = hasher.hashData(magicSMTBytes)
|
||||
}
|
||||
|
||||
// Prove constructs a merkle proof for SMT, it respect the protocol used by the ethereum-trie
|
||||
// but save the node data with a compact form
|
||||
func (mt *ZkTrieImpl) prove(kHash *zkt.Hash, fromLevel uint, writeNode func(*Node) error) error {
|
||||
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
var nodes []*Node
|
||||
tn := mt.rootKey
|
||||
for i := 0; i < mt.maxLevels; i++ {
|
||||
n, err := mt.GetNode(tn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
finished := true
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
case NodeTypeLeaf:
|
||||
// notice even we found a leaf whose entry didn't match the expected k,
|
||||
// we still include it as the proof of absence
|
||||
case NodeTypeMiddle:
|
||||
finished = false
|
||||
if path[i] {
|
||||
tn = n.ChildR
|
||||
} else {
|
||||
tn = n.ChildL
|
||||
}
|
||||
default:
|
||||
return ErrInvalidNodeFound
|
||||
}
|
||||
|
||||
nodes = append(nodes, n)
|
||||
if finished {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, n := range nodes {
|
||||
if fromLevel > 0 {
|
||||
fromLevel--
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: notice here we may have broken some implicit on the proofDb:
|
||||
// the key is not kecca(value) and it even can not be derived from
|
||||
// the value by any means without a actually decoding
|
||||
if err := writeNode(n); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mt *ZkTrieImpl) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error {
|
||||
|
||||
kHash, err := zkt.NewHashFromBytes(common.BytesToHash(key).Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mt.prove(kHash, fromLevel, func(n *Node) error {
|
||||
key, err := n.Key()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return proofDb.Put(key[:], n.Value())
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we put this special kv pair in db so we can distinguish the type and
|
||||
// make suitable Proof
|
||||
return proofDb.Put(magicHash, magicSMTBytes)
|
||||
}
|
||||
|
||||
func buildZkTrieProof(rootKey *zkt.Hash, k *big.Int, lvl int, getNode func(key *zkt.Hash) (*Node, error)) (*Proof,
|
||||
*Node, error) {
|
||||
|
||||
p := &Proof{}
|
||||
var siblingKey *zkt.Hash
|
||||
|
||||
kHash := zkt.NewHashFromBigInt(k)
|
||||
path := getPath(lvl, kHash[:])
|
||||
|
||||
nextKey := rootKey
|
||||
for p.depth = 0; p.depth < uint(lvl); p.depth++ {
|
||||
n, err := getNode(nextKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
return p, n, nil
|
||||
case NodeTypeLeaf:
|
||||
if bytes.Equal(kHash[:], n.NodeKey[:]) {
|
||||
p.Existence = true
|
||||
return p, n, nil
|
||||
}
|
||||
// We found a leaf whose entry didn't match hIndex
|
||||
p.NodeAux = &NodeAux{Key: n.NodeKey, Value: n.valueHash}
|
||||
return p, n, nil
|
||||
case NodeTypeMiddle:
|
||||
if path[p.depth] {
|
||||
nextKey = n.ChildR
|
||||
siblingKey = n.ChildL
|
||||
} else {
|
||||
nextKey = n.ChildL
|
||||
siblingKey = n.ChildR
|
||||
}
|
||||
default:
|
||||
return nil, nil, ErrInvalidNodeFound
|
||||
}
|
||||
if !bytes.Equal(siblingKey[:], zkt.HashZero[:]) {
|
||||
zkt.SetBitBigEndian(p.notempties[:], p.depth)
|
||||
p.Siblings = append(p.Siblings, siblingKey)
|
||||
}
|
||||
}
|
||||
return nil, nil, ErrKeyNotFound
|
||||
|
||||
}
|
||||
|
||||
// DecodeProof try to decode a node bytes, return can be nil for any non-node data (magic code)
|
||||
func DecodeSMTProof(data []byte) (*Node, error) {
|
||||
|
||||
if bytes.Equal(magicSMTBytes, data) {
|
||||
//skip magic bytes node
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return NewNodeFromBytes(data)
|
||||
}
|
||||
|
||||
// VerifyProof checks merkle proofs. The given proof must contain the value for
|
||||
// key in a trie with the given root hash. VerifyProof returns an error if the
|
||||
// proof contains invalid trie nodes or the wrong value.
|
||||
func VerifyProofSMT(rootHash common.Hash, key []byte, proofDb ethdb.KeyValueReader) (value []byte, err error) {
|
||||
|
||||
h, err := zkt.NewHashFromBytes(rootHash.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
word := zkt.NewByte32FromBytesPaddingZero(key)
|
||||
k, err := word.Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proof, n, err := buildZkTrieProof(h, k, len(key)*8, func(key *zkt.Hash) (*Node, error) {
|
||||
buf, _ := proofDb.Get(key[:])
|
||||
if buf == nil {
|
||||
return nil, ErrKeyNotFound
|
||||
}
|
||||
n, err := NewNodeFromBytes(buf)
|
||||
return n, err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// do not contain the key
|
||||
return nil, err
|
||||
} else if !proof.Existence {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if VerifyProofZkTrie(h, proof, n) {
|
||||
return n.Data(), nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("bad proof node %v", proof)
|
||||
}
|
||||
}
|
||||
|
|
@ -24,8 +24,9 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
zkt "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb/memorydb"
|
||||
)
|
||||
|
|
@ -36,7 +37,7 @@ func init() {
|
|||
|
||||
// makeProvers creates Merkle trie provers based on different implementations to
|
||||
// test all variations.
|
||||
func makeSMTProvers(mt *ZkTrieImpl) []func(key []byte) *memorydb.Database {
|
||||
func makeSMTProvers(mt *ZkTrie) []func(key []byte) *memorydb.Database {
|
||||
var provers []func(key []byte) *memorydb.Database
|
||||
|
||||
// Create a direct trie based Merkle prover
|
||||
|
|
@ -47,7 +48,11 @@ func makeSMTProvers(mt *ZkTrieImpl) []func(key []byte) *memorydb.Database {
|
|||
panic(err)
|
||||
}
|
||||
proof := memorydb.New()
|
||||
mt.Prove(k.Bytes(), 0, proof)
|
||||
err = mt.Prove(common.BytesToHash(k.Bytes()).Bytes(), 0, proof)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return proof
|
||||
})
|
||||
return provers
|
||||
|
|
@ -58,13 +63,14 @@ func verifyValue(proveVal []byte, vPreimage []byte) bool {
|
|||
}
|
||||
|
||||
func TestSMTOneElementProof(t *testing.T) {
|
||||
mt, _ := NewZkTrieImpl(NewZktrieDatabase((memorydb.New())), 64)
|
||||
tr, _ := NewZkTrie(common.Hash{}, NewZktrieDatabase((memorydb.New())))
|
||||
mt := &zkTrieImplTestWrapper{tr.Tree()}
|
||||
err := mt.UpdateWord(
|
||||
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("k"), 32)),
|
||||
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("v"), 32)),
|
||||
)
|
||||
assert.Nil(t, err)
|
||||
for i, prover := range makeSMTProvers(mt) {
|
||||
for i, prover := range makeSMTProvers(tr) {
|
||||
keyBytes := bytes.Repeat([]byte("k"), 32)
|
||||
proof := prover(keyBytes)
|
||||
if proof == nil {
|
||||
|
|
@ -85,7 +91,7 @@ func TestSMTOneElementProof(t *testing.T) {
|
|||
|
||||
func TestSMTProof(t *testing.T) {
|
||||
mt, vals := randomZktrie(t, 500)
|
||||
root := mt.Root()
|
||||
root := mt.Tree().Root()
|
||||
for i, prover := range makeSMTProvers(mt) {
|
||||
for _, kv := range vals {
|
||||
proof := prover(kv.k)
|
||||
|
|
@ -105,7 +111,7 @@ func TestSMTProof(t *testing.T) {
|
|||
|
||||
func TestSMTBadProof(t *testing.T) {
|
||||
mt, vals := randomZktrie(t, 500)
|
||||
root := mt.Root()
|
||||
root := mt.Tree().Root()
|
||||
for i, prover := range makeSMTProvers(mt) {
|
||||
for _, kv := range vals {
|
||||
proof := prover(kv.k)
|
||||
|
|
@ -134,14 +140,15 @@ func TestSMTBadProof(t *testing.T) {
|
|||
// Tests that missing keys can also be proven. The test explicitly uses a single
|
||||
// entry trie and checks for missing keys both before and after the single entry.
|
||||
func TestSMTMissingKeyProof(t *testing.T) {
|
||||
mt, _ := NewZkTrieImpl(NewZktrieDatabase((memorydb.New())), 64)
|
||||
tr, _ := NewZkTrie(common.Hash{}, NewZktrieDatabase((memorydb.New())))
|
||||
mt := &zkTrieImplTestWrapper{tr.Tree()}
|
||||
err := mt.UpdateWord(
|
||||
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("k"), 20)),
|
||||
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("v"), 20)),
|
||||
)
|
||||
assert.Nil(t, err)
|
||||
|
||||
prover := makeSMTProvers(mt)[0]
|
||||
prover := makeSMTProvers(tr)[0]
|
||||
|
||||
for i, key := range []string{"a", "j", "l", "z"} {
|
||||
keyBytes := bytes.Repeat([]byte(key), 32)
|
||||
|
|
@ -160,11 +167,12 @@ func TestSMTMissingKeyProof(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func randomZktrie(t *testing.T, n int) (*ZkTrieImpl, map[string]*kv) {
|
||||
mt, err := NewZkTrieImpl(NewZktrieDatabase((memorydb.New())), 64)
|
||||
func randomZktrie(t *testing.T, n int) (*ZkTrie, map[string]*kv) {
|
||||
tr, err := NewZkTrie(common.Hash{}, NewZktrieDatabase((memorydb.New())))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mt := &zkTrieImplTestWrapper{tr.Tree()}
|
||||
vals := make(map[string]*kv)
|
||||
for i := byte(0); i < 100; i++ {
|
||||
|
||||
|
|
@ -185,5 +193,5 @@ func randomZktrie(t *testing.T, n int) (*ZkTrieImpl, map[string]*kv) {
|
|||
vals[string(value.k)] = value
|
||||
}
|
||||
|
||||
return mt, vals
|
||||
return tr, vals
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
zkt "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb/memorydb"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
|
||||
zktrie "github.com/scroll-tech/zktrie/trie"
|
||||
zkt "github.com/scroll-tech/zktrie/types"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
zkt "github.com/scroll-tech/go-ethereum/core/types/zktrie"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb/memorydb"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/scroll-tech/go-ethereum/trie"
|
||||
|
|
@ -39,10 +41,10 @@ func addressToKey(addr common.Address) *zkt.Hash {
|
|||
}
|
||||
|
||||
//resume the proof bytes into db and return the leaf node
|
||||
func resumeProofs(proof []hexutil.Bytes, db *memorydb.Database) *trie.Node {
|
||||
func resumeProofs(proof []hexutil.Bytes, db *memorydb.Database) *zktrie.Node {
|
||||
for _, buf := range proof {
|
||||
|
||||
n, err := trie.DecodeSMTProof(buf)
|
||||
n, err := zktrie.DecodeSMTProof(buf)
|
||||
if err != nil {
|
||||
log.Warn("decode proof string fail", "error", err)
|
||||
} else if n != nil {
|
||||
|
|
@ -53,7 +55,7 @@ func resumeProofs(proof []hexutil.Bytes, db *memorydb.Database) *trie.Node {
|
|||
//notice: must consistent with trie/merkletree.go
|
||||
bt := k[:]
|
||||
db.Put(bt, buf)
|
||||
if n.Type == trie.NodeTypeLeaf || n.Type == trie.NodeTypeEmpty {
|
||||
if n.Type == zktrie.NodeTypeLeaf || n.Type == zktrie.NodeTypeEmpty {
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
|
@ -68,14 +70,14 @@ func resumeProofs(proof []hexutil.Bytes, db *memorydb.Database) *trie.Node {
|
|||
// whole path in sequence, from root to leaf
|
||||
func decodeProofForMPTPath(proof proofList, path *SMTPath) {
|
||||
|
||||
var lastNode *trie.Node
|
||||
var lastNode *zktrie.Node
|
||||
keyPath := big.NewInt(0)
|
||||
path.KeyPathPart = (*hexutil.Big)(keyPath)
|
||||
|
||||
keyCounter := big.NewInt(1)
|
||||
|
||||
for _, buf := range proof {
|
||||
n, err := trie.DecodeSMTProof(buf)
|
||||
n, err := zktrie.DecodeSMTProof(buf)
|
||||
if err != nil {
|
||||
log.Warn("decode proof string fail", "error", err)
|
||||
} else if n != nil {
|
||||
|
|
@ -105,9 +107,9 @@ func decodeProofForMPTPath(proof proofList, path *SMTPath) {
|
|||
keyCounter.Mul(keyCounter, big.NewInt(2))
|
||||
}
|
||||
switch n.Type {
|
||||
case trie.NodeTypeMiddle:
|
||||
case zktrie.NodeTypeMiddle:
|
||||
lastNode = n
|
||||
case trie.NodeTypeLeaf:
|
||||
case zktrie.NodeTypeLeaf:
|
||||
vhash, _ := n.ValueKey()
|
||||
path.Leaf = &SMTPathNode{
|
||||
//here we just return the inner represent of hash (little endian, reversed byte order to common hash)
|
||||
|
|
@ -125,7 +127,7 @@ func decodeProofForMPTPath(proof proofList, path *SMTPath) {
|
|||
}
|
||||
|
||||
return
|
||||
case trie.NodeTypeEmpty:
|
||||
case zktrie.NodeTypeEmpty:
|
||||
return
|
||||
default:
|
||||
panic(fmt.Errorf("unknown node type %d", n.Type))
|
||||
|
|
@ -158,7 +160,7 @@ func NewZkTrieProofWriter(storage *types.StorageTrace) (*zktrieProofWriter, erro
|
|||
for addrs, proof := range storage.Proofs {
|
||||
if n := resumeProofs(proof, underlayerDb); n != nil {
|
||||
addr := common.HexToAddress(addrs)
|
||||
if n.Type == trie.NodeTypeEmpty {
|
||||
if n.Type == zktrie.NodeTypeEmpty {
|
||||
accounts[addr] = nil
|
||||
} else if acc, err := types.UnmarshalStateAccount(n.Data()); err == nil {
|
||||
if bytes.Equal(n.NodeKey[:], addressToKey(addr)[:]) {
|
||||
|
|
@ -371,7 +373,8 @@ func (w *zktrieProofWriter) traceAccountUpdate(addr common.Address, updateAccDat
|
|||
}
|
||||
|
||||
var proof proofList
|
||||
if err := w.tracingZktrie.Prove(addr.Bytes32(), 0, &proof); err != nil {
|
||||
s_key, _ := zkt.ToSecureKeyBytes(addr.Bytes())
|
||||
if err := w.tracingZktrie.Prove(s_key.Bytes(), 0, &proof); err != nil {
|
||||
return nil, fmt.Errorf("prove BEFORE state for <%x> fail: %s", addr.Bytes(), err)
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +415,7 @@ func (w *zktrieProofWriter) traceAccountUpdate(addr common.Address, updateAccDat
|
|||
}
|
||||
|
||||
proof = proofList{}
|
||||
if err := w.tracingZktrie.Prove(addr.Bytes32(), 0, &proof); err != nil {
|
||||
if err := w.tracingZktrie.Prove(s_key.Bytes(), 0, &proof); err != nil {
|
||||
return nil, fmt.Errorf("prove AFTER state fail: %s", err)
|
||||
}
|
||||
|
||||
|
|
@ -465,7 +468,8 @@ func (w *zktrieProofWriter) traceStorageUpdate(addr common.Address, key, value [
|
|||
}
|
||||
|
||||
var storageBeforeProof, storageAfterProof proofList
|
||||
if err := trie.Prove(storeKey.Bytes(), 0, &storageBeforeProof); err != nil {
|
||||
s_key, _ := zkt.ToSecureKeyBytes(storeKey.Bytes())
|
||||
if err := trie.Prove(s_key.Bytes(), 0, &storageBeforeProof); err != nil {
|
||||
return nil, fmt.Errorf("prove BEFORE storage state fail: %s", err)
|
||||
}
|
||||
|
||||
|
|
@ -488,7 +492,7 @@ func (w *zktrieProofWriter) traceStorageUpdate(addr common.Address, key, value [
|
|||
}
|
||||
}
|
||||
|
||||
if err := trie.Prove(storeKey.Bytes(), 0, &storageAfterProof); err != nil {
|
||||
if err := trie.Prove(s_key.Bytes(), 0, &storageAfterProof); err != nil {
|
||||
return nil, fmt.Errorf("prove AFTER storage state fail: %s", err)
|
||||
}
|
||||
decodeProofForMPTPath(storageAfterProof, statePath[1])
|
||||
|
|
@ -561,10 +565,7 @@ func (w *zktrieProofWriter) HandleNewState(accountState *types.AccountWrapper) (
|
|||
return nil, fmt.Errorf("update account state %s fail: %s", accountState.Address, err)
|
||||
}
|
||||
|
||||
hash, err := zkt.NewHashFromBytes(stateRoot[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("malform of state root in account %s", accountState.Address)
|
||||
}
|
||||
hash := zkt.NewHashFromBytes(stateRoot[:])
|
||||
out.CommonStateRoot = hash[:]
|
||||
return out, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue