diff --git a/portalnetwork/state/types.go b/portalnetwork/state/types.go index f3de06084c62..04401bc1c41c 100644 --- a/portalnetwork/state/types.go +++ b/portalnetwork/state/types.go @@ -65,7 +65,7 @@ func (n *Nibbles) Deserialize(dr *codec.DecodingReader) error { return err } flag, first := unpackNibblePair(firstByte) - nibbles := make([]byte, 1+2*len(packedNibbles)) + nibbles := make([]byte, 0, 1+2*len(packedNibbles)) if flag == 0 { if first != 0 { @@ -77,10 +77,9 @@ func (n *Nibbles) Deserialize(dr *codec.DecodingReader) error { return fmt.Errorf("nibbles: The highest 4 bits of the first byte must be 0 or 1, but was: %x", flag) } - for i, b := range packedNibbles { + for _, b := range packedNibbles { left, right := unpackNibblePair(b) - nibbles[1+2*i] = left - nibbles[1+2*i+1] = right + nibbles = append(nibbles, left, right) } unpackedNibbles, err := FromUnpackedNibbles(nibbles) @@ -114,3 +113,121 @@ func FromUnpackedNibbles(nibbles []byte) (*Nibbles, error) { func unpackNibblePair(pair byte) (byte, byte) { return pair >> 4, pair & 0xf } + +// test data from +// https://github.com/ethereum/portal-network-specs/blob/master/state/state-network-test-vectors.md +type AccountTrieNodeKey struct { + Path Nibbles + NodeHash common.Bytes32 +} + +func (a *AccountTrieNodeKey) Deserialize(dr *codec.DecodingReader) error { + return dr.Container( + &a.Path, + &a.NodeHash, + ) +} + +func (a *AccountTrieNodeKey) Serialize(w *codec.EncodingWriter) error { + return w.Container( + &a.Path, + &a.NodeHash, + ) +} + +func (a *AccountTrieNodeKey) ByteLength(spec *common.Spec) uint64 { + return codec.ContainerLength( + &a.Path, + &a.NodeHash, + ) +} + +func (a *AccountTrieNodeKey) FixedLength(spec *common.Spec) uint64 { + return 0 +} + +func (a *AccountTrieNodeKey) HashTreeRoot(spec *common.Spec, hFn tree.HashFn) common.Root { + return hFn.HashTreeRoot( + &a.Path, + &a.NodeHash, + ) +} + +type ContractStorageTrieNodeKey struct { + Address common.Eth1Address + Path Nibbles + NodeHash common.Bytes32 +} + +func (c *ContractStorageTrieNodeKey) Deserialize(dr *codec.DecodingReader) error { + return dr.Container( + &c.Address, + &c.Path, + &c.NodeHash, + ) +} + +func (c *ContractStorageTrieNodeKey) Serialize(w *codec.EncodingWriter) error { + return w.Container( + &c.Address, + &c.Path, + &c.NodeHash, + ) +} + +func (c *ContractStorageTrieNodeKey) ByteLength(spec *common.Spec) uint64 { + return codec.ContainerLength( + &c.Address, + &c.Path, + &c.NodeHash, + ) +} + +func (c *ContractStorageTrieNodeKey) FixedLength(spec *common.Spec) uint64 { + return 0 +} + +func (c *ContractStorageTrieNodeKey) HashTreeRoot(spec *common.Spec, hFn tree.HashFn) common.Root { + return hFn.HashTreeRoot( + &c.Address, + &c.Path, + &c.NodeHash, + ) +} + +type ContractBytecodeKey struct { + Address common.Eth1Address + NodeHash common.Bytes32 +} + +func (c *ContractBytecodeKey) Deserialize(dr *codec.DecodingReader) error { + return dr.FixedLenContainer( + &c.Address, + &c.NodeHash, + ) +} + +func (c *ContractBytecodeKey) Serialize(w *codec.EncodingWriter) error { + return w.FixedLenContainer( + &c.Address, + &c.NodeHash, + ) +} + +func (c *ContractBytecodeKey) ByteLength(spec *common.Spec) uint64 { + return codec.ContainerLength( + &c.Address, + &c.NodeHash, + ) +} + +func (c *ContractBytecodeKey) FixedLength(spec *common.Spec) uint64 { + return 0 +} + +func (c *ContractBytecodeKey) HashTreeRoot(spec *common.Spec, hFn tree.HashFn) common.Root { + return hFn.HashTreeRoot( + &c.Address, + &c.NodeHash, + ) +} diff --git a/portalnetwork/state/types_test.go b/portalnetwork/state/types_test.go index 66b3890bb8e3..b40198378743 100644 --- a/portalnetwork/state/types_test.go +++ b/portalnetwork/state/types_test.go @@ -5,8 +5,10 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/protolambda/zrnt/eth2/beacon/common" "github.com/protolambda/ztyp/codec" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNibblesEncodeDecode(t *testing.T) { @@ -80,6 +82,11 @@ func TestNibblesEncodeDecode(t *testing.T) { err = n.Serialize(codec.NewEncodingWriter(&tt.args.buf)) assert.NoError(t, err) assert.Equal(t, tt.encodeds, hexutil.Encode(tt.args.buf.Bytes())) + + newNibble := &Nibbles{} + err = newNibble.Deserialize(codec.NewDecodingReader(&tt.args.buf, uint64(len(tt.args.buf.Bytes())))) + require.NoError(t, err) + require.Equal(t, newNibble.Nibbles, n.Nibbles) }) } } @@ -196,3 +203,66 @@ func initSlice(n int, v byte) []byte { } return s } + +func TestAccountTrieNode(t *testing.T) { + n, err := FromUnpackedNibbles([]byte{8, 6, 7, 9, 14, 8, 14, 13}) + require.NoError(t, err) + + accountTrieNode := &AccountTrieNodeKey{ + Path: *n, + NodeHash: common.Bytes32(hexutil.MustDecode("0x6225fcc63b22b80301d9f2582014e450e91f9b329b7cc87ad16894722fff5296")), + } + var buf bytes.Buffer + err = accountTrieNode.Serialize(codec.NewEncodingWriter(&buf)) + require.NoError(t, err) + hexStr := hexutil.Encode(buf.Bytes()) + require.Equal(t, hexStr, "0x240000006225fcc63b22b80301d9f2582014e450e91f9b329b7cc87ad16894722fff5296008679e8ed") + + newAccount := &AccountTrieNodeKey{} + err = newAccount.Deserialize(codec.NewDecodingReader(&buf, uint64(len(buf.Bytes())))) + require.NoError(t, err) + require.Equal(t, newAccount.NodeHash, accountTrieNode.NodeHash) + require.Equal(t, newAccount.Path.Nibbles, accountTrieNode.Path.Nibbles) +} + +func TestContractStorageTrieNode(t *testing.T) { + path, err := FromUnpackedNibbles([]byte{4, 0, 5, 7, 8, 7}) + require.NoError(t, err) + contractStorage := &ContractStorageTrieNodeKey{ + Address: common.Eth1Address(hexutil.MustDecode("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), + Path: *path, + NodeHash: common.Bytes32(hexutil.MustDecode("0xeb43d68008d216e753fef198cf51077f5a89f406d9c244119d1643f0f2b19011")), + } + + var buf bytes.Buffer + err = contractStorage.Serialize(codec.NewEncodingWriter(&buf)) + require.NoError(t, err) + hexStr := hexutil.Encode(buf.Bytes()) + require.Equal(t, hexStr, "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc238000000eb43d68008d216e753fef198cf51077f5a89f406d9c244119d1643f0f2b1901100405787") + + newContractStorage := &ContractStorageTrieNodeKey{} + err = newContractStorage.Deserialize(codec.NewDecodingReader(&buf, uint64(len(buf.Bytes())))) + require.NoError(t, err) + require.Equal(t, newContractStorage.NodeHash, contractStorage.NodeHash) + require.Equal(t, newContractStorage.Path.Nibbles, contractStorage.Path.Nibbles) + require.Equal(t, newContractStorage.Address, contractStorage.Address) +} + +func TestContractBytecode(t *testing.T) { + bytecode := &ContractBytecodeKey{ + Address: common.Eth1Address(hexutil.MustDecode("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), + NodeHash: common.Bytes32(hexutil.MustDecode("0xd0a06b12ac47863b5c7be4185c2deaad1c61557033f56c7d4ea74429cbb25e23")), + } + + var buf bytes.Buffer + err := bytecode.Serialize(codec.NewEncodingWriter(&buf)) + require.NoError(t, err) + hexStr := hexutil.Encode(buf.Bytes()) + require.Equal(t, hexStr, "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2d0a06b12ac47863b5c7be4185c2deaad1c61557033f56c7d4ea74429cbb25e23") + + newBytecode := &ContractBytecodeKey{} + err = newBytecode.Deserialize(codec.NewDecodingReader(&buf, uint64(len(buf.Bytes())))) + require.NoError(t, err) + require.Equal(t, newBytecode.NodeHash, bytecode.NodeHash) + require.Equal(t, newBytecode.Address, bytecode.Address) +}