diff --git a/common/dbutils/bucket.go b/common/dbutils/bucket.go index a535e9b5da40421a77734bbcc818877e5e7b7137..08e9f1bcc5755cf3a56b2a883c0a55d834c3284b 100644 --- a/common/dbutils/bucket.go +++ b/common/dbutils/bucket.go @@ -110,7 +110,7 @@ hasHash - mark prefixes which hashes are saved in current trie_account record (a v v v v v +------------------+ +----------------------+ +---------------+ +---------------+ +---------------+ | Account: | | BranchNode: 0x0B0004 | | Account: | | Account: | | Account: | -| 0x0B0000... | | has no record in | | 0x0B01... | | 0x0B0301... | | 0x050304... | +| 0x0B0000... | | has no record in | | 0x0B01... | | 0x0B0301... | | 0x0B0304... | | in HashedAccount | | TrieAccount | | | | | | | +------------------+ +----------------------+ +---------------+ +---------------+ +---------------+ | | diff --git a/eth/stagedsync/stage_interhashes_test.go b/eth/stagedsync/stage_interhashes_test.go new file mode 100644 index 0000000000000000000000000000000000000000..25e2d95fbdbdb7ed766dbbf64d637904b697ce08 --- /dev/null +++ b/eth/stagedsync/stage_interhashes_test.go @@ -0,0 +1,65 @@ +package stagedsync + +import ( + "testing" + + "github.com/ledgerwatch/turbo-geth/common" + "github.com/ledgerwatch/turbo-geth/common/dbutils" + "github.com/ledgerwatch/turbo-geth/core/types/accounts" + "github.com/ledgerwatch/turbo-geth/ethdb" + "github.com/ledgerwatch/turbo-geth/turbo/trie" + "github.com/stretchr/testify/assert" +) + +func addTestAccount(db ethdb.Putter, hash common.Hash, balance uint64) error { + acc := accounts.NewAccount() + acc.Balance.SetUint64(balance) + encoded := make([]byte, acc.EncodingLengthForStorage()) + acc.EncodeForStorage(encoded) + return db.Put(dbutils.HashedAccountsBucket, hash[:], encoded) +} + +func TestTrieOfAccountsLayout(t *testing.T) { + db := ethdb.NewMemDatabase() + + hash1 := common.HexToHash("0xB000000000000000000000000000000000000000000000000000000000000000") + assert.Nil(t, addTestAccount(db, hash1, 300_000_000_000)) + + hash2 := common.HexToHash("0xB040000000000000000000000000000000000000000000000000000000000000") + assert.Nil(t, addTestAccount(db, hash2, 100_000_000_000)) + + hash3 := common.HexToHash("0xB041000000000000000000000000000000000000000000000000000000000000") + assert.Nil(t, addTestAccount(db, hash3, 200_000_000_000)) + + hash4 := common.HexToHash("0xB100000000000000000000000000000000000000000000000000000000000000") + assert.Nil(t, addTestAccount(db, hash4, 400_000_000_000)) + + hash5 := common.HexToHash("0xB310000000000000000000000000000000000000000000000000000000000000") + assert.Nil(t, addTestAccount(db, hash5, 800_000_000_000)) + + hash6 := common.HexToHash("0xB340000000000000000000000000000000000000000000000000000000000000") + assert.Nil(t, addTestAccount(db, hash6, 100_000_000_000)) + + err := RegenerateIntermediateHashes("IH", db, false /* checkRoot */, nil /* cache */, getTmpDir(), common.Hash{} /* expectedRootHash */, nil /* quit */) + assert.Nil(t, err) + + account_trie := make(map[string][]byte) + + err = db.Walk(dbutils.TrieOfAccountsBucket, []byte{}, 0, func(k, v []byte) (bool, error) { + account_trie[string(k)] = v + return true, nil + }) + assert.Nil(t, err) + + assert.Equal(t, 2, len(account_trie)) + + hasState1, hasTree1, hasHash1, _, _ := trie.UnmarshalTrieNode(account_trie[string(common.FromHex("0B"))]) + assert.Equal(t, uint16(0b1011), hasState1) + assert.Equal(t, uint16(0b0001), hasTree1) + assert.Equal(t, uint16(0b1001), hasHash1) + + hasState2, hasTree2, hasHash2, _, _ := trie.UnmarshalTrieNode(account_trie[string(common.FromHex("0B00"))]) + assert.Equal(t, uint16(0b10001), hasState2) + assert.Equal(t, uint16(0b00000), hasTree2) + assert.Equal(t, uint16(0b10000), hasHash2) +} diff --git a/ethdb/kv_lmdb.go b/ethdb/kv_lmdb.go index 796a0e17fe723c469ef07c5c96c060579dc88204..968a92f5f01fa1d5ca61c72172f917b2e6ea0067 100644 --- a/ethdb/kv_lmdb.go +++ b/ethdb/kv_lmdb.go @@ -1320,8 +1320,13 @@ func (c *LmdbCursor) Append(k []byte, v []byte) error { func (c *LmdbCursor) Close() { if c.c != nil { c.c.Close() + l := len(c.tx.cursors) + if l == 0 { + c.c = nil + return + } //TODO: Find a better solution to avoid the leak? - newCursors := make([]*lmdb.Cursor, len(c.tx.cursors)-1) + newCursors := make([]*lmdb.Cursor, l-1) i := 0 for _, cc := range c.tx.cursors { if cc != c.c { diff --git a/ethdb/kv_mdbx.go b/ethdb/kv_mdbx.go index eb5e26447a3936364cf22f370fc2feb334c6f635..b7d8b18d43c5fa5027aaf23699cec270a2d6c30a 100644 --- a/ethdb/kv_mdbx.go +++ b/ethdb/kv_mdbx.go @@ -1375,8 +1375,13 @@ func (c *MdbxCursor) Append(k []byte, v []byte) error { func (c *MdbxCursor) Close() { if c.c != nil { c.c.Close() + l := len(c.tx.cursors) + if l == 0 { + c.c = nil + return + } //TODO: Find a better solution to avoid the leak? - newCursors := make([]*mdbx.Cursor, len(c.tx.cursors)-1) + newCursors := make([]*mdbx.Cursor, l-1) i := 0 for _, cc := range c.tx.cursors { if cc != c.c {