From 47b6d2779280963f24e3ef6eec98e7e093c4ac06 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Wed, 16 Feb 2022 20:51:39 +0530 Subject: [PATCH 01/22] Cover more store/load child trie related test cases --- internal/trie/node/node_mock.go | 253 ++++++++++++++++++++++++++++++++ lib/trie/database.go | 2 + lib/trie/database_test.go | 53 +++++++ 3 files changed, 308 insertions(+) create mode 100644 internal/trie/node/node_mock.go diff --git a/internal/trie/node/node_mock.go b/internal/trie/node/node_mock.go new file mode 100644 index 0000000000..409d3526bf --- /dev/null +++ b/internal/trie/node/node_mock.go @@ -0,0 +1,253 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: internal/trie/node/node.go + +// Package github.com/ChainSafe/gossamer/internal/trie/node is a generated GoMock package. +package node + +import ( + gomock "github.com/golang/mock/gomock" + gotree "github.com/qdm12/gotree" + reflect "reflect" +) + +// MockNode is a mock of Node interface. +type MockNode struct { + ctrl *gomock.Controller + recorder *MockNodeMockRecorder +} + +// MockNodeMockRecorder is the mock recorder for MockNode. +type MockNodeMockRecorder struct { + mock *MockNode +} + +// NewMockNode creates a new mock instance. +func NewMockNode(ctrl *gomock.Controller) *MockNode { + mock := &MockNode{ctrl: ctrl} + mock.recorder = &MockNodeMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNode) EXPECT() *MockNodeMockRecorder { + return m.recorder +} + +// Copy mocks base method. +func (m *MockNode) Copy(copyChildren bool) Node { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Copy", copyChildren) + ret0, _ := ret[0].(Node) + return ret0 +} + +// Copy indicates an expected call of Copy. +func (mr *MockNodeMockRecorder) Copy(copyChildren interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Copy", reflect.TypeOf((*MockNode)(nil).Copy), copyChildren) +} + +// Encode mocks base method. +func (m *MockNode) Encode(buffer Buffer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Encode", buffer) + ret0, _ := ret[0].(error) + return ret0 +} + +// Encode indicates an expected call of Encode. +func (mr *MockNodeMockRecorder) Encode(buffer interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Encode", reflect.TypeOf((*MockNode)(nil).Encode), buffer) +} + +// EncodeAndHash mocks base method. +func (m *MockNode) EncodeAndHash() ([]byte, []byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EncodeAndHash") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].([]byte) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// EncodeAndHash indicates an expected call of EncodeAndHash. +func (mr *MockNodeMockRecorder) EncodeAndHash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EncodeAndHash", reflect.TypeOf((*MockNode)(nil).EncodeAndHash)) +} + +// GetGeneration mocks base method. +func (m *MockNode) GetGeneration() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGeneration") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetGeneration indicates an expected call of GetGeneration. +func (mr *MockNodeMockRecorder) GetGeneration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGeneration", reflect.TypeOf((*MockNode)(nil).GetGeneration)) +} + +// GetHash mocks base method. +func (m *MockNode) GetHash() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetHash") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// GetHash indicates an expected call of GetHash. +func (mr *MockNodeMockRecorder) GetHash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHash", reflect.TypeOf((*MockNode)(nil).GetHash)) +} + +// GetKey mocks base method. +func (m *MockNode) GetKey() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetKey") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// GetKey indicates an expected call of GetKey. +func (mr *MockNodeMockRecorder) GetKey() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKey", reflect.TypeOf((*MockNode)(nil).GetKey)) +} + +// GetValue mocks base method. +func (m *MockNode) GetValue() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetValue") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// GetValue indicates an expected call of GetValue. +func (mr *MockNodeMockRecorder) GetValue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValue", reflect.TypeOf((*MockNode)(nil).GetValue)) +} + +// IsDirty mocks base method. +func (m *MockNode) IsDirty() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsDirty") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsDirty indicates an expected call of IsDirty. +func (mr *MockNodeMockRecorder) IsDirty() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsDirty", reflect.TypeOf((*MockNode)(nil).IsDirty)) +} + +// ScaleEncodeHash mocks base method. +func (m *MockNode) ScaleEncodeHash() ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ScaleEncodeHash") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ScaleEncodeHash indicates an expected call of ScaleEncodeHash. +func (mr *MockNodeMockRecorder) ScaleEncodeHash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScaleEncodeHash", reflect.TypeOf((*MockNode)(nil).ScaleEncodeHash)) +} + +// SetDirty mocks base method. +func (m *MockNode) SetDirty(dirty bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetDirty", dirty) +} + +// SetDirty indicates an expected call of SetDirty. +func (mr *MockNodeMockRecorder) SetDirty(dirty interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDirty", reflect.TypeOf((*MockNode)(nil).SetDirty), dirty) +} + +// SetEncodingAndHash mocks base method. +func (m *MockNode) SetEncodingAndHash(encoding, hash []byte) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetEncodingAndHash", encoding, hash) +} + +// SetEncodingAndHash indicates an expected call of SetEncodingAndHash. +func (mr *MockNodeMockRecorder) SetEncodingAndHash(encoding, hash interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetEncodingAndHash", reflect.TypeOf((*MockNode)(nil).SetEncodingAndHash), encoding, hash) +} + +// SetGeneration mocks base method. +func (m *MockNode) SetGeneration(generation uint64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetGeneration", generation) +} + +// SetGeneration indicates an expected call of SetGeneration. +func (mr *MockNodeMockRecorder) SetGeneration(generation interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetGeneration", reflect.TypeOf((*MockNode)(nil).SetGeneration), generation) +} + +// SetKey mocks base method. +func (m *MockNode) SetKey(key []byte) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetKey", key) +} + +// SetKey indicates an expected call of SetKey. +func (mr *MockNodeMockRecorder) SetKey(key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetKey", reflect.TypeOf((*MockNode)(nil).SetKey), key) +} + +// String mocks base method. +func (m *MockNode) String() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "String") + ret0, _ := ret[0].(string) + return ret0 +} + +// String indicates an expected call of String. +func (mr *MockNodeMockRecorder) String() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockNode)(nil).String)) +} + +// StringNode mocks base method. +func (m *MockNode) StringNode() *gotree.Node { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StringNode") + ret0, _ := ret[0].(*gotree.Node) + return ret0 +} + +// StringNode indicates an expected call of StringNode. +func (mr *MockNodeMockRecorder) StringNode() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StringNode", reflect.TypeOf((*MockNode)(nil).StringNode)) +} + +// Type mocks base method. +func (m *MockNode) Type() Type { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Type") + ret0, _ := ret[0].(Type) + return ret0 +} + +// Type indicates an expected call of Type. +func (mr *MockNodeMockRecorder) Type() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Type", reflect.TypeOf((*MockNode)(nil).Type)) +} diff --git a/lib/trie/database.go b/lib/trie/database.go index 312da1ca3d..886f437bba 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -209,11 +209,13 @@ func (t *Trie) load(db chaindb.Database, n Node) error { for _, key := range t.GetKeysWithPrefix(ChildStorageKeyPrefix) { childTrie := NewEmptyTrie() value := t.Get(key) + // TODO: Tests this error err := childTrie.Load(db, common.NewHash(value)) if err != nil { return fmt.Errorf("failed to load child trie with root hash=0x%x: %w", value, err) } + // TODO: Test this error err = t.PutChild(value, childTrie) if err != nil { return fmt.Errorf("failed to insert child trie with root hash=0x%x into main trie: %w", diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index f121573d41..8c36e099e4 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -5,11 +5,14 @@ package trie import ( "bytes" + "errors" "fmt" "testing" "github.com/ChainSafe/chaindb" + "github.com/ChainSafe/gossamer/internal/trie/node" "github.com/ChainSafe/gossamer/lib/utils" + gomock "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -387,3 +390,53 @@ func TestTrie_GetFromDB(t *testing.T) { } } } + +func TestLoadWithChildTriesFails(t *testing.T) { + // Use a fake node implementation in which Encode always fails + // Make that root of one of the childtries + // Run load and check that it fails + + testCase := []Test{ + {key: []byte{0x01, 0x35}, value: []byte("pen")}, + {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, + {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, + {key: []byte{0xf2}, value: []byte("feather")}, + {key: []byte{0xf2, 0x3}, value: []byte("f")}, + {key: []byte{0x09, 0xd3}, value: []byte("noot")}, + {key: []byte{0x07}, value: []byte("ramen")}, + {key: []byte{0}, value: nil}, + } + + trie := NewEmptyTrie() + + for _, test := range testCase { + trie.Put(test.key, test.value) + } + sampleChildTrie := NewEmptyTrie() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockNode := node.NewMockNode(mockCtrl) + mockNode.EXPECT().Encode(gomock.Any()).AnyTimes().Return(nil) + // TODO: Mock remaining methods + + sampleChildTrie.root = mockNode + + keyToChild := []byte("test") + err := trie.PutChild(keyToChild, sampleChildTrie) + require.NoError(t, err) + + db := newTestDB(t) + err = trie.Store(db) + require.NoError(t, err) + + mockNode.EXPECT().Encode(gomock.Any()).AnyTimes().Return(errors.New("some error")) + + res := NewEmptyTrie() + err = res.Load(db, trie.MustHash()) + require.NoError(t, err) + fmt.Printf("expected:\n %s\n", trie.String()) + fmt.Printf("actual:\n %s\n", res.String()) + + require.Equal(t, trie.MustHash(), res.MustHash()) +} From 29ace8a056ce8bdee190dd83e4ebbd7510efe12a Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 21 Feb 2022 20:38:52 +0530 Subject: [PATCH 02/22] test error `failed to insert child trie with root` in trie.Load --- internal/trie/node/leaf.go | 56 +++++++ internal/trie/node/node_mock.go | 253 -------------------------------- lib/trie/database_test.go | 28 ++-- 3 files changed, 71 insertions(+), 266 deletions(-) delete mode 100644 internal/trie/node/node_mock.go diff --git a/internal/trie/node/leaf.go b/internal/trie/node/leaf.go index b5a5e02b2a..313af82eee 100644 --- a/internal/trie/node/leaf.go +++ b/internal/trie/node/leaf.go @@ -4,9 +4,12 @@ package node import ( + "errors" "fmt" "sync" + "github.com/ChainSafe/gossamer/internal/trie/codec" + "github.com/ChainSafe/gossamer/pkg/scale" "github.com/qdm12/gotree" ) @@ -73,3 +76,56 @@ func bytesToString(b []byte) (s string) { } } + +type MockLeaf struct { + Leaf + + Fail bool +} + +// Encode is a hijackable Encode method. +func (m *MockLeaf) Encode(buffer Buffer) (err error) { + if m.Fail { + return errors.New("some error") + } + + m.Leaf.encodingMu.RLock() + if !m.Leaf.Dirty && m.Leaf.Encoding != nil { + _, err = buffer.Write(m.Leaf.Encoding) + m.Leaf.encodingMu.RUnlock() + if err != nil { + return fmt.Errorf("cannot write stored encoding to buffer: %w", err) + } + return nil + } + m.Leaf.encodingMu.RUnlock() + + err = m.Leaf.encodeHeader(buffer) + if err != nil { + return fmt.Errorf("cannot encode header: %w", err) + } + + keyLE := codec.NibblesToKeyLE(m.Leaf.Key) + _, err = buffer.Write(keyLE) + if err != nil { + return fmt.Errorf("cannot write LE key to buffer: %w", err) + } + + encodedValue, err := scale.Marshal(m.Leaf.Value) // TODO scale encoder to write to buffer + if err != nil { + return fmt.Errorf("cannot scale marshal value: %w", err) + } + + _, err = buffer.Write(encodedValue) + if err != nil { + return fmt.Errorf("cannot write scale encoded value to buffer: %w", err) + } + + // TODO remove this copying since it defeats the purpose of `buffer` + // and the sync.Pool. + m.Leaf.encodingMu.Lock() + defer m.Leaf.encodingMu.Unlock() + m.Leaf.Encoding = make([]byte, buffer.Len()) + copy(m.Leaf.Encoding, buffer.Bytes()) + return nil +} diff --git a/internal/trie/node/node_mock.go b/internal/trie/node/node_mock.go deleted file mode 100644 index 409d3526bf..0000000000 --- a/internal/trie/node/node_mock.go +++ /dev/null @@ -1,253 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: internal/trie/node/node.go - -// Package github.com/ChainSafe/gossamer/internal/trie/node is a generated GoMock package. -package node - -import ( - gomock "github.com/golang/mock/gomock" - gotree "github.com/qdm12/gotree" - reflect "reflect" -) - -// MockNode is a mock of Node interface. -type MockNode struct { - ctrl *gomock.Controller - recorder *MockNodeMockRecorder -} - -// MockNodeMockRecorder is the mock recorder for MockNode. -type MockNodeMockRecorder struct { - mock *MockNode -} - -// NewMockNode creates a new mock instance. -func NewMockNode(ctrl *gomock.Controller) *MockNode { - mock := &MockNode{ctrl: ctrl} - mock.recorder = &MockNodeMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockNode) EXPECT() *MockNodeMockRecorder { - return m.recorder -} - -// Copy mocks base method. -func (m *MockNode) Copy(copyChildren bool) Node { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Copy", copyChildren) - ret0, _ := ret[0].(Node) - return ret0 -} - -// Copy indicates an expected call of Copy. -func (mr *MockNodeMockRecorder) Copy(copyChildren interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Copy", reflect.TypeOf((*MockNode)(nil).Copy), copyChildren) -} - -// Encode mocks base method. -func (m *MockNode) Encode(buffer Buffer) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Encode", buffer) - ret0, _ := ret[0].(error) - return ret0 -} - -// Encode indicates an expected call of Encode. -func (mr *MockNodeMockRecorder) Encode(buffer interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Encode", reflect.TypeOf((*MockNode)(nil).Encode), buffer) -} - -// EncodeAndHash mocks base method. -func (m *MockNode) EncodeAndHash() ([]byte, []byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EncodeAndHash") - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].([]byte) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// EncodeAndHash indicates an expected call of EncodeAndHash. -func (mr *MockNodeMockRecorder) EncodeAndHash() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EncodeAndHash", reflect.TypeOf((*MockNode)(nil).EncodeAndHash)) -} - -// GetGeneration mocks base method. -func (m *MockNode) GetGeneration() uint64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetGeneration") - ret0, _ := ret[0].(uint64) - return ret0 -} - -// GetGeneration indicates an expected call of GetGeneration. -func (mr *MockNodeMockRecorder) GetGeneration() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGeneration", reflect.TypeOf((*MockNode)(nil).GetGeneration)) -} - -// GetHash mocks base method. -func (m *MockNode) GetHash() []byte { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetHash") - ret0, _ := ret[0].([]byte) - return ret0 -} - -// GetHash indicates an expected call of GetHash. -func (mr *MockNodeMockRecorder) GetHash() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHash", reflect.TypeOf((*MockNode)(nil).GetHash)) -} - -// GetKey mocks base method. -func (m *MockNode) GetKey() []byte { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetKey") - ret0, _ := ret[0].([]byte) - return ret0 -} - -// GetKey indicates an expected call of GetKey. -func (mr *MockNodeMockRecorder) GetKey() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKey", reflect.TypeOf((*MockNode)(nil).GetKey)) -} - -// GetValue mocks base method. -func (m *MockNode) GetValue() []byte { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetValue") - ret0, _ := ret[0].([]byte) - return ret0 -} - -// GetValue indicates an expected call of GetValue. -func (mr *MockNodeMockRecorder) GetValue() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValue", reflect.TypeOf((*MockNode)(nil).GetValue)) -} - -// IsDirty mocks base method. -func (m *MockNode) IsDirty() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsDirty") - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsDirty indicates an expected call of IsDirty. -func (mr *MockNodeMockRecorder) IsDirty() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsDirty", reflect.TypeOf((*MockNode)(nil).IsDirty)) -} - -// ScaleEncodeHash mocks base method. -func (m *MockNode) ScaleEncodeHash() ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScaleEncodeHash") - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ScaleEncodeHash indicates an expected call of ScaleEncodeHash. -func (mr *MockNodeMockRecorder) ScaleEncodeHash() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScaleEncodeHash", reflect.TypeOf((*MockNode)(nil).ScaleEncodeHash)) -} - -// SetDirty mocks base method. -func (m *MockNode) SetDirty(dirty bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetDirty", dirty) -} - -// SetDirty indicates an expected call of SetDirty. -func (mr *MockNodeMockRecorder) SetDirty(dirty interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDirty", reflect.TypeOf((*MockNode)(nil).SetDirty), dirty) -} - -// SetEncodingAndHash mocks base method. -func (m *MockNode) SetEncodingAndHash(encoding, hash []byte) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetEncodingAndHash", encoding, hash) -} - -// SetEncodingAndHash indicates an expected call of SetEncodingAndHash. -func (mr *MockNodeMockRecorder) SetEncodingAndHash(encoding, hash interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetEncodingAndHash", reflect.TypeOf((*MockNode)(nil).SetEncodingAndHash), encoding, hash) -} - -// SetGeneration mocks base method. -func (m *MockNode) SetGeneration(generation uint64) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetGeneration", generation) -} - -// SetGeneration indicates an expected call of SetGeneration. -func (mr *MockNodeMockRecorder) SetGeneration(generation interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetGeneration", reflect.TypeOf((*MockNode)(nil).SetGeneration), generation) -} - -// SetKey mocks base method. -func (m *MockNode) SetKey(key []byte) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetKey", key) -} - -// SetKey indicates an expected call of SetKey. -func (mr *MockNodeMockRecorder) SetKey(key interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetKey", reflect.TypeOf((*MockNode)(nil).SetKey), key) -} - -// String mocks base method. -func (m *MockNode) String() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "String") - ret0, _ := ret[0].(string) - return ret0 -} - -// String indicates an expected call of String. -func (mr *MockNodeMockRecorder) String() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockNode)(nil).String)) -} - -// StringNode mocks base method. -func (m *MockNode) StringNode() *gotree.Node { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StringNode") - ret0, _ := ret[0].(*gotree.Node) - return ret0 -} - -// StringNode indicates an expected call of StringNode. -func (mr *MockNodeMockRecorder) StringNode() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StringNode", reflect.TypeOf((*MockNode)(nil).StringNode)) -} - -// Type mocks base method. -func (m *MockNode) Type() Type { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Type") - ret0, _ := ret[0].(Type) - return ret0 -} - -// Type indicates an expected call of Type. -func (mr *MockNodeMockRecorder) Type() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Type", reflect.TypeOf((*MockNode)(nil).Type)) -} diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index 8c36e099e4..29a458d203 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -5,14 +5,12 @@ package trie import ( "bytes" - "errors" "fmt" "testing" "github.com/ChainSafe/chaindb" "github.com/ChainSafe/gossamer/internal/trie/node" "github.com/ChainSafe/gossamer/lib/utils" - gomock "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -414,13 +412,16 @@ func TestLoadWithChildTriesFails(t *testing.T) { } sampleChildTrie := NewEmptyTrie() - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - mockNode := node.NewMockNode(mockCtrl) - mockNode.EXPECT().Encode(gomock.Any()).AnyTimes().Return(nil) - // TODO: Mock remaining methods + key := []byte{1, 2} + value := []byte{3, 4} + const dirty = true + const generation = 9 - sampleChildTrie.root = mockNode + mockNode := node.MockLeaf{ + Leaf: *node.NewLeaf(key, value, dirty, generation), + } + + sampleChildTrie.root = &mockNode keyToChild := []byte("test") err := trie.PutChild(keyToChild, sampleChildTrie) @@ -430,13 +431,14 @@ func TestLoadWithChildTriesFails(t *testing.T) { err = trie.Store(db) require.NoError(t, err) - mockNode.EXPECT().Encode(gomock.Any()).AnyTimes().Return(errors.New("some error")) - + mockNode.Fail = true res := NewEmptyTrie() err = res.Load(db, trie.MustHash()) - require.NoError(t, err) - fmt.Printf("expected:\n %s\n", trie.String()) - fmt.Printf("actual:\n %s\n", res.String()) + // require.NoError(t, err) + require.Error(t, err) + fmt.Println(err) + // fmt.Printf("expected:\n %s\n", trie.String()) + // fmt.Printf("actual:\n %s\n", res.String()) require.Equal(t, trie.MustHash(), res.MustHash()) } From 772b6c2ab50ef6523d3ff690fbd41e13db91046c Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Tue, 22 Feb 2022 16:09:52 +0530 Subject: [PATCH 03/22] temp --- lib/trie/database_test.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index 29a458d203..1dfc0f96a8 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -410,19 +410,17 @@ func TestLoadWithChildTriesFails(t *testing.T) { for _, test := range testCase { trie.Put(test.key, test.value) } - sampleChildTrie := NewEmptyTrie() key := []byte{1, 2} value := []byte{3, 4} const dirty = true - const generation = 9 + const generation = 0 mockNode := node.MockLeaf{ Leaf: *node.NewLeaf(key, value, dirty, generation), } - sampleChildTrie.root = &mockNode - + sampleChildTrie := NewTrie(&mockNode) keyToChild := []byte("test") err := trie.PutChild(keyToChild, sampleChildTrie) require.NoError(t, err) @@ -431,7 +429,7 @@ func TestLoadWithChildTriesFails(t *testing.T) { err = trie.Store(db) require.NoError(t, err) - mockNode.Fail = true + // mockNode.Fail = true res := NewEmptyTrie() err = res.Load(db, trie.MustHash()) // require.NoError(t, err) From 061b9bf692b3fe6515a7394633ddeb38bf27a7c0 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Thu, 3 Mar 2022 21:23:30 +0530 Subject: [PATCH 04/22] test TestGetStorageChildAndGetStorageFromChild with non-empty trie --- dot/state/storage_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dot/state/storage_test.go b/dot/state/storage_test.go index b455a66231..df7c80e43e 100644 --- a/dot/state/storage_test.go +++ b/dot/state/storage_test.go @@ -11,6 +11,7 @@ import ( "github.com/ChainSafe/gossamer/dot/state/pruner" "github.com/ChainSafe/gossamer/dot/telemetry" "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/internal/trie/node" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/genesis" runtime "github.com/ChainSafe/gossamer/lib/runtime/storage" @@ -182,7 +183,12 @@ func TestGetStorageChildAndGetStorageFromChild(t *testing.T) { blockState, err := NewBlockStateFromGenesis(db, genHeader, telemetryMock) require.NoError(t, err) - testChildTrie := trie.NewEmptyTrie() + key := []byte{1, 2} + value := []byte{3, 4} + const dirty = true + const generation = 0 + testChildTrie := trie.NewTrie(node.NewLeaf(key, value, dirty, generation)) + testChildTrie.Put([]byte("keyInsidechild"), []byte("voila")) err = genTrie.PutChild([]byte("keyToChild"), testChildTrie) @@ -213,7 +219,7 @@ func TestGetStorageChildAndGetStorageFromChild(t *testing.T) { _, err = storage.GetStorageChild(&rootHash, []byte("keyToChild")) require.NoError(t, err) - value, err := storage.GetStorageFromChild(&rootHash, []byte("keyToChild"), []byte("keyInsidechild")) + value, err = storage.GetStorageFromChild(&rootHash, []byte("keyToChild"), []byte("keyInsidechild")) require.NoError(t, err) require.Equal(t, []byte("voila"), value) From bf0f5eeda4e4cdfed76550dcea40df40e9e9eaab Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Thu, 3 Mar 2022 21:24:09 +0530 Subject: [PATCH 05/22] tackle the case when encoding and hash is same i.e., encoding is less than 32 bits --- lib/trie/database.go | 24 +++++++++++++++++++-- lib/trie/database_test.go | 44 ++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/lib/trie/database.go b/lib/trie/database.go index 886f437bba..0dc1588e97 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -51,7 +51,16 @@ func (t *Trie) store(db chaindb.Batch, n Node) error { return err } - err = db.Put(hash, encoding) + key := hash + if bytes.Equal(hash, encoding) { + hashArray, err := common.Blake2bHash(hash) + if err != nil { + return err + } + key = hashArray[:] + } + + err = db.Put(key, encoding) if err != nil { return err } @@ -184,7 +193,18 @@ func (t *Trie) load(db chaindb.Database, n Node) error { continue } - hash := child.GetHash() + encoding, hash, err := child.EncodeAndHash() + if err != nil { + return err + } + if bytes.Equal(hash, encoding) { + hashArray, err := common.Blake2bHash(hash) + if err != nil { + return err + } + hash = hashArray[:] + } + encodedNode, err := db.Get(hash) if err != nil { return fmt.Errorf("cannot find child node key 0x%x in database: %w", hash, err) diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index 1dfc0f96a8..d29c54e44e 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -67,6 +67,7 @@ func TestTrie_DatabaseStoreAndLoad(t *testing.T) { err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) + require.Equal(t, trie.String(), res.String()) for _, test := range testCase { val, err := GetFromDB(db, trie.MustHash(), test.key) @@ -395,10 +396,10 @@ func TestLoadWithChildTriesFails(t *testing.T) { // Run load and check that it fails testCase := []Test{ - {key: []byte{0x01, 0x35}, value: []byte("pen")}, - {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, - {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, - {key: []byte{0xf2}, value: []byte("feather")}, + // {key: []byte{0x01, 0x35}, value: []byte("pen")}, + // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, + // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, + // {key: []byte{0xf2}, value: []byte("feather")}, {key: []byte{0xf2, 0x3}, value: []byte("f")}, {key: []byte{0x09, 0xd3}, value: []byte("noot")}, {key: []byte{0x07}, value: []byte("ramen")}, @@ -416,27 +417,42 @@ func TestLoadWithChildTriesFails(t *testing.T) { const dirty = true const generation = 0 - mockNode := node.MockLeaf{ - Leaf: *node.NewLeaf(key, value, dirty, generation), - } + // mockNode := node.MockLeaf{ + // Leaf: *node.NewLeaf(key, value, dirty, generation), + // } + + // mockNode := *node.NewLeaf(key, value, dirty, generation) + + // sampleChildTrie := NewTrie(&mockNode) + + sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) - sampleChildTrie := NewTrie(&mockNode) + db := newTestDB(t) keyToChild := []byte("test") err := trie.PutChild(keyToChild, sampleChildTrie) require.NoError(t, err) - db := newTestDB(t) + // newChildTrie, err := trie.GetChild(keyToChild) + // require.NoError(t, err) + // fmt.Printf("old child trie\n%s\n", sampleChildTrie.String()) + + // fmt.Printf("new child trie\n%s\n", newChildTrie.String()) + err = trie.Store(db) require.NoError(t, err) // mockNode.Fail = true res := NewEmptyTrie() + err = res.Load(db, trie.MustHash()) - // require.NoError(t, err) - require.Error(t, err) - fmt.Println(err) - // fmt.Printf("expected:\n %s\n", trie.String()) - // fmt.Printf("actual:\n %s\n", res.String()) + require.NoError(t, err) + + // require.Error(t, err) + // fmt.Println(err) + // fmt.Printf("original:\n %s\n", trie.String()) + // fmt.Printf("loaded:\n %s\n", res.String()) + fmt.Printf("trie.childTries:\n %s\n", trie.childTries) + fmt.Printf("res.childTries:\n %s\n", res.childTries) require.Equal(t, trie.MustHash(), res.MustHash()) } From 8a5f18ca99e4ef48c1671571df3992a58bfae9a9 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 7 Mar 2022 14:20:47 +0530 Subject: [PATCH 06/22] so far things work, no error finding any nodes, child tries get populated Problems that still exists: - loaded childtries have empty bit in their encoding - child trie leaf is being replaced by a branch --- dot/state/storage_test.go | 3 -- lib/trie/child_storage.go | 20 ++++++++--- lib/trie/database.go | 71 ++++++++++++++++++++++++--------------- lib/trie/database_test.go | 21 ++++++------ 4 files changed, 70 insertions(+), 45 deletions(-) diff --git a/dot/state/storage_test.go b/dot/state/storage_test.go index fe4661098b..5f92a54d7c 100644 --- a/dot/state/storage_test.go +++ b/dot/state/storage_test.go @@ -228,9 +228,6 @@ func TestGetStorageChildAndGetStorageFromChild(t *testing.T) { "0", )) - // blockState, err := NewBlockStateFromGenesis(db, genHeader, telemetryMock) - // require.NoError(t, err) - key := []byte{1, 2} value := []byte{3, 4} const dirty = true diff --git a/lib/trie/child_storage.go b/lib/trie/child_storage.go index 41307ded29..6107efc287 100644 --- a/lib/trie/child_storage.go +++ b/lib/trie/child_storage.go @@ -16,11 +16,23 @@ var ChildStorageKeyPrefix = []byte(":child_storage:default:") var ErrChildTrieDoesNotExist = errors.New("child trie does not exist") // PutChild inserts a child trie into the main trie at key :child_storage:[keyToChild] +// A child trie is added as a node (K, V) in main trie. K is the child storage key +// associated to the child trie, and V is the Merkle value of its corresponding child trie. +// To get merkle value of a node, we get value of the node. It the value is shorter than +// 32 bits we use it as merkle value. Otherwise, we use it's blake2b hash as merkle value. func (t *Trie) PutChild(keyToChild []byte, child *Trie) error { - childHash, err := child.Hash() - if err != nil { - return err - } + fmt.Printf("inside PutChild\n%s\n", child.String()) + // testHash, err := child.Hash() + // if err != nil { + // return err + // } + _, hash, _ := child.root.EncodeAndHash() + // childHash := common.NewHash(hash) + childHash := common.BytesToHash(hash) + + // fmt.Printf("testHash %s\n", testHash) + fmt.Printf("childHash %s\n", childHash) + fmt.Printf("plain hash 0x%x\n", hash) key := append(ChildStorageKeyPrefix, keyToChild...) value := [32]byte(childHash) diff --git a/lib/trie/database.go b/lib/trie/database.go index 0dc1588e97..1fed4abded 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -26,6 +26,7 @@ var ( // Generally, this will only be used for the genesis trie. func (t *Trie) Store(db chaindb.Database) error { for _, v := range t.childTries { + fmt.Println("this one") if err := v.Store(db); err != nil { return fmt.Errorf("failed to store child trie with root hash=0x%x in the db: %w", v.root.GetHash(), err) } @@ -51,14 +52,15 @@ func (t *Trie) store(db chaindb.Batch, n Node) error { return err } - key := hash - if bytes.Equal(hash, encoding) { - hashArray, err := common.Blake2bHash(hash) - if err != nil { - return err - } - key = hashArray[:] - } + key := common.BytesToHash(hash).ToBytes() + fmt.Printf("hash in db 0x%x, less than 32: %t\n", key, len(hash) < 32) + // if bytes.Equal(hash, encoding) { + // hashArray, err := common.Blake2bHash(hash) + // if err != nil { + // return err + // } + // key = hashArray[:] + // } err = db.Put(key, encoding) if err != nil { @@ -162,6 +164,7 @@ func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { rootHashBytes := rootHash[:] + fmt.Printf("key in db get 0x%x\n", rootHashBytes) encodedNode, err := db.Get(rootHashBytes) if err != nil { return fmt.Errorf("failed to find root key %s: %w", rootHash, err) @@ -172,11 +175,15 @@ func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { if err != nil { return fmt.Errorf("cannot decode root node: %w", err) } + t.root = root t.root.SetDirty(false) t.root.SetEncodingAndHash(encodedNode, rootHashBytes) + fmt.Printf("what is being loaded:\n%s\n", t.String()) + + err = t.load(db, t.root) - return t.load(db, t.root) + return err } func (t *Trie) load(db chaindb.Database, n Node) error { @@ -193,19 +200,24 @@ func (t *Trie) load(db chaindb.Database, n Node) error { continue } - encoding, hash, err := child.EncodeAndHash() - if err != nil { - return err - } - if bytes.Equal(hash, encoding) { - hashArray, err := common.Blake2bHash(hash) - if err != nil { - return err - } - hash = hashArray[:] - } - - encodedNode, err := db.Get(hash) + hash := child.GetHash() + // _, hash, err := child.EncodeAndHash() + // if err != nil { + // return err + // } + fmt.Printf("printing the node %s\n", child.String()) + // fmt.Printf("child.GetHash(): 0x%x\n", hash) + + // if bytes.Equal(hash, encoding) { + // hashArray, err := common.Blake2bHash(hash) + // if err != nil { + // return err + // } + // hash = hashArray[:] + // } + fmt.Printf("key in db get 2 0x%x\n", hash) + + encodedNode, err := db.Get(common.BytesToHash(hash).ToBytes()) if err != nil { return fmt.Errorf("cannot find child node key 0x%x in database: %w", hash, err) } @@ -230,9 +242,13 @@ func (t *Trie) load(db chaindb.Database, n Node) error { childTrie := NewEmptyTrie() value := t.Get(key) // TODO: Tests this error - err := childTrie.Load(db, common.NewHash(value)) + // tempHash, _ := common.HexToHash("0xca95d093b5303f296c2fff7fc207eebed6a1b93e161d458f0c9861457f62afee") + rootHash := common.BytesToHash(value) + // rootHash, _ := common.Blake2bHash(value) + fmt.Printf("rootHash loading: %s\n", rootHash) + err := childTrie.Load(db, rootHash) if err != nil { - return fmt.Errorf("failed to load child trie with root hash=0x%x: %w", value, err) + return fmt.Errorf("failed to load child trie with root hash=%s: %w", rootHash, err) } // TODO: Test this error @@ -356,7 +372,7 @@ func getFromDB(db chaindb.Database, n Node, key []byte) ( } childHash := childWithHashOnly.GetHash() - encodedChild, err := db.Get(childHash) + encodedChild, err := db.Get(common.BytesToHash(childHash).ToBytes()) if err != nil { return nil, fmt.Errorf( "cannot find child with hash 0x%x in database: %w", @@ -399,8 +415,8 @@ func (t *Trie) writeDirty(db chaindb.Batch, n Node) error { n.GetHash(), err) } - if n == t.root { - // hash root node even if its encoding is under 32 bytes + // hash root node even if its encoding is under 32 bytes + if n == t.root && len(encoding) < 32 { encodingDigest, err := common.Blake2bHash(encoding) if err != nil { return fmt.Errorf("cannot hash root node encoding: %w", err) @@ -409,6 +425,7 @@ func (t *Trie) writeDirty(db chaindb.Batch, n Node) error { hash = encodingDigest[:] } + fmt.Printf("wonder if here, hash 0x%x\n", hash) err = db.Put(hash, encoding) if err != nil { return fmt.Errorf( diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index d29c54e44e..b85af9ddfe 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -10,6 +10,7 @@ import ( "github.com/ChainSafe/chaindb" "github.com/ChainSafe/gossamer/internal/trie/node" + "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/utils" "github.com/stretchr/testify/require" ) @@ -67,7 +68,9 @@ func TestTrie_DatabaseStoreAndLoad(t *testing.T) { err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) - require.Equal(t, trie.String(), res.String()) + // require.Equal(t, trie.String(), res.String()) + fmt.Printf("original\n%s\n", trie.String()) + fmt.Printf("new\n%s\n", res.String()) for _, test := range testCase { val, err := GetFromDB(db, trie.MustHash(), test.key) @@ -428,30 +431,26 @@ func TestLoadWithChildTriesFails(t *testing.T) { sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) db := newTestDB(t) - keyToChild := []byte("test") + keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") err := trie.PutChild(keyToChild, sampleChildTrie) require.NoError(t, err) - // newChildTrie, err := trie.GetChild(keyToChild) - // require.NoError(t, err) - // fmt.Printf("old child trie\n%s\n", sampleChildTrie.String()) - - // fmt.Printf("new child trie\n%s\n", newChildTrie.String()) - err = trie.Store(db) require.NoError(t, err) + fmt.Printf("original:\n %s\n", trie.String()) + fmt.Printf("trie.childTries:\n %s\n", trie.childTries) // mockNode.Fail = true res := NewEmptyTrie() - err = res.Load(db, trie.MustHash()) + rootHash := common.BytesToHash(trie.root.GetHash()) + err = res.Load(db, rootHash) require.NoError(t, err) // require.Error(t, err) // fmt.Println(err) // fmt.Printf("original:\n %s\n", trie.String()) - // fmt.Printf("loaded:\n %s\n", res.String()) - fmt.Printf("trie.childTries:\n %s\n", trie.childTries) + fmt.Printf("loaded:\n %s\n", res.String()) fmt.Printf("res.childTries:\n %s\n", res.childTries) require.Equal(t, trie.MustHash(), res.MustHash()) From e4f434a4d829226f09ef0d72356aeea91cb40ce6 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 7 Mar 2022 15:38:32 +0530 Subject: [PATCH 07/22] child tries don't have empty bits in their encoding --- lib/trie/database.go | 22 ++++++--- lib/trie/database_test.go | 100 +++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 57 deletions(-) diff --git a/lib/trie/database.go b/lib/trie/database.go index 1fed4abded..e7c2413f6a 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -52,8 +52,8 @@ func (t *Trie) store(db chaindb.Batch, n Node) error { return err } - key := common.BytesToHash(hash).ToBytes() - fmt.Printf("hash in db 0x%x, less than 32: %t\n", key, len(hash) < 32) + // key := common.BytesToHash(hash).ToBytes() + // fmt.Printf("hash in db 0x%x, less than 32: %t\n", key, len(hash) < 32) // if bytes.Equal(hash, encoding) { // hashArray, err := common.Blake2bHash(hash) // if err != nil { @@ -62,7 +62,7 @@ func (t *Trie) store(db chaindb.Batch, n Node) error { // key = hashArray[:] // } - err = db.Put(key, encoding) + err = db.Put(hash, encoding) if err != nil { return err } @@ -161,9 +161,19 @@ func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { t.root = nil return nil } + fmt.Println("rootHash", rootHash.ToBytes()) - rootHashBytes := rootHash[:] + // withoutEmptyBits := []byte{} + counter := 0 + for _, v := range rootHash.ToBytes() { + if v != 0 { + break + } + counter++ + } + rootHashBytes := rootHash[counter:] + // rootHashBytes := withoutEmptyBits fmt.Printf("key in db get 0x%x\n", rootHashBytes) encodedNode, err := db.Get(rootHashBytes) if err != nil { @@ -217,7 +227,7 @@ func (t *Trie) load(db chaindb.Database, n Node) error { // } fmt.Printf("key in db get 2 0x%x\n", hash) - encodedNode, err := db.Get(common.BytesToHash(hash).ToBytes()) + encodedNode, err := db.Get(hash) if err != nil { return fmt.Errorf("cannot find child node key 0x%x in database: %w", hash, err) } @@ -372,7 +382,7 @@ func getFromDB(db chaindb.Database, n Node, key []byte) ( } childHash := childWithHashOnly.GetHash() - encodedChild, err := db.Get(common.BytesToHash(childHash).ToBytes()) + encodedChild, err := db.Get(childHash) if err != nil { return nil, fmt.Errorf( "cannot find child with hash 0x%x in database: %w", diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index b85af9ddfe..fa604752d6 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -9,8 +9,6 @@ import ( "testing" "github.com/ChainSafe/chaindb" - "github.com/ChainSafe/gossamer/internal/trie/node" - "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/utils" "github.com/stretchr/testify/require" ) @@ -393,65 +391,65 @@ func TestTrie_GetFromDB(t *testing.T) { } } -func TestLoadWithChildTriesFails(t *testing.T) { - // Use a fake node implementation in which Encode always fails - // Make that root of one of the childtries - // Run load and check that it fails - - testCase := []Test{ - // {key: []byte{0x01, 0x35}, value: []byte("pen")}, - // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, - // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, - // {key: []byte{0xf2}, value: []byte("feather")}, - {key: []byte{0xf2, 0x3}, value: []byte("f")}, - {key: []byte{0x09, 0xd3}, value: []byte("noot")}, - {key: []byte{0x07}, value: []byte("ramen")}, - {key: []byte{0}, value: nil}, - } +// func TestLoadWithChildTriesFails(t *testing.T) { +// // Use a fake node implementation in which Encode always fails +// // Make that root of one of the childtries +// // Run load and check that it fails - trie := NewEmptyTrie() +// testCase := []Test{ +// // {key: []byte{0x01, 0x35}, value: []byte("pen")}, +// // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, +// // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, +// // {key: []byte{0xf2}, value: []byte("feather")}, +// {key: []byte{0xf2, 0x3}, value: []byte("f")}, +// {key: []byte{0x09, 0xd3}, value: []byte("noot")}, +// {key: []byte{0x07}, value: []byte("ramen")}, +// {key: []byte{0}, value: nil}, +// } - for _, test := range testCase { - trie.Put(test.key, test.value) - } +// trie := NewEmptyTrie() - key := []byte{1, 2} - value := []byte{3, 4} - const dirty = true - const generation = 0 +// for _, test := range testCase { +// trie.Put(test.key, test.value) +// } - // mockNode := node.MockLeaf{ - // Leaf: *node.NewLeaf(key, value, dirty, generation), - // } +// key := []byte{1, 2} +// value := []byte{3, 4} +// const dirty = true +// const generation = 0 - // mockNode := *node.NewLeaf(key, value, dirty, generation) +// // mockNode := node.MockLeaf{ +// // Leaf: *node.NewLeaf(key, value, dirty, generation), +// // } - // sampleChildTrie := NewTrie(&mockNode) +// // mockNode := *node.NewLeaf(key, value, dirty, generation) - sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) +// // sampleChildTrie := NewTrie(&mockNode) - db := newTestDB(t) - keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") - err := trie.PutChild(keyToChild, sampleChildTrie) - require.NoError(t, err) +// sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) - err = trie.Store(db) - require.NoError(t, err) - fmt.Printf("original:\n %s\n", trie.String()) - fmt.Printf("trie.childTries:\n %s\n", trie.childTries) +// db := newTestDB(t) +// keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") +// err := trie.PutChild(keyToChild, sampleChildTrie) +// require.NoError(t, err) - // mockNode.Fail = true - res := NewEmptyTrie() +// err = trie.Store(db) +// require.NoError(t, err) +// fmt.Printf("original:\n %s\n", trie.String()) +// fmt.Printf("trie.childTries:\n %s\n", trie.childTries) - rootHash := common.BytesToHash(trie.root.GetHash()) - err = res.Load(db, rootHash) - require.NoError(t, err) +// // mockNode.Fail = true +// res := NewEmptyTrie() - // require.Error(t, err) - // fmt.Println(err) - // fmt.Printf("original:\n %s\n", trie.String()) - fmt.Printf("loaded:\n %s\n", res.String()) - fmt.Printf("res.childTries:\n %s\n", res.childTries) +// rootHash := common.BytesToHash(trie.root.GetHash()) +// err = res.Load(db, rootHash) +// require.NoError(t, err) - require.Equal(t, trie.MustHash(), res.MustHash()) -} +// // require.Error(t, err) +// // fmt.Println(err) +// // fmt.Printf("original:\n %s\n", trie.String()) +// fmt.Printf("loaded:\n %s\n", res.String()) +// fmt.Printf("res.childTries:\n %s\n", res.childTries) + +// require.Equal(t, trie.MustHash(), res.MustHash()) +// } From 13f3e59f411a4c5df951d428913c97a23c3558e3 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 7 Mar 2022 15:59:00 +0530 Subject: [PATCH 08/22] cleaning up --- lib/trie/child_storage.go | 21 +++------ lib/trie/database.go | 41 ++--------------- lib/trie/database_test.go | 96 +++++++++++++++++++-------------------- 3 files changed, 55 insertions(+), 103 deletions(-) diff --git a/lib/trie/child_storage.go b/lib/trie/child_storage.go index 6107efc287..db6ab5ac2e 100644 --- a/lib/trie/child_storage.go +++ b/lib/trie/child_storage.go @@ -21,24 +21,15 @@ var ErrChildTrieDoesNotExist = errors.New("child trie does not exist") // To get merkle value of a node, we get value of the node. It the value is shorter than // 32 bits we use it as merkle value. Otherwise, we use it's blake2b hash as merkle value. func (t *Trie) PutChild(keyToChild []byte, child *Trie) error { - fmt.Printf("inside PutChild\n%s\n", child.String()) - // testHash, err := child.Hash() - // if err != nil { - // return err - // } - _, hash, _ := child.root.EncodeAndHash() - // childHash := common.NewHash(hash) - childHash := common.BytesToHash(hash) - - // fmt.Printf("testHash %s\n", testHash) - fmt.Printf("childHash %s\n", childHash) - fmt.Printf("plain hash 0x%x\n", hash) + _, hash, err := child.root.EncodeAndHash() + if err != nil { + return err + } key := append(ChildStorageKeyPrefix, keyToChild...) - value := [32]byte(childHash) - t.Put(key, value[:]) - t.childTries[childHash] = child + t.Put(key, hash) + t.childTries[common.BytesToHash(hash)] = child return nil } diff --git a/lib/trie/database.go b/lib/trie/database.go index e7c2413f6a..53fd10dc0d 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -26,7 +26,6 @@ var ( // Generally, this will only be used for the genesis trie. func (t *Trie) Store(db chaindb.Database) error { for _, v := range t.childTries { - fmt.Println("this one") if err := v.Store(db); err != nil { return fmt.Errorf("failed to store child trie with root hash=0x%x in the db: %w", v.root.GetHash(), err) } @@ -52,16 +51,6 @@ func (t *Trie) store(db chaindb.Batch, n Node) error { return err } - // key := common.BytesToHash(hash).ToBytes() - // fmt.Printf("hash in db 0x%x, less than 32: %t\n", key, len(hash) < 32) - // if bytes.Equal(hash, encoding) { - // hashArray, err := common.Blake2bHash(hash) - // if err != nil { - // return err - // } - // key = hashArray[:] - // } - err = db.Put(hash, encoding) if err != nil { return err @@ -161,9 +150,7 @@ func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { t.root = nil return nil } - fmt.Println("rootHash", rootHash.ToBytes()) - // withoutEmptyBits := []byte{} counter := 0 for _, v := range rootHash.ToBytes() { if v != 0 { @@ -172,9 +159,9 @@ func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { counter++ } + // remove initial 0 bits rootHashBytes := rootHash[counter:] - // rootHashBytes := withoutEmptyBits - fmt.Printf("key in db get 0x%x\n", rootHashBytes) + encodedNode, err := db.Get(rootHashBytes) if err != nil { return fmt.Errorf("failed to find root key %s: %w", rootHash, err) @@ -189,11 +176,8 @@ func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { t.root = root t.root.SetDirty(false) t.root.SetEncodingAndHash(encodedNode, rootHashBytes) - fmt.Printf("what is being loaded:\n%s\n", t.String()) - - err = t.load(db, t.root) - return err + return t.load(db, t.root) } func (t *Trie) load(db chaindb.Database, n Node) error { @@ -211,21 +195,6 @@ func (t *Trie) load(db chaindb.Database, n Node) error { } hash := child.GetHash() - // _, hash, err := child.EncodeAndHash() - // if err != nil { - // return err - // } - fmt.Printf("printing the node %s\n", child.String()) - // fmt.Printf("child.GetHash(): 0x%x\n", hash) - - // if bytes.Equal(hash, encoding) { - // hashArray, err := common.Blake2bHash(hash) - // if err != nil { - // return err - // } - // hash = hashArray[:] - // } - fmt.Printf("key in db get 2 0x%x\n", hash) encodedNode, err := db.Get(hash) if err != nil { @@ -252,10 +221,7 @@ func (t *Trie) load(db chaindb.Database, n Node) error { childTrie := NewEmptyTrie() value := t.Get(key) // TODO: Tests this error - // tempHash, _ := common.HexToHash("0xca95d093b5303f296c2fff7fc207eebed6a1b93e161d458f0c9861457f62afee") rootHash := common.BytesToHash(value) - // rootHash, _ := common.Blake2bHash(value) - fmt.Printf("rootHash loading: %s\n", rootHash) err := childTrie.Load(db, rootHash) if err != nil { return fmt.Errorf("failed to load child trie with root hash=%s: %w", rootHash, err) @@ -435,7 +401,6 @@ func (t *Trie) writeDirty(db chaindb.Batch, n Node) error { hash = encodingDigest[:] } - fmt.Printf("wonder if here, hash 0x%x\n", hash) err = db.Put(hash, encoding) if err != nil { return fmt.Errorf( diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index fa604752d6..160370b962 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -9,6 +9,8 @@ import ( "testing" "github.com/ChainSafe/chaindb" + "github.com/ChainSafe/gossamer/internal/trie/node" + "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/utils" "github.com/stretchr/testify/require" ) @@ -391,65 +393,59 @@ func TestTrie_GetFromDB(t *testing.T) { } } -// func TestLoadWithChildTriesFails(t *testing.T) { -// // Use a fake node implementation in which Encode always fails -// // Make that root of one of the childtries -// // Run load and check that it fails - -// testCase := []Test{ -// // {key: []byte{0x01, 0x35}, value: []byte("pen")}, -// // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, -// // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, -// // {key: []byte{0xf2}, value: []byte("feather")}, -// {key: []byte{0xf2, 0x3}, value: []byte("f")}, -// {key: []byte{0x09, 0xd3}, value: []byte("noot")}, -// {key: []byte{0x07}, value: []byte("ramen")}, -// {key: []byte{0}, value: nil}, -// } - -// trie := NewEmptyTrie() +func TestLoadWithChildTriesFails(t *testing.T) { + // Use a fake node implementation in which Encode always fails + // Make that root of one of the childtries + // Run load and check that it fails + + testCase := []Test{ + // {key: []byte{0x01, 0x35}, value: []byte("pen")}, + // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, + // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, + // {key: []byte{0xf2}, value: []byte("feather")}, + {key: []byte{0xf2, 0x3}, value: []byte("f")}, + {key: []byte{0x09, 0xd3}, value: []byte("noot")}, + {key: []byte{0x07}, value: []byte("ramen")}, + {key: []byte{0}, value: nil}, + } -// for _, test := range testCase { -// trie.Put(test.key, test.value) -// } + trie := NewEmptyTrie() -// key := []byte{1, 2} -// value := []byte{3, 4} -// const dirty = true -// const generation = 0 + for _, test := range testCase { + trie.Put(test.key, test.value) + } -// // mockNode := node.MockLeaf{ -// // Leaf: *node.NewLeaf(key, value, dirty, generation), -// // } + key := []byte{1, 2} + value := []byte{3, 4} + const dirty = true + const generation = 0 -// // mockNode := *node.NewLeaf(key, value, dirty, generation) + // mockNode := node.MockLeaf{ + // Leaf: *node.NewLeaf(key, value, dirty, generation), + // } -// // sampleChildTrie := NewTrie(&mockNode) + // mockNode := *node.NewLeaf(key, value, dirty, generation) -// sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) + // sampleChildTrie := NewTrie(&mockNode) -// db := newTestDB(t) -// keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") -// err := trie.PutChild(keyToChild, sampleChildTrie) -// require.NoError(t, err) + sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) -// err = trie.Store(db) -// require.NoError(t, err) -// fmt.Printf("original:\n %s\n", trie.String()) -// fmt.Printf("trie.childTries:\n %s\n", trie.childTries) + db := newTestDB(t) + keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") + err := trie.PutChild(keyToChild, sampleChildTrie) + require.NoError(t, err) -// // mockNode.Fail = true -// res := NewEmptyTrie() + err = trie.Store(db) + require.NoError(t, err) -// rootHash := common.BytesToHash(trie.root.GetHash()) -// err = res.Load(db, rootHash) -// require.NoError(t, err) + // mockNode.Fail = true + res := NewEmptyTrie() -// // require.Error(t, err) -// // fmt.Println(err) -// // fmt.Printf("original:\n %s\n", trie.String()) -// fmt.Printf("loaded:\n %s\n", res.String()) -// fmt.Printf("res.childTries:\n %s\n", res.childTries) + rootHash := common.BytesToHash(trie.root.GetHash()) + err = res.Load(db, rootHash) + require.NoError(t, err) -// require.Equal(t, trie.MustHash(), res.MustHash()) -// } + require.Equal(t, trie.String(), res.String()) + require.Equal(t, trie.childTries, res.childTries) + require.Equal(t, trie.MustHash(), res.MustHash()) +} From d6d5a879d912f6a1e770bc2fa2a251bcb3270706 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 7 Mar 2022 16:23:27 +0530 Subject: [PATCH 09/22] more clean up --- lib/trie/database_test.go | 94 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index 160370b962..eb78513ea8 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -9,8 +9,6 @@ import ( "testing" "github.com/ChainSafe/chaindb" - "github.com/ChainSafe/gossamer/internal/trie/node" - "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/utils" "github.com/stretchr/testify/require" ) @@ -68,9 +66,7 @@ func TestTrie_DatabaseStoreAndLoad(t *testing.T) { err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) - // require.Equal(t, trie.String(), res.String()) - fmt.Printf("original\n%s\n", trie.String()) - fmt.Printf("new\n%s\n", res.String()) + require.Equal(t, trie.String(), res.String()) for _, test := range testCase { val, err := GetFromDB(db, trie.MustHash(), test.key) @@ -393,59 +389,59 @@ func TestTrie_GetFromDB(t *testing.T) { } } -func TestLoadWithChildTriesFails(t *testing.T) { - // Use a fake node implementation in which Encode always fails - // Make that root of one of the childtries - // Run load and check that it fails - - testCase := []Test{ - // {key: []byte{0x01, 0x35}, value: []byte("pen")}, - // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, - // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, - // {key: []byte{0xf2}, value: []byte("feather")}, - {key: []byte{0xf2, 0x3}, value: []byte("f")}, - {key: []byte{0x09, 0xd3}, value: []byte("noot")}, - {key: []byte{0x07}, value: []byte("ramen")}, - {key: []byte{0}, value: nil}, - } +// func TestLoadWithChildTriesFails(t *testing.T) { +// // Use a fake node implementation in which Encode always fails +// // Make that root of one of the childtries +// // Run load and check that it fails - trie := NewEmptyTrie() +// testCase := []Test{ +// // {key: []byte{0x01, 0x35}, value: []byte("pen")}, +// // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, +// // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, +// // {key: []byte{0xf2}, value: []byte("feather")}, +// {key: []byte{0xf2, 0x3}, value: []byte("f")}, +// {key: []byte{0x09, 0xd3}, value: []byte("noot")}, +// {key: []byte{0x07}, value: []byte("ramen")}, +// {key: []byte{0}, value: nil}, +// } - for _, test := range testCase { - trie.Put(test.key, test.value) - } +// trie := NewEmptyTrie() - key := []byte{1, 2} - value := []byte{3, 4} - const dirty = true - const generation = 0 +// for _, test := range testCase { +// trie.Put(test.key, test.value) +// } - // mockNode := node.MockLeaf{ - // Leaf: *node.NewLeaf(key, value, dirty, generation), - // } +// key := []byte{1, 2} +// value := []byte{3, 4} +// const dirty = true +// const generation = 0 - // mockNode := *node.NewLeaf(key, value, dirty, generation) +// // mockNode := node.MockLeaf{ +// // Leaf: *node.NewLeaf(key, value, dirty, generation), +// // } - // sampleChildTrie := NewTrie(&mockNode) +// // mockNode := *node.NewLeaf(key, value, dirty, generation) - sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) +// // sampleChildTrie := NewTrie(&mockNode) - db := newTestDB(t) - keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") - err := trie.PutChild(keyToChild, sampleChildTrie) - require.NoError(t, err) +// sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) - err = trie.Store(db) - require.NoError(t, err) +// db := newTestDB(t) +// keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") +// err := trie.PutChild(keyToChild, sampleChildTrie) +// require.NoError(t, err) - // mockNode.Fail = true - res := NewEmptyTrie() +// err = trie.Store(db) +// require.NoError(t, err) - rootHash := common.BytesToHash(trie.root.GetHash()) - err = res.Load(db, rootHash) - require.NoError(t, err) +// // mockNode.Fail = true +// res := NewEmptyTrie() - require.Equal(t, trie.String(), res.String()) - require.Equal(t, trie.childTries, res.childTries) - require.Equal(t, trie.MustHash(), res.MustHash()) -} +// rootHash := common.BytesToHash(trie.root.GetHash()) +// err = res.Load(db, rootHash) +// require.NoError(t, err) + +// require.Equal(t, trie.String(), res.String()) +// require.Equal(t, trie.childTries, res.childTries) +// require.Equal(t, trie.MustHash(), res.MustHash()) +// } From 4eed7673e7ccdeee3db2aa83e553fb9d65d6d967 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 7 Mar 2022 16:32:29 +0530 Subject: [PATCH 10/22] accept []byte key in trie.Load instead of common.Hash --- dot/state/base_test.go | 2 +- dot/state/storage.go | 2 +- lib/trie/database.go | 29 ++++++++++++++--------------- lib/trie/database_test.go | 10 +++++----- lib/trie/proof.go | 2 +- lib/trie/trie_endtoend_test.go | 3 +-- 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/dot/state/base_test.go b/dot/state/base_test.go index a217d63887..bde319ff25 100644 --- a/dot/state/base_test.go +++ b/dot/state/base_test.go @@ -35,7 +35,7 @@ func TestTrie_StoreAndLoadFromDB(t *testing.T) { expected := tt.MustHash() tt = trie.NewEmptyTrie() - err = tt.Load(db, encroot) + err = tt.Load(db, encroot.ToBytes()) require.NoError(t, err) require.Equal(t, expected, tt.MustHash()) } diff --git a/dot/state/storage.go b/dot/state/storage.go index 4571c9279b..3b02676f30 100644 --- a/dot/state/storage.go +++ b/dot/state/storage.go @@ -142,7 +142,7 @@ func (s *StorageState) TrieState(root *common.Hash) (*rtstorage.TrieState, error // LoadFromDB loads an encoded trie from the DB where the key is `root` func (s *StorageState) LoadFromDB(root common.Hash) (*trie.Trie, error) { t := trie.NewEmptyTrie() - err := t.Load(s.db, root) + err := t.Load(s.db, root.ToBytes()) if err != nil { return nil, err } diff --git a/lib/trie/database.go b/lib/trie/database.go index 53fd10dc0d..c0ca62b938 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -145,26 +145,26 @@ func (t *Trie) loadProof(proofHashToNode map[string]Node, n Node) { // Load reconstructs the trie from the database from the given root hash. // It is used when restarting the node to load the current state trie. -func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { - if rootHash == EmptyHash { +func (t *Trie) Load(db chaindb.Database, rootHashBytes []byte) error { + if len(rootHashBytes) == 0 { t.root = nil return nil } - counter := 0 - for _, v := range rootHash.ToBytes() { - if v != 0 { - break - } - counter++ - } + // counter := 0 + // for _, v := range rootHash.ToBytes() { + // if v != 0 { + // break + // } + // counter++ + // } - // remove initial 0 bits - rootHashBytes := rootHash[counter:] + // // remove initial 0 bits + // rootHashBytes := rootHash[counter:] encodedNode, err := db.Get(rootHashBytes) if err != nil { - return fmt.Errorf("failed to find root key %s: %w", rootHash, err) + return fmt.Errorf("failed to find root key 0x%x: %w", rootHashBytes, err) } reader := bytes.NewReader(encodedNode) @@ -221,10 +221,9 @@ func (t *Trie) load(db chaindb.Database, n Node) error { childTrie := NewEmptyTrie() value := t.Get(key) // TODO: Tests this error - rootHash := common.BytesToHash(value) - err := childTrie.Load(db, rootHash) + err := childTrie.Load(db, value) if err != nil { - return fmt.Errorf("failed to load child trie with root hash=%s: %w", rootHash, err) + return fmt.Errorf("failed to load child trie with root hash=0x%x: %w", value, err) } // TODO: Test this error diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index eb78513ea8..a51d65b8e4 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -63,7 +63,7 @@ func TestTrie_DatabaseStoreAndLoad(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash()) + err = res.Load(db, trie.MustHash().ToBytes()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) require.Equal(t, trie.String(), res.String()) @@ -135,7 +135,7 @@ func TestTrie_WriteDirty_Put(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash()) + err = res.Load(db, trie.MustHash().ToBytes()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) @@ -205,7 +205,7 @@ func TestTrie_WriteDirty_PutReplace(t *testing.T) { } res := NewEmptyTrie() - err := res.Load(db, trie.MustHash()) + err := res.Load(db, trie.MustHash().ToBytes()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) @@ -265,7 +265,7 @@ func TestTrie_WriteDirty_Delete(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash()) + err = res.Load(db, trie.MustHash().ToBytes()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) @@ -330,7 +330,7 @@ func TestTrie_WriteDirty_ClearPrefix(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash()) + err = res.Load(db, trie.MustHash().ToBytes()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) diff --git a/lib/trie/proof.go b/lib/trie/proof.go index 4bd2b0c066..a3b2aad31f 100644 --- a/lib/trie/proof.go +++ b/lib/trie/proof.go @@ -37,7 +37,7 @@ func GenerateProof(root []byte, keys [][]byte, db chaindb.Database) ([][]byte, e trackedProofs := make(map[string][]byte) proofTrie := NewEmptyTrie() - if err := proofTrie.Load(db, common.BytesToHash(root)); err != nil { + if err := proofTrie.Load(db, root); err != nil { return nil, err } diff --git a/lib/trie/trie_endtoend_test.go b/lib/trie/trie_endtoend_test.go index 7baf467c7a..8327b75f2c 100644 --- a/lib/trie/trie_endtoend_test.go +++ b/lib/trie/trie_endtoend_test.go @@ -22,7 +22,6 @@ import ( "github.com/ChainSafe/gossamer/internal/trie/codec" "github.com/ChainSafe/gossamer/internal/trie/node" - "github.com/ChainSafe/gossamer/lib/common" ) const ( @@ -397,7 +396,7 @@ func TestTrieDiff(t *testing.T) { } dbTrie := NewEmptyTrie() - err = dbTrie.Load(storageDB, common.BytesToHash(newTrie.root.GetHash())) + err = dbTrie.Load(storageDB, newTrie.root.GetHash()) require.NoError(t, err) } From c24a76d3191ed562561c338d7ed1c10744d979f6 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 7 Mar 2022 16:34:12 +0530 Subject: [PATCH 11/22] uncomment the test TestLoadWithChildTriesFails --- lib/trie/database_test.go | 88 +++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index a51d65b8e4..877035c0a6 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/ChainSafe/chaindb" + "github.com/ChainSafe/gossamer/internal/trie/node" "github.com/ChainSafe/gossamer/lib/utils" "github.com/stretchr/testify/require" ) @@ -389,59 +390,58 @@ func TestTrie_GetFromDB(t *testing.T) { } } -// func TestLoadWithChildTriesFails(t *testing.T) { -// // Use a fake node implementation in which Encode always fails -// // Make that root of one of the childtries -// // Run load and check that it fails - -// testCase := []Test{ -// // {key: []byte{0x01, 0x35}, value: []byte("pen")}, -// // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, -// // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, -// // {key: []byte{0xf2}, value: []byte("feather")}, -// {key: []byte{0xf2, 0x3}, value: []byte("f")}, -// {key: []byte{0x09, 0xd3}, value: []byte("noot")}, -// {key: []byte{0x07}, value: []byte("ramen")}, -// {key: []byte{0}, value: nil}, -// } +func TestLoadWithChildTriesFails(t *testing.T) { + // Use a fake node implementation in which Encode always fails + // Make that root of one of the childtries + // Run load and check that it fails + + testCase := []Test{ + // {key: []byte{0x01, 0x35}, value: []byte("pen")}, + // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, + // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, + // {key: []byte{0xf2}, value: []byte("feather")}, + {key: []byte{0xf2, 0x3}, value: []byte("f")}, + {key: []byte{0x09, 0xd3}, value: []byte("noot")}, + {key: []byte{0x07}, value: []byte("ramen")}, + {key: []byte{0}, value: nil}, + } -// trie := NewEmptyTrie() + trie := NewEmptyTrie() -// for _, test := range testCase { -// trie.Put(test.key, test.value) -// } + for _, test := range testCase { + trie.Put(test.key, test.value) + } -// key := []byte{1, 2} -// value := []byte{3, 4} -// const dirty = true -// const generation = 0 + key := []byte{1, 2} + value := []byte{3, 4} + const dirty = true + const generation = 0 -// // mockNode := node.MockLeaf{ -// // Leaf: *node.NewLeaf(key, value, dirty, generation), -// // } + // mockNode := node.MockLeaf{ + // Leaf: *node.NewLeaf(key, value, dirty, generation), + // } -// // mockNode := *node.NewLeaf(key, value, dirty, generation) + // mockNode := *node.NewLeaf(key, value, dirty, generation) -// // sampleChildTrie := NewTrie(&mockNode) + // sampleChildTrie := NewTrie(&mockNode) -// sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) + sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) -// db := newTestDB(t) -// keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") -// err := trie.PutChild(keyToChild, sampleChildTrie) -// require.NoError(t, err) + db := newTestDB(t) + keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") + err := trie.PutChild(keyToChild, sampleChildTrie) + require.NoError(t, err) -// err = trie.Store(db) -// require.NoError(t, err) + err = trie.Store(db) + require.NoError(t, err) -// // mockNode.Fail = true -// res := NewEmptyTrie() + // mockNode.Fail = true + res := NewEmptyTrie() -// rootHash := common.BytesToHash(trie.root.GetHash()) -// err = res.Load(db, rootHash) -// require.NoError(t, err) + err = res.Load(db, trie.root.GetHash()) + require.NoError(t, err) -// require.Equal(t, trie.String(), res.String()) -// require.Equal(t, trie.childTries, res.childTries) -// require.Equal(t, trie.MustHash(), res.MustHash()) -// } + require.Equal(t, trie.String(), res.String()) + require.Equal(t, trie.childTries, res.childTries) + require.Equal(t, trie.MustHash(), res.MustHash()) +} From d6f63bd027868062e28cb2ffc13be28073a0d8cd Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 7 Mar 2022 21:59:19 +0530 Subject: [PATCH 12/22] more clean up --- lib/trie/database.go | 11 ---------- lib/trie/database_test.go | 45 ++++++++++++++++++--------------------- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/lib/trie/database.go b/lib/trie/database.go index c0ca62b938..67e163d6cc 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -151,17 +151,6 @@ func (t *Trie) Load(db chaindb.Database, rootHashBytes []byte) error { return nil } - // counter := 0 - // for _, v := range rootHash.ToBytes() { - // if v != 0 { - // break - // } - // counter++ - // } - - // // remove initial 0 bits - // rootHashBytes := rootHash[counter:] - encodedNode, err := db.Get(rootHashBytes) if err != nil { return fmt.Errorf("failed to find root key 0x%x: %w", rootHashBytes, err) diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index 877035c0a6..a722a4ecc3 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -390,16 +390,12 @@ func TestTrie_GetFromDB(t *testing.T) { } } -func TestLoadWithChildTriesFails(t *testing.T) { +func TestStoreAndLoadWithChildTries(t *testing.T) { // Use a fake node implementation in which Encode always fails // Make that root of one of the childtries // Run load and check that it fails testCase := []Test{ - // {key: []byte{0x01, 0x35}, value: []byte("pen")}, - // {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, - // {key: []byte{0x01, 0x35, 0x7}, value: []byte("g")}, - // {key: []byte{0xf2}, value: []byte("feather")}, {key: []byte{0xf2, 0x3}, value: []byte("f")}, {key: []byte{0x09, 0xd3}, value: []byte("noot")}, {key: []byte{0x07}, value: []byte("ramen")}, @@ -417,31 +413,32 @@ func TestLoadWithChildTriesFails(t *testing.T) { const dirty = true const generation = 0 - // mockNode := node.MockLeaf{ - // Leaf: *node.NewLeaf(key, value, dirty, generation), - // } + t.Run("happy path, tries being loaded are same as trie being read", func(t *testing.T) { - // mockNode := *node.NewLeaf(key, value, dirty, generation) + // hash could be different for keys smaller than 32 and larger than 32 bits. + // thus, testing with keys of different sizes. + keysToTest := [][]byte{ + []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs."), + } - // sampleChildTrie := NewTrie(&mockNode) + db := newTestDB(t) + for _, keyToChild := range keysToTest { + sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) - sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) + err := trie.PutChild(keyToChild, sampleChildTrie) + require.NoError(t, err) - db := newTestDB(t) - keyToChild := []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs, and how to completely and clearly express your ideas.") - err := trie.PutChild(keyToChild, sampleChildTrie) - require.NoError(t, err) + err = trie.Store(db) + require.NoError(t, err) - err = trie.Store(db) - require.NoError(t, err) + res := NewEmptyTrie() - // mockNode.Fail = true - res := NewEmptyTrie() + err = res.Load(db, trie.root.GetHash()) + require.NoError(t, err) - err = res.Load(db, trie.root.GetHash()) - require.NoError(t, err) + require.Equal(t, trie.childTries, res.childTries) + } + + }) - require.Equal(t, trie.String(), res.String()) - require.Equal(t, trie.childTries, res.childTries) - require.Equal(t, trie.MustHash(), res.MustHash()) } From 46d590c405e0f235f575e6840c5109602a6ae5a9 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Tue, 8 Mar 2022 17:50:47 +0530 Subject: [PATCH 13/22] more cleanup --- lib/trie/child_storage.go | 4 ++-- lib/trie/database_test.go | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/trie/child_storage.go b/lib/trie/child_storage.go index db6ab5ac2e..e69344b009 100644 --- a/lib/trie/child_storage.go +++ b/lib/trie/child_storage.go @@ -18,8 +18,8 @@ var ErrChildTrieDoesNotExist = errors.New("child trie does not exist") // PutChild inserts a child trie into the main trie at key :child_storage:[keyToChild] // A child trie is added as a node (K, V) in main trie. K is the child storage key // associated to the child trie, and V is the Merkle value of its corresponding child trie. -// To get merkle value of a node, we get value of the node. It the value is shorter than -// 32 bits we use it as merkle value. Otherwise, we use it's blake2b hash as merkle value. +// To get merkle value of a node, we get value of the node. If the value is shorter than +// 32 bits, we use it as merkle value. Otherwise, we use it's blake2b hash as merkle value. func (t *Trie) PutChild(keyToChild []byte, child *Trie) error { _, hash, err := child.root.EncodeAndHash() if err != nil { diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index a722a4ecc3..7f2f5b269a 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -391,21 +391,15 @@ func TestTrie_GetFromDB(t *testing.T) { } func TestStoreAndLoadWithChildTries(t *testing.T) { - // Use a fake node implementation in which Encode always fails - // Make that root of one of the childtries - // Run load and check that it fails - testCase := []Test{ {key: []byte{0xf2, 0x3}, value: []byte("f")}, {key: []byte{0x09, 0xd3}, value: []byte("noot")}, {key: []byte{0x07}, value: []byte("ramen")}, {key: []byte{0}, value: nil}, - } - - trie := NewEmptyTrie() - - for _, test := range testCase { - trie.Put(test.key, test.value) + { + key: []byte("The boxed moved. That was a problem."), + value: []byte("The question now was whether or not Peter was going to open it up and look inside to see why it had moved."), // nolint + }, } key := []byte{1, 2} @@ -414,15 +408,23 @@ func TestStoreAndLoadWithChildTries(t *testing.T) { const generation = 0 t.Run("happy path, tries being loaded are same as trie being read", func(t *testing.T) { - // hash could be different for keys smaller than 32 and larger than 32 bits. // thus, testing with keys of different sizes. keysToTest := [][]byte{ []byte("This handout will help you understand how paragraphs are formed, how to develop stronger paragraphs."), + []byte("This handout"), + []byte("test"), } - db := newTestDB(t) for _, keyToChild := range keysToTest { + trie := NewEmptyTrie() + + for _, test := range testCase { + trie.Put(test.key, test.value) + } + + db := newTestDB(t) + sampleChildTrie := NewTrie(node.NewLeaf(key, value, dirty, generation)) err := trie.PutChild(keyToChild, sampleChildTrie) From 68e446935da28c8b0ed3bc6443307030082fe70b Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Tue, 8 Mar 2022 18:08:13 +0530 Subject: [PATCH 14/22] remove mockleaf --- internal/trie/node/leaf.go | 51 -------------------------------------- 1 file changed, 51 deletions(-) diff --git a/internal/trie/node/leaf.go b/internal/trie/node/leaf.go index 614f6c8c44..f3087c14ff 100644 --- a/internal/trie/node/leaf.go +++ b/internal/trie/node/leaf.go @@ -4,11 +4,8 @@ package node import ( - "errors" "fmt" - "github.com/ChainSafe/gossamer/internal/trie/codec" - "github.com/ChainSafe/gossamer/pkg/scale" "github.com/qdm12/gotree" ) @@ -72,51 +69,3 @@ func bytesToString(b []byte) (s string) { return fmt.Sprintf("0x%x...%x", b[:8], b[len(b)-8:]) } } - -type MockLeaf struct { - Leaf - - Fail bool -} - -// Encode is a hijackable Encode method. -func (m *MockLeaf) Encode(buffer Buffer) (err error) { - if m.Fail { - return errors.New("some error") - } - - if !m.Leaf.Dirty && m.Leaf.Encoding != nil { - _, err = buffer.Write(m.Leaf.Encoding) - if err != nil { - return fmt.Errorf("cannot write stored encoding to buffer: %w", err) - } - return nil - } - - err = m.Leaf.encodeHeader(buffer) - if err != nil { - return fmt.Errorf("cannot encode header: %w", err) - } - - keyLE := codec.NibblesToKeyLE(m.Leaf.Key) - _, err = buffer.Write(keyLE) - if err != nil { - return fmt.Errorf("cannot write LE key to buffer: %w", err) - } - - encodedValue, err := scale.Marshal(m.Leaf.Value) // TODO scale encoder to write to buffer - if err != nil { - return fmt.Errorf("cannot scale marshal value: %w", err) - } - - _, err = buffer.Write(encodedValue) - if err != nil { - return fmt.Errorf("cannot write scale encoded value to buffer: %w", err) - } - - // TODO remove this copying since it defeats the purpose of `buffer` - // and the sync.Pool. - m.Leaf.Encoding = make([]byte, buffer.Len()) - copy(m.Leaf.Encoding, buffer.Bytes()) - return nil -} From 42d15329ca736b5e22f8c24ce18fe8ab90ef7a46 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Thu, 10 Mar 2022 17:43:55 +0530 Subject: [PATCH 15/22] fix the commit --- lib/trie/child_storage.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/trie/child_storage.go b/lib/trie/child_storage.go index e69344b009..1086e431f5 100644 --- a/lib/trie/child_storage.go +++ b/lib/trie/child_storage.go @@ -17,9 +17,7 @@ var ErrChildTrieDoesNotExist = errors.New("child trie does not exist") // PutChild inserts a child trie into the main trie at key :child_storage:[keyToChild] // A child trie is added as a node (K, V) in main trie. K is the child storage key -// associated to the child trie, and V is the Merkle value of its corresponding child trie. -// To get merkle value of a node, we get value of the node. If the value is shorter than -// 32 bits, we use it as merkle value. Otherwise, we use it's blake2b hash as merkle value. +// associated to the child trie, and V is the root hash of the child trie. func (t *Trie) PutChild(keyToChild []byte, child *Trie) error { _, hash, err := child.root.EncodeAndHash() if err != nil { From 2dd3a2c04ba967122b0ac829e219003483fd6fe9 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Mon, 14 Mar 2022 11:55:43 +0530 Subject: [PATCH 16/22] fix(lib/trie): Make sure writing and reading to disk gives the same trie (#2360) - If a node is root, we return blake2b hash of its encoding as hash regardless of whether length of encoding is smaller or greater than 32 - don't put childTrie again inside the trie - Revert "accept []byte key in trie.Load instead of common.Hash" --- dot/state/base_test.go | 2 +- dot/state/block_test.go | 2 +- dot/state/storage.go | 4 +-- dot/state/storage_test.go | 2 ++ internal/trie/node/hash.go | 8 +++--- internal/trie/node/hash_test.go | 4 +-- internal/trie/node/leaf.go | 2 +- internal/trie/node/node.go | 2 +- lib/trie/child_storage.go | 11 +++----- lib/trie/database.go | 47 ++++++++++----------------------- lib/trie/database_test.go | 13 ++++----- lib/trie/lookup.go | 12 ++++----- lib/trie/proof.go | 2 +- lib/trie/trie_endtoend_test.go | 3 ++- 14 files changed, 48 insertions(+), 66 deletions(-) diff --git a/dot/state/base_test.go b/dot/state/base_test.go index bde319ff25..a217d63887 100644 --- a/dot/state/base_test.go +++ b/dot/state/base_test.go @@ -35,7 +35,7 @@ func TestTrie_StoreAndLoadFromDB(t *testing.T) { expected := tt.MustHash() tt = trie.NewEmptyTrie() - err = tt.Load(db, encroot.ToBytes()) + err = tt.Load(db, encroot) require.NoError(t, err) require.Equal(t, expected, tt.MustHash()) } diff --git a/dot/state/block_test.go b/dot/state/block_test.go index 68167c0176..e665c8cdea 100644 --- a/dot/state/block_test.go +++ b/dot/state/block_test.go @@ -40,7 +40,7 @@ func newTestBlockState(t *testing.T, header *types.Header, tries *Tries) *BlockS // loads in-memory tries with genesis state root, should be deleted // after another block is finalised tr := trie.NewEmptyTrie() - err = tr.Load(bs.db, header.StateRoot.ToBytes()) + err = tr.Load(bs.db, header.StateRoot) require.NoError(t, err) bs.tries.softSet(header.StateRoot, tr) diff --git a/dot/state/storage.go b/dot/state/storage.go index 565826f7c7..684f229208 100644 --- a/dot/state/storage.go +++ b/dot/state/storage.go @@ -142,7 +142,7 @@ func (s *StorageState) TrieState(root *common.Hash) (*rtstorage.TrieState, error // LoadFromDB loads an encoded trie from the DB where the key is `root` func (s *StorageState) LoadFromDB(root common.Hash) (*trie.Trie, error) { t := trie.NewEmptyTrie() - err := t.Load(s.db, root.ToBytes()) + err := t.Load(s.db, root) if err != nil { return nil, err } @@ -167,7 +167,7 @@ func (s *StorageState) loadTrie(root *common.Hash) (*trie.Trie, error) { tr, err := s.LoadFromDB(*root) if err != nil { - return nil, errTrieDoesNotExist(*root) + return nil, fmt.Errorf("%s, %w", err, errTrieDoesNotExist(*root)) } return tr, nil diff --git a/dot/state/storage_test.go b/dot/state/storage_test.go index e5bbf32989..999fcddabf 100644 --- a/dot/state/storage_test.go +++ b/dot/state/storage_test.go @@ -4,6 +4,7 @@ package state import ( + "fmt" "testing" "time" @@ -201,6 +202,7 @@ func TestGetStorageChildAndGetStorageFromChild(t *testing.T) { trieState, err := runtime.NewTrieState(genTrie) require.NoError(t, err) + fmt.Printf("genTrie.RootNode().GetHash() %s\n", genTrie.RootNode().GetHash()) header, err := types.NewHeader(blockState.GenesisHash(), trieState.MustRoot(), common.Hash{}, 1, types.NewDigest()) diff --git a/internal/trie/node/hash.go b/internal/trie/node/hash.go index d8fc2a51d2..85d997e6c7 100644 --- a/internal/trie/node/hash.go +++ b/internal/trie/node/hash.go @@ -29,7 +29,7 @@ func (b *Branch) GetHash() []byte { // the blake2b hash digest of the encoding of the branch. // If the encoding is less than 32 bytes, the hash returned // is the encoding and not the hash of the encoding. -func (b *Branch) EncodeAndHash() (encoding, hash []byte, err error) { +func (b *Branch) EncodeAndHash(isRoot bool) (encoding, hash []byte, err error) { if !b.Dirty && b.Encoding != nil && b.HashDigest != nil { return b.Encoding, b.HashDigest, nil } @@ -49,7 +49,7 @@ func (b *Branch) EncodeAndHash() (encoding, hash []byte, err error) { copy(b.Encoding, bufferBytes) encoding = b.Encoding // no need to copy - if buffer.Len() < 32 { + if !isRoot && buffer.Len() < 32 { b.HashDigest = make([]byte, len(bufferBytes)) copy(b.HashDigest, bufferBytes) hash = b.HashDigest // no need to copy @@ -86,7 +86,7 @@ func (l *Leaf) GetHash() []byte { // the blake2b hash digest of the encoding of the leaf. // If the encoding is less than 32 bytes, the hash returned // is the encoding and not the hash of the encoding. -func (l *Leaf) EncodeAndHash() (encoding, hash []byte, err error) { +func (l *Leaf) EncodeAndHash(isRoot bool) (encoding, hash []byte, err error) { if !l.IsDirty() && l.Encoding != nil && l.HashDigest != nil { return l.Encoding, l.HashDigest, nil } @@ -108,7 +108,7 @@ func (l *Leaf) EncodeAndHash() (encoding, hash []byte, err error) { copy(l.Encoding, bufferBytes) encoding = l.Encoding // no need to copy - if len(bufferBytes) < 32 { + if !isRoot && len(bufferBytes) < 32 { l.HashDigest = make([]byte, len(bufferBytes)) copy(l.HashDigest, bufferBytes) hash = l.HashDigest // no need to copy diff --git a/internal/trie/node/hash_test.go b/internal/trie/node/hash_test.go index 32532d05b1..10dd165726 100644 --- a/internal/trie/node/hash_test.go +++ b/internal/trie/node/hash_test.go @@ -119,7 +119,7 @@ func Test_Branch_EncodeAndHash(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - encoding, hash, err := testCase.branch.EncodeAndHash() + encoding, hash, err := testCase.branch.EncodeAndHash(false) assert.ErrorIs(t, err, testCase.errWrapped) if testCase.errWrapped != nil { @@ -241,7 +241,7 @@ func Test_Leaf_EncodeAndHash(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - encoding, hash, err := testCase.leaf.EncodeAndHash() + encoding, hash, err := testCase.leaf.EncodeAndHash(false) assert.ErrorIs(t, err, testCase.errWrapped) if testCase.errWrapped != nil { diff --git a/internal/trie/node/leaf.go b/internal/trie/node/leaf.go index f3087c14ff..129ebce3c1 100644 --- a/internal/trie/node/leaf.go +++ b/internal/trie/node/leaf.go @@ -16,7 +16,7 @@ type Leaf struct { // Partial key bytes in nibbles (0 to f in hexadecimal) Key []byte Value []byte - // Dirty is true when the branch differs + // Dirty is true when the leaf differs // from the node stored in the database. Dirty bool HashDigest []byte diff --git a/internal/trie/node/node.go b/internal/trie/node/node.go index 32ce4fc729..cedab37772 100644 --- a/internal/trie/node/node.go +++ b/internal/trie/node/node.go @@ -8,7 +8,7 @@ import "github.com/qdm12/gotree" // Node is a node in the trie and can be a leaf or a branch. type Node interface { Encode(buffer Buffer) (err error) // TODO change to io.Writer - EncodeAndHash() (encoding []byte, hash []byte, err error) + EncodeAndHash(isRoot bool) (encoding []byte, hash []byte, err error) ScaleEncodeHash() (encoding []byte, err error) IsDirty() bool SetDirty(dirty bool) diff --git a/lib/trie/child_storage.go b/lib/trie/child_storage.go index 1086e431f5..86c983e4ad 100644 --- a/lib/trie/child_storage.go +++ b/lib/trie/child_storage.go @@ -19,15 +19,14 @@ var ErrChildTrieDoesNotExist = errors.New("child trie does not exist") // A child trie is added as a node (K, V) in main trie. K is the child storage key // associated to the child trie, and V is the root hash of the child trie. func (t *Trie) PutChild(keyToChild []byte, child *Trie) error { - _, hash, err := child.root.EncodeAndHash() + hash, err := child.Hash() if err != nil { return err } - key := append(ChildStorageKeyPrefix, keyToChild...) - t.Put(key, hash) - t.childTries[common.BytesToHash(hash)] = child + t.Put(key, hash.ToBytes()) + t.childTries[hash] = child return nil } @@ -39,9 +38,7 @@ func (t *Trie) GetChild(keyToChild []byte) (*Trie, error) { return nil, fmt.Errorf("%w at key 0x%x%x", ErrChildTrieDoesNotExist, ChildStorageKeyPrefix, keyToChild) } - hash := [32]byte{} - copy(hash[:], childHash) - return t.childTries[common.Hash(hash)], nil + return t.childTries[common.BytesToHash(childHash)], nil } // PutIntoChild puts a key-value pair into the child trie located in the main trie at key :child_storage:[keyToChild] diff --git a/lib/trie/database.go b/lib/trie/database.go index 67e163d6cc..7fa58f34b8 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -46,7 +46,7 @@ func (t *Trie) store(db chaindb.Batch, n Node) error { return nil } - encoding, hash, err := n.EncodeAndHash() + encoding, hash, err := n.EncodeAndHash(n == t.root) if err != nil { return err } @@ -97,7 +97,7 @@ func (t *Trie) loadFromProof(rawProof [][]byte, rootHash []byte) error { decodedNode.SetDirty(dirty) decodedNode.SetEncodingAndHash(rawNode, nil) - _, hash, err := decodedNode.EncodeAndHash() + _, hash, err := decodedNode.EncodeAndHash(decodedNode == t.root) if err != nil { return fmt.Errorf("cannot encode and hash node at index %d: %w", i, err) } @@ -145,15 +145,16 @@ func (t *Trie) loadProof(proofHashToNode map[string]Node, n Node) { // Load reconstructs the trie from the database from the given root hash. // It is used when restarting the node to load the current state trie. -func (t *Trie) Load(db chaindb.Database, rootHashBytes []byte) error { - if len(rootHashBytes) == 0 { +func (t *Trie) Load(db chaindb.Database, rootHash common.Hash) error { + if rootHash == EmptyHash { t.root = nil return nil } + rootHashBytes := rootHash.ToBytes() encodedNode, err := db.Get(rootHashBytes) if err != nil { - return fmt.Errorf("failed to find root key 0x%x: %w", rootHashBytes, err) + return fmt.Errorf("failed to find root key %s: %w", rootHash, err) } reader := bytes.NewReader(encodedNode) @@ -210,17 +211,17 @@ func (t *Trie) load(db chaindb.Database, n Node) error { childTrie := NewEmptyTrie() value := t.Get(key) // TODO: Tests this error - err := childTrie.Load(db, value) + rootHash := common.BytesToHash(value) + err := childTrie.Load(db, rootHash) if err != nil { - return fmt.Errorf("failed to load child trie with root hash=0x%x: %w", value, err) + return fmt.Errorf("failed to load child trie with root hash=%s: %w", rootHash, err) } - // TODO: Test this error - err = t.PutChild(value, childTrie) + hash, err := childTrie.Hash() if err != nil { - return fmt.Errorf("failed to insert child trie with root hash=0x%x into main trie: %w", - childTrie.root.GetHash(), err) + return err } + t.childTries[hash] = childTrie } return nil @@ -372,23 +373,13 @@ func (t *Trie) writeDirty(db chaindb.Batch, n Node) error { return nil } - encoding, hash, err := n.EncodeAndHash() + encoding, hash, err := n.EncodeAndHash(n == t.root) if err != nil { return fmt.Errorf( "cannot encode and hash node with hash 0x%x: %w", n.GetHash(), err) } - // hash root node even if its encoding is under 32 bytes - if n == t.root && len(encoding) < 32 { - encodingDigest, err := common.Blake2bHash(encoding) - if err != nil { - return fmt.Errorf("cannot hash root node encoding: %w", err) - } - - hash = encodingDigest[:] - } - err = db.Put(hash, encoding) if err != nil { return fmt.Errorf( @@ -448,23 +439,13 @@ func (t *Trie) getInsertedNodeHashes(n Node, hashes map[common.Hash]struct{}) (e return nil } - encoding, hash, err := n.EncodeAndHash() + _, hash, err := n.EncodeAndHash(n == t.root) if err != nil { return fmt.Errorf( "cannot encode and hash node with hash 0x%x: %w", n.GetHash(), err) } - if n == t.root && len(encoding) < 32 { - // hash root node even if its encoding is under 32 bytes - encodingDigest, err := common.Blake2bHash(encoding) - if err != nil { - return fmt.Errorf("cannot hash root node encoding: %w", err) - } - - hash = encodingDigest[:] - } - hashes[common.BytesToHash(hash)] = struct{}{} switch n.Type() { diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index 7f2f5b269a..befc538a2f 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -64,7 +64,7 @@ func TestTrie_DatabaseStoreAndLoad(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash().ToBytes()) + err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) require.Equal(t, trie.String(), res.String()) @@ -136,7 +136,7 @@ func TestTrie_WriteDirty_Put(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash().ToBytes()) + err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) @@ -206,7 +206,7 @@ func TestTrie_WriteDirty_PutReplace(t *testing.T) { } res := NewEmptyTrie() - err := res.Load(db, trie.MustHash().ToBytes()) + err := res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) @@ -266,7 +266,7 @@ func TestTrie_WriteDirty_Delete(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash().ToBytes()) + err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) @@ -331,7 +331,7 @@ func TestTrie_WriteDirty_ClearPrefix(t *testing.T) { require.NoError(t, err) res := NewEmptyTrie() - err = res.Load(db, trie.MustHash().ToBytes()) + err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.MustHash(), res.MustHash()) @@ -435,10 +435,11 @@ func TestStoreAndLoadWithChildTries(t *testing.T) { res := NewEmptyTrie() - err = res.Load(db, trie.root.GetHash()) + err = res.Load(db, trie.MustHash()) require.NoError(t, err) require.Equal(t, trie.childTries, res.childTries) + require.Equal(t, trie.String(), res.String()) } }) diff --git a/lib/trie/lookup.go b/lib/trie/lookup.go index b47d989495..606f64114b 100644 --- a/lib/trie/lookup.go +++ b/lib/trie/lookup.go @@ -18,24 +18,24 @@ type recorder interface { // findAndRecord search for a desired key recording all the nodes in the path including the desired node func findAndRecord(t *Trie, key []byte, recorder recorder) error { - return find(t.root, key, recorder) + return find(t.root, key, recorder, true) } -func find(parent Node, key []byte, recorder recorder) error { - enc, hash, err := parent.EncodeAndHash() +func find(current Node, key []byte, recorder recorder, isCurrentRoot bool) error { + enc, hash, err := current.EncodeAndHash(isCurrentRoot) if err != nil { return err } recorder.Record(hash, enc) - switch parent.Type() { + switch current.Type() { case node.BranchType, node.BranchWithValueType: default: // not a branch return nil } - b := parent.(*node.Branch) + b := current.(*node.Branch) length := lenCommonPrefix(b.Key, key) @@ -49,5 +49,5 @@ func find(parent Node, key []byte, recorder recorder) error { return nil } - return find(b.Children[key[length]], key[length+1:], recorder) + return find(b.Children[key[length]], key[length+1:], recorder, false) } diff --git a/lib/trie/proof.go b/lib/trie/proof.go index a3b2aad31f..4bd2b0c066 100644 --- a/lib/trie/proof.go +++ b/lib/trie/proof.go @@ -37,7 +37,7 @@ func GenerateProof(root []byte, keys [][]byte, db chaindb.Database) ([][]byte, e trackedProofs := make(map[string][]byte) proofTrie := NewEmptyTrie() - if err := proofTrie.Load(db, root); err != nil { + if err := proofTrie.Load(db, common.BytesToHash(root)); err != nil { return nil, err } diff --git a/lib/trie/trie_endtoend_test.go b/lib/trie/trie_endtoend_test.go index 8327b75f2c..7baf467c7a 100644 --- a/lib/trie/trie_endtoend_test.go +++ b/lib/trie/trie_endtoend_test.go @@ -22,6 +22,7 @@ import ( "github.com/ChainSafe/gossamer/internal/trie/codec" "github.com/ChainSafe/gossamer/internal/trie/node" + "github.com/ChainSafe/gossamer/lib/common" ) const ( @@ -396,7 +397,7 @@ func TestTrieDiff(t *testing.T) { } dbTrie := NewEmptyTrie() - err = dbTrie.Load(storageDB, newTrie.root.GetHash()) + err = dbTrie.Load(storageDB, common.BytesToHash(newTrie.root.GetHash())) require.NoError(t, err) } From 019953bc7cc76c3d95dac326e349c5d9761c9891 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Tue, 15 Mar 2022 17:44:16 +0530 Subject: [PATCH 17/22] remove todos --- lib/trie/database.go | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/trie/database.go b/lib/trie/database.go index b96f7ba105..8bee2f11df 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -210,7 +210,6 @@ func (t *Trie) load(db chaindb.Database, n Node) error { for _, key := range t.GetKeysWithPrefix(ChildStorageKeyPrefix) { childTrie := NewEmptyTrie() value := t.Get(key) - // TODO: Tests this error rootHash := common.BytesToHash(value) err := childTrie.Load(db, rootHash) if err != nil { From ccca175473b6e419fc4b5cf56ea12a772cc3391d Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Thu, 17 Mar 2022 20:39:28 +0530 Subject: [PATCH 18/22] Update lib/trie/child_storage.go Co-authored-by: Quentin McGaw --- lib/trie/child_storage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/trie/child_storage.go b/lib/trie/child_storage.go index 86c983e4ad..f0ea8cb5fa 100644 --- a/lib/trie/child_storage.go +++ b/lib/trie/child_storage.go @@ -16,7 +16,7 @@ var ChildStorageKeyPrefix = []byte(":child_storage:default:") var ErrChildTrieDoesNotExist = errors.New("child trie does not exist") // PutChild inserts a child trie into the main trie at key :child_storage:[keyToChild] -// A child trie is added as a node (K, V) in main trie. K is the child storage key +// A child trie is added as a node (K, V) in the main trie. K is the child storage key // associated to the child trie, and V is the root hash of the child trie. func (t *Trie) PutChild(keyToChild []byte, child *Trie) error { hash, err := child.Hash() From 03af4b0146a87199804a15785bb8a3fdb6499c39 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Thu, 17 Mar 2022 20:45:15 +0530 Subject: [PATCH 19/22] Update dot/state/storage_test.go Co-authored-by: Quentin McGaw --- dot/state/storage_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/dot/state/storage_test.go b/dot/state/storage_test.go index 999fcddabf..3dd07f18ed 100644 --- a/dot/state/storage_test.go +++ b/dot/state/storage_test.go @@ -202,7 +202,6 @@ func TestGetStorageChildAndGetStorageFromChild(t *testing.T) { trieState, err := runtime.NewTrieState(genTrie) require.NoError(t, err) - fmt.Printf("genTrie.RootNode().GetHash() %s\n", genTrie.RootNode().GetHash()) header, err := types.NewHeader(blockState.GenesisHash(), trieState.MustRoot(), common.Hash{}, 1, types.NewDigest()) From 9d4f1959d68850209c2bde91f7e02bcbc35d08b6 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Fri, 18 Mar 2022 09:20:57 +0530 Subject: [PATCH 20/22] Update dot/state/storage.go Co-authored-by: Quentin McGaw --- dot/state/storage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dot/state/storage.go b/dot/state/storage.go index 684f229208..b4781b204c 100644 --- a/dot/state/storage.go +++ b/dot/state/storage.go @@ -167,7 +167,7 @@ func (s *StorageState) loadTrie(root *common.Hash) (*trie.Trie, error) { tr, err := s.LoadFromDB(*root) if err != nil { - return nil, fmt.Errorf("%s, %w", err, errTrieDoesNotExist(*root)) + return nil, fmt.Errorf("trie does not exist at root %s: %w", *root, err) } return tr, nil From d6cfcc26849a67fc5ca500d00f3130270e000a42 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Fri, 18 Mar 2022 09:31:20 +0530 Subject: [PATCH 21/22] addressed reviews --- dot/state/storage_test.go | 9 ++------- lib/trie/child_storage.go | 6 +++--- lib/trie/database.go | 2 +- lib/trie/database_test.go | 3 ++- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/dot/state/storage_test.go b/dot/state/storage_test.go index 3dd07f18ed..b060cf2c3e 100644 --- a/dot/state/storage_test.go +++ b/dot/state/storage_test.go @@ -4,7 +4,6 @@ package state import ( - "fmt" "testing" "time" @@ -181,11 +180,7 @@ func TestGetStorageChildAndGetStorageFromChild(t *testing.T) { "0", )) - key := []byte{1, 2} - value := []byte{3, 4} - const dirty = true - const generation = 0 - testChildTrie := trie.NewTrie(node.NewLeaf(key, value, dirty, generation)) + testChildTrie := trie.NewTrie(node.NewLeaf([]byte{1, 2}, []byte{3, 4}, true, 0)) testChildTrie.Put([]byte("keyInsidechild"), []byte("voila")) @@ -222,7 +217,7 @@ func TestGetStorageChildAndGetStorageFromChild(t *testing.T) { _, err = storage.GetStorageChild(&rootHash, []byte("keyToChild")) require.NoError(t, err) - value, err = storage.GetStorageFromChild(&rootHash, []byte("keyToChild"), []byte("keyInsidechild")) + value, err := storage.GetStorageFromChild(&rootHash, []byte("keyToChild"), []byte("keyInsidechild")) require.NoError(t, err) require.Equal(t, []byte("voila"), value) diff --git a/lib/trie/child_storage.go b/lib/trie/child_storage.go index f0ea8cb5fa..9b49f95a4d 100644 --- a/lib/trie/child_storage.go +++ b/lib/trie/child_storage.go @@ -19,14 +19,14 @@ var ErrChildTrieDoesNotExist = errors.New("child trie does not exist") // A child trie is added as a node (K, V) in the main trie. K is the child storage key // associated to the child trie, and V is the root hash of the child trie. func (t *Trie) PutChild(keyToChild []byte, child *Trie) error { - hash, err := child.Hash() + childHash, err := child.Hash() if err != nil { return err } key := append(ChildStorageKeyPrefix, keyToChild...) - t.Put(key, hash.ToBytes()) - t.childTries[hash] = child + t.Put(key, childHash.ToBytes()) + t.childTries[childHash] = child return nil } diff --git a/lib/trie/database.go b/lib/trie/database.go index 8bee2f11df..b9822dc47a 100644 --- a/lib/trie/database.go +++ b/lib/trie/database.go @@ -218,7 +218,7 @@ func (t *Trie) load(db chaindb.Database, n Node) error { hash, err := childTrie.Hash() if err != nil { - return err + return fmt.Errorf("cannot hash chilld trie at key 0x%x: %w", key, err) } t.childTries[hash] = childTrie } diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index befc538a2f..8ec940658e 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -66,7 +66,6 @@ func TestTrie_DatabaseStoreAndLoad(t *testing.T) { res := NewEmptyTrie() err = res.Load(db, trie.MustHash()) require.NoError(t, err) - require.Equal(t, trie.MustHash(), res.MustHash()) require.Equal(t, trie.String(), res.String()) for _, test := range testCase { @@ -408,6 +407,8 @@ func TestStoreAndLoadWithChildTries(t *testing.T) { const generation = 0 t.Run("happy path, tries being loaded are same as trie being read", func(t *testing.T) { + t.Parallel() + // hash could be different for keys smaller than 32 and larger than 32 bits. // thus, testing with keys of different sizes. keysToTest := [][]byte{ From 5c7ec3825d9e101382f5ee22a8df08b7f2457d61 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Fri, 18 Mar 2022 09:33:58 +0530 Subject: [PATCH 22/22] renaming Test to keyValue --- lib/trie/database_test.go | 16 ++++++------- lib/trie/helpers_test.go | 2 +- lib/trie/trie_endtoend_test.go | 42 +++++++++++++++++----------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/trie/database_test.go b/lib/trie/database_test.go index 8ec940658e..07a041090b 100644 --- a/lib/trie/database_test.go +++ b/lib/trie/database_test.go @@ -22,7 +22,7 @@ func newTestDB(t *testing.T) chaindb.Database { } func TestTrie_DatabaseStoreAndLoad(t *testing.T) { - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, @@ -77,7 +77,7 @@ func TestTrie_DatabaseStoreAndLoad(t *testing.T) { } func TestTrie_WriteDirty_Put(t *testing.T) { - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, @@ -155,7 +155,7 @@ func TestTrie_WriteDirty_Put(t *testing.T) { } func TestTrie_WriteDirty_PutReplace(t *testing.T) { - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, @@ -218,7 +218,7 @@ func TestTrie_WriteDirty_PutReplace(t *testing.T) { } func TestTrie_WriteDirty_Delete(t *testing.T) { - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, @@ -285,7 +285,7 @@ func TestTrie_WriteDirty_Delete(t *testing.T) { } func TestTrie_WriteDirty_ClearPrefix(t *testing.T) { - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, @@ -338,7 +338,7 @@ func TestTrie_WriteDirty_ClearPrefix(t *testing.T) { } func TestTrie_GetFromDB(t *testing.T) { - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, @@ -390,7 +390,7 @@ func TestTrie_GetFromDB(t *testing.T) { } func TestStoreAndLoadWithChildTries(t *testing.T) { - testCase := []Test{ + keyValue := []keyValues{ {key: []byte{0xf2, 0x3}, value: []byte("f")}, {key: []byte{0x09, 0xd3}, value: []byte("noot")}, {key: []byte{0x07}, value: []byte("ramen")}, @@ -420,7 +420,7 @@ func TestStoreAndLoadWithChildTries(t *testing.T) { for _, keyToChild := range keysToTest { trie := NewEmptyTrie() - for _, test := range testCase { + for _, test := range keyValue { trie.Put(test.key, test.value) } diff --git a/lib/trie/helpers_test.go b/lib/trie/helpers_test.go index 834415f4d9..e0853c6efe 100644 --- a/lib/trie/helpers_test.go +++ b/lib/trie/helpers_test.go @@ -20,7 +20,7 @@ type writeCall struct { var errTest = errors.New("test error") -type Test struct { +type keyValues struct { key []byte value []byte op int diff --git a/lib/trie/trie_endtoend_test.go b/lib/trie/trie_endtoend_test.go index 7baf467c7a..cdb0c69945 100644 --- a/lib/trie/trie_endtoend_test.go +++ b/lib/trie/trie_endtoend_test.go @@ -60,7 +60,7 @@ func writeFailedData(t *testing.T, kv map[string][]byte, path string) { func buildSmallTrie() *Trie { trie := NewEmptyTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, {key: []byte{0xf2}, value: []byte("feather")}, @@ -76,7 +76,7 @@ func buildSmallTrie() *Trie { return trie } -func runTests(t *testing.T, trie *Trie, tests []Test) { +func runTests(t *testing.T, trie *Trie, tests []keyValues) { for _, test := range tests { switch test.op { case put: @@ -96,7 +96,7 @@ func runTests(t *testing.T, trie *Trie, tests []Test) { func TestPutAndGetBranch(t *testing.T) { trie := NewEmptyTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{0x01, 0x35}, value: []byte("spaghetti"), op: put}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("gnocchi"), op: put}, {key: []byte{0x07}, value: []byte("ramen"), op: put}, @@ -115,7 +115,7 @@ func TestPutAndGetBranch(t *testing.T) { func TestPutAndGetOddKeyLengths(t *testing.T) { trie := NewEmptyTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{0x43, 0xc1}, value: []byte("noot"), op: put}, {key: []byte{0x49, 0x29}, value: []byte("nootagain"), op: put}, {key: []byte{0x43, 0x0c}, value: []byte("odd"), op: put}, @@ -210,7 +210,7 @@ func Test_Trie_PutAndGet_FailedData(t *testing.T) { func TestGetPartialKey(t *testing.T) { trie := NewEmptyTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{0x01, 0x35}, value: []byte("pen"), op: put}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin"), op: put}, {key: []byte{0x01, 0x35, 0x07}, value: []byte("odd"), op: put}, @@ -235,7 +235,7 @@ func TestGetPartialKey(t *testing.T) { func TestDeleteSmall(t *testing.T) { trie := buildSmallTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{}, value: []byte("floof"), op: del}, {key: []byte{}, value: nil, op: get}, {key: []byte{}, value: []byte("floof"), op: put}, @@ -279,7 +279,7 @@ func TestDeleteSmall(t *testing.T) { func TestDeleteCombineBranch(t *testing.T) { trie := buildSmallTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{0x01, 0x35, 0x46}, value: []byte("raccoon"), op: put}, {key: []byte{0x01, 0x35, 0x46, 0x77}, value: []byte("rat"), op: put}, {key: []byte{0x09, 0xd3}, value: []byte("noot"), op: del}, @@ -292,7 +292,7 @@ func TestDeleteCombineBranch(t *testing.T) { func TestDeleteFromBranch(t *testing.T) { trie := NewEmptyTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{0x06, 0x15, 0xfc}, value: []byte("noot"), op: put}, {key: []byte{0x06, 0x2b, 0xa9}, value: []byte("nootagain"), op: put}, {key: []byte{0x06, 0xaf, 0xb1}, value: []byte("odd"), op: put}, @@ -317,7 +317,7 @@ func TestDeleteFromBranch(t *testing.T) { func TestDeleteOddKeyLengths(t *testing.T) { trie := NewEmptyTrie() - tests := []Test{ + tests := []keyValues{ {key: []byte{0x43, 0xc1}, value: []byte("noot"), op: put}, {key: []byte{0x43, 0xc1}, value: []byte("noot"), op: get}, {key: []byte{0x49, 0x29}, value: []byte("nootagain"), op: put}, @@ -360,7 +360,7 @@ func TestTrieDiff(t *testing.T) { var testKey = []byte("testKey") - tests := []Test{ + tests := []keyValues{ {key: testKey, value: testKey}, {key: []byte("testKey1"), value: []byte("testKey1")}, {key: []byte("testKey2"), value: []byte("testKey2")}, @@ -374,7 +374,7 @@ func TestTrieDiff(t *testing.T) { err = trie.Store(storageDB) require.NoError(t, err) - tests = []Test{ + tests = []keyValues{ {key: testKey, value: []byte("newTestKey2")}, {key: []byte("testKey2"), value: []byte("newKey")}, {key: []byte("testKey3"), value: []byte("testKey3")}, @@ -462,7 +462,7 @@ func TestDelete(t *testing.T) { } func TestClearPrefix(t *testing.T) { - tests := []Test{ + tests := []keyValues{ {key: []byte{0x01, 0x35}, value: []byte("spaghetti"), op: put}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("gnocchi"), op: put}, {key: []byte{0x01, 0x35, 0x79, 0xab}, value: []byte("spaghetti"), op: put}, @@ -627,7 +627,7 @@ func TestTrie_ClearPrefixVsDelete(t *testing.T) { []byte("a"), } - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("penguin")}, @@ -681,7 +681,7 @@ func TestTrie_ClearPrefixVsDelete(t *testing.T) { } func TestSnapshot(t *testing.T) { - tests := []Test{ + tests := []keyValues{ {key: []byte{0x01, 0x35}, value: []byte("spaghetti"), op: put}, {key: []byte{0x01, 0x35, 0x79}, value: []byte("gnocchi"), op: put}, {key: []byte{0x01, 0x35, 0x79, 0xab}, value: []byte("spaghetti"), op: put}, @@ -784,11 +784,11 @@ func TestTrie_ConcurrentSnapshotWrites(t *testing.T) { const size = 1000 const workers = 4 - testCases := make([][]Test, workers) + testCases := make([][]keyValues, workers) expectedTries := make([]*Trie, workers) for i := 0; i < workers; i++ { - testCases[i] = make([]Test, size) + testCases[i] = make([]keyValues, size) expectedTries[i] = buildSmallTrie() for j := 0; j < size; j++ { k := make([]byte, 2) @@ -805,7 +805,7 @@ func TestTrie_ConcurrentSnapshotWrites(t *testing.T) { expectedTries[i].ClearPrefix(k) } - testCases[i][j] = Test{ + testCases[i][j] = keyValues{ key: k, op: op, } @@ -821,7 +821,7 @@ func TestTrie_ConcurrentSnapshotWrites(t *testing.T) { for i := 0; i < workers; i++ { snapshotedTries[i] = buildSmallTrie().Snapshot() - go func(trie *Trie, operations []Test, + go func(trie *Trie, operations []keyValues, startWg, finishWg *sync.WaitGroup) { defer finishWg.Done() startWg.Done() @@ -864,7 +864,7 @@ func TestTrie_ClearPrefixLimit(t *testing.T) { {0x09}, } - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01, 0x35}, value: []byte("pen")}, {key: []byte{0x01, 0x36}, value: []byte("pencil")}, @@ -900,7 +900,7 @@ func TestTrie_ClearPrefixLimit(t *testing.T) { }, } - testFn := func(t *testing.T, testCase []Test, prefix []byte) { + testFn := func(t *testing.T, testCase []keyValues, prefix []byte) { prefixNibbles := codec.KeyLEToNibbles(prefix) if len(prefixNibbles) > 0 && prefixNibbles[len(prefixNibbles)-1] == 0 { prefixNibbles = prefixNibbles[:len(prefixNibbles)-1] @@ -965,7 +965,7 @@ func TestTrie_ClearPrefixLimitSnapshot(t *testing.T) { {0x09}, } - cases := [][]Test{ + cases := [][]keyValues{ { {key: []byte{0x01}, value: []byte("feather")}, },