core/rawdb: fix transaction indexing/unindexing hashing error (#22457)
* core/rawdb: more verbose error logs + better hashing * core/rawdb: add failing testcase * core/rawdb: properly hash transactions while indexing/unindexing * core/rawdb: exit on error + better log msg
This commit is contained in:
parent
7cbf1d70a7
commit
94ab4ea341
@ -23,10 +23,10 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitDatabaseFromFreezer reinitializes an empty database from a previous batch
|
// InitDatabaseFromFreezer reinitializes an empty database from a previous batch
|
||||||
@ -135,32 +135,15 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
|
|||||||
close(hashesCh)
|
close(hashesCh)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var hasher = sha3.NewLegacyKeccak256()
|
|
||||||
for data := range rlpCh {
|
for data := range rlpCh {
|
||||||
it, err := rlp.NewListIterator(data.rlp)
|
var body types.Body
|
||||||
if err != nil {
|
if err := rlp.DecodeBytes(data.rlp, &body); err != nil {
|
||||||
log.Warn("tx iteration error", "error", err)
|
log.Warn("Failed to decode block body", "block", data.number, "error", err)
|
||||||
return
|
|
||||||
}
|
|
||||||
it.Next()
|
|
||||||
txs := it.Value()
|
|
||||||
txIt, err := rlp.NewListIterator(txs)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("tx iteration error", "error", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var hashes []common.Hash
|
var hashes []common.Hash
|
||||||
for txIt.Next() {
|
for _, tx := range body.Transactions {
|
||||||
if err := txIt.Err(); err != nil {
|
hashes = append(hashes, tx.Hash())
|
||||||
log.Warn("tx iteration error", "error", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var txHash common.Hash
|
|
||||||
hasher.Reset()
|
|
||||||
hasher.Write(txIt.Value())
|
|
||||||
hasher.Sum(txHash[:0])
|
|
||||||
hashes = append(hashes, txHash)
|
|
||||||
}
|
}
|
||||||
result := &blockTxHashes{
|
result := &blockTxHashes{
|
||||||
hashes: hashes,
|
hashes: hashes,
|
||||||
|
@ -33,14 +33,34 @@ func TestChainIterator(t *testing.T) {
|
|||||||
|
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
var txs []*types.Transaction
|
var txs []*types.Transaction
|
||||||
for i := uint64(0); i <= 10; i++ {
|
to := common.BytesToAddress([]byte{0x11})
|
||||||
if i == 0 {
|
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newHasher()) // Empty genesis block
|
||||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, nil, nil, nil, newHasher()) // Empty genesis block
|
WriteBlock(chainDb, block)
|
||||||
|
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||||
|
for i := uint64(1); i <= 10; i++ {
|
||||||
|
var tx *types.Transaction
|
||||||
|
if i%2 == 0 {
|
||||||
|
tx = types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: i,
|
||||||
|
GasPrice: big.NewInt(11111),
|
||||||
|
Gas: 1111,
|
||||||
|
To: &to,
|
||||||
|
Value: big.NewInt(111),
|
||||||
|
Data: []byte{0x11, 0x11, 0x11},
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
tx := types.NewTransaction(i, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
|
tx = types.NewTx(&types.AccessListTx{
|
||||||
|
ChainID: big.NewInt(1337),
|
||||||
|
Nonce: i,
|
||||||
|
GasPrice: big.NewInt(11111),
|
||||||
|
Gas: 1111,
|
||||||
|
To: &to,
|
||||||
|
Value: big.NewInt(111),
|
||||||
|
Data: []byte{0x11, 0x11, 0x11},
|
||||||
|
})
|
||||||
|
}
|
||||||
txs = append(txs, tx)
|
txs = append(txs, tx)
|
||||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
|
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
|
||||||
}
|
|
||||||
WriteBlock(chainDb, block)
|
WriteBlock(chainDb, block)
|
||||||
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||||
}
|
}
|
||||||
@ -66,7 +86,7 @@ func TestChainIterator(t *testing.T) {
|
|||||||
numbers = append(numbers, int(h.number))
|
numbers = append(numbers, int(h.number))
|
||||||
if len(h.hashes) > 0 {
|
if len(h.hashes) > 0 {
|
||||||
if got, exp := h.hashes[0], txs[h.number-1].Hash(); got != exp {
|
if got, exp := h.hashes[0], txs[h.number-1].Hash(); got != exp {
|
||||||
t.Fatalf("hash wrong, got %x exp %x", got, exp)
|
t.Fatalf("block %d: hash wrong, got %x exp %x", h.number, got, exp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,14 +108,37 @@ func TestIndexTransactions(t *testing.T) {
|
|||||||
|
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
var txs []*types.Transaction
|
var txs []*types.Transaction
|
||||||
for i := uint64(0); i <= 10; i++ {
|
to := common.BytesToAddress([]byte{0x11})
|
||||||
if i == 0 {
|
|
||||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, nil, nil, nil, newHasher()) // Empty genesis block
|
// Write empty genesis block
|
||||||
|
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newHasher())
|
||||||
|
WriteBlock(chainDb, block)
|
||||||
|
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||||
|
|
||||||
|
for i := uint64(1); i <= 10; i++ {
|
||||||
|
var tx *types.Transaction
|
||||||
|
if i%2 == 0 {
|
||||||
|
tx = types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: i,
|
||||||
|
GasPrice: big.NewInt(11111),
|
||||||
|
Gas: 1111,
|
||||||
|
To: &to,
|
||||||
|
Value: big.NewInt(111),
|
||||||
|
Data: []byte{0x11, 0x11, 0x11},
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
tx := types.NewTransaction(i, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
|
tx = types.NewTx(&types.AccessListTx{
|
||||||
|
ChainID: big.NewInt(1337),
|
||||||
|
Nonce: i,
|
||||||
|
GasPrice: big.NewInt(11111),
|
||||||
|
Gas: 1111,
|
||||||
|
To: &to,
|
||||||
|
Value: big.NewInt(111),
|
||||||
|
Data: []byte{0x11, 0x11, 0x11},
|
||||||
|
})
|
||||||
|
}
|
||||||
txs = append(txs, tx)
|
txs = append(txs, tx)
|
||||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
|
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
|
||||||
}
|
|
||||||
WriteBlock(chainDb, block)
|
WriteBlock(chainDb, block)
|
||||||
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||||
}
|
}
|
||||||
@ -108,10 +151,10 @@ func TestIndexTransactions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
|
number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
|
||||||
if exist && number == nil {
|
if exist && number == nil {
|
||||||
t.Fatalf("Transaction indice missing")
|
t.Fatalf("Transaction index %d missing", i)
|
||||||
}
|
}
|
||||||
if !exist && number != nil {
|
if !exist && number != nil {
|
||||||
t.Fatalf("Transaction indice is not deleted")
|
t.Fatalf("Transaction index %d is not deleted", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
number := ReadTxIndexTail(chainDb)
|
number := ReadTxIndexTail(chainDb)
|
||||||
|
@ -23,6 +23,7 @@ type listIterator struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewListIterator creates an iterator for the (list) represented by data
|
// NewListIterator creates an iterator for the (list) represented by data
|
||||||
|
// TODO: Consider removing this implementation, as it is no longer used.
|
||||||
func NewListIterator(data RawValue) (*listIterator, error) {
|
func NewListIterator(data RawValue) (*listIterator, error) {
|
||||||
k, t, c, err := readKind(data)
|
k, t, c, err := readKind(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user