Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion core/rawdb/chain_iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
type blockTxHashes struct {
number uint64
hashes []common.Hash
err error
}

// iterateTransactions iterates over all transactions in the (canon) block
Expand Down Expand Up @@ -144,7 +145,12 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
var body types.Body
if err := rlp.DecodeBytes(data.rlp, &body); err != nil {
log.Warn("Failed to decode block body", "block", data.number, "error", err)
return
select {
case hashesCh <- &blockTxHashes{number: data.number, err: err}:
case <-interrupt:
return
}
continue
}
var hashes []common.Hash
for _, tx := range body.Transactions {
Expand Down Expand Up @@ -211,6 +217,14 @@ func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan
}
// Next block available, pop it off and index it
delivery := queue.PopItem().(*blockTxHashes)
if delivery.err != nil {
log.Warn("Missing or corrupt block body during indexing; aborting run", "block", delivery.number, "err", delivery.err)
WriteTxIndexTail(batch, lastNum)
if err := batch.Write(); err != nil {
log.Crit("Failed writing batch to db", "error", err)
}
return
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
lastNum = delivery.number
Comment thread
coderabbitai[bot] marked this conversation as resolved.
WriteTxLookupEntries(batch, delivery.number, delivery.hashes)
blocks++
Expand Down Expand Up @@ -300,6 +314,10 @@ func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch
}
delivery := queue.PopItem().(*blockTxHashes)
nextNum = delivery.number + 1
if delivery.err != nil {
log.Warn("Block skipped during unindexing; tx lookup entries NOT deleted", "block", delivery.number, "err", delivery.err)
continue
}
DeleteTxLookupEntries(batch, delivery.hashes)
Comment thread
SegueII marked this conversation as resolved.
txs += len(delivery.hashes)
blocks++
Expand Down
160 changes: 160 additions & 0 deletions core/rawdb/chain_iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,163 @@ func TestIndexTransactions(t *testing.T) {
verify(8, 11, true, 8)
verify(0, 8, false, 8)
}

func TestIndexTransactionsMissingBody(t *testing.T) {
chainDb := NewMemoryDatabase()

var txs []*types.Transaction
to := common.BytesToAddress([]byte{0x11})

block := types.NewBlock(&types.Header{Number: big.NewInt(0)}, nil, nil, nil, newHasher())
WriteBlock(chainDb, block)
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())

for i := uint64(1); i <= 10; i++ {
tx := types.NewTx(&types.LegacyTx{
Nonce: i,
GasPrice: big.NewInt(11111),
Gas: 1111,
To: &to,
Value: big.NewInt(111),
Data: []byte{0x11, 0x11, 0x11},
})
txs = append(txs, tx)
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
WriteBlock(chainDb, block)
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
}

missingBlock := uint64(5)
hash := ReadCanonicalHash(chainDb, missingBlock)
DeleteBody(chainDb, hash, missingBlock)

IndexTransactions(chainDb, 0, 11, nil)

// Tail must not advance past the missing block: the last successfully
// indexed block from the top was 6, so tail == 6.
tail := ReadTxIndexTail(chainDb)
if tail == nil || *tail != missingBlock+1 {
t.Fatalf("tx index tail mismatch after index with missing body: got %v, want %d", tail, missingBlock+1)
}
// Blocks above the gap are indexed; blocks at and below are not.
for i := uint64(1); i <= 10; i++ {
number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
if i > missingBlock {
if number == nil {
t.Fatalf("tx index %d missing after indexing (above gap)", i)
}
} else {
if number != nil {
t.Fatalf("tx index %d should not be indexed (at/below gap)", i)
}
}
}
}

func TestUnindexTransactionsMissingBody(t *testing.T) {
chainDb := NewMemoryDatabase()

var txs []*types.Transaction
to := common.BytesToAddress([]byte{0x11})

block := types.NewBlock(&types.Header{Number: big.NewInt(0)}, nil, nil, nil, newHasher())
WriteBlock(chainDb, block)
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())

for i := uint64(1); i <= 10; i++ {
tx := types.NewTx(&types.LegacyTx{
Nonce: i,
GasPrice: big.NewInt(11111),
Gas: 1111,
To: &to,
Value: big.NewInt(111),
Data: []byte{0x11, 0x11, 0x11},
})
txs = append(txs, tx)
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
WriteBlock(chainDb, block)
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
}
IndexTransactions(chainDb, 0, 11, nil)

for i := 1; i <= 10; i++ {
number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
if number == nil {
t.Fatalf("tx index %d missing after indexing", i)
}
}

missingBlock := uint64(5)
hash := ReadCanonicalHash(chainDb, missingBlock)
DeleteBody(chainDb, hash, missingBlock)

UnindexTransactions(chainDb, 0, 11, nil)

tail := ReadTxIndexTail(chainDb)
if tail == nil || *tail != 11 {
t.Fatalf("tx index tail mismatch after unindex with missing body: got %v, want 11", tail)
}
for i := 1; i <= 10; i++ {
number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
if uint64(i) == missingBlock {
continue
}
if number != nil {
t.Fatalf("tx index %d should be deleted after unindexing", i)
}
}
}

func TestUnindexTransactionsCorruptBody(t *testing.T) {
chainDb := NewMemoryDatabase()

var txs []*types.Transaction
to := common.BytesToAddress([]byte{0x11})

block := types.NewBlock(&types.Header{Number: big.NewInt(0)}, nil, nil, nil, newHasher())
WriteBlock(chainDb, block)
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())

for i := uint64(1); i <= 10; i++ {
tx := types.NewTx(&types.LegacyTx{
Nonce: i,
GasPrice: big.NewInt(11111),
Gas: 1111,
To: &to,
Value: big.NewInt(111),
Data: []byte{0x11, 0x11, 0x11},
})
txs = append(txs, tx)
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
WriteBlock(chainDb, block)
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
}
IndexTransactions(chainDb, 0, 11, nil)

for i := 1; i <= 10; i++ {
number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
if number == nil {
t.Fatalf("tx index %d missing after indexing", i)
}
}

corruptBlock := uint64(5)
hash := ReadCanonicalHash(chainDb, corruptBlock)
WriteBodyRLP(chainDb, hash, corruptBlock, []byte{0xff})

UnindexTransactions(chainDb, 0, 11, nil)

tail := ReadTxIndexTail(chainDb)
if tail == nil || *tail != 11 {
t.Fatalf("tx index tail mismatch after unindex with corrupt body: got %v, want 11", tail)
}
for i := 1; i <= 10; i++ {
number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
if uint64(i) == corruptBlock {
continue
}
if number != nil {
t.Fatalf("tx index %d should be deleted after unindexing", i)
}
}
}
12 changes: 6 additions & 6 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ func (tx *Transaction) FeeTokenID() uint16 {

func (tx *Transaction) FeeLimit() *big.Int {
if !tx.IsMorphTx() {
return big.NewInt(0)
return nil
}
return tx.AsMorphTx().FeeLimit
}
Expand Down Expand Up @@ -912,9 +912,9 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
msg := Message{
nonce: tx.Nonce(),
gasLimit: tx.Gas(),
gasPrice: new(big.Int).Set(tx.GasPrice()),
gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
gasTipCap: new(big.Int).Set(tx.GasTipCap()),
gasPrice: tx.GasPrice(),
gasFeeCap: tx.GasFeeCap(),
gasTipCap: tx.GasTipCap(),
to: tx.To(),
amount: tx.Value(),
data: tx.Data(),
Expand All @@ -936,8 +936,8 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
return Message{}, err
}

if tx.FeeLimit() != nil {
msg.feeLimit = tx.FeeLimit()
if fl := tx.FeeLimit(); fl != nil {
msg.feeLimit = new(big.Int).Set(fl)
}

var err error
Expand Down
20 changes: 13 additions & 7 deletions core/types/transaction_signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,10 @@ func (s *modernSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *bi
if tx.inner.chainID().Sign() != 0 && tx.inner.chainID().Cmp(s.chainID) != 0 {
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.inner.chainID(), s.chainID)
}
R, S, _ = decodeSignature(sig)
R, S, _, err = decodeSignature(sig)
if err != nil {
return nil, nil, nil, err
}
V = big.NewInt(int64(sig[64]))
return R, S, V, nil
}
Expand Down Expand Up @@ -383,7 +386,10 @@ func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
if tx.Type() != LegacyTxType {
return nil, nil, nil, ErrTxTypeNotSupported
}
R, S, V = decodeSignature(sig)
R, S, V, err = decodeSignature(sig)
if err != nil {
return nil, nil, nil, err
}
if s.chainId.Sign() != 0 {
V = big.NewInt(int64(sig[64] + 35))
V.Add(V, s.chainIdMul)
Expand Down Expand Up @@ -457,8 +463,8 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *
if tx.Type() != LegacyTxType {
return nil, nil, nil, ErrTxTypeNotSupported
}
r, s, v = decodeSignature(sig)
return r, s, v, nil
r, s, v, err = decodeSignature(sig)
return r, s, v, err
}

// Hash returns the hash to be signed by the sender.
Expand All @@ -474,14 +480,14 @@ func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
})
}

func decodeSignature(sig []byte) (r, s, v *big.Int) {
func decodeSignature(sig []byte) (r, s, v *big.Int, err error) {
if len(sig) != crypto.SignatureLength {
panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength))
return nil, nil, nil, fmt.Errorf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength)
}
r = new(big.Int).SetBytes(sig[:32])
s = new(big.Int).SetBytes(sig[32:64])
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
return r, s, v
return r, s, v, nil
}

func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
Expand Down
52 changes: 52 additions & 0 deletions core/types/transaction_signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,55 @@ func TestChainId(t *testing.T) {
t.Error("expected no error")
}
}

func TestSignatureValuesError(t *testing.T) {
tx := NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil)
signer := HomesteadSigner{}

tests := []struct {
name string
sig []byte
}{
{name: "empty", sig: nil},
{name: "short", sig: make([]byte, 64)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("Panicked for invalid signature length, expected error: %v", r)
}
}()
_, err := tx.WithSignature(signer, tt.sig)
if err == nil {
t.Fatal("Expected error for invalid signature length, got nil")
}
t.Logf("Got expected error: %v", err)
})
}
}

func TestSignSetCode(t *testing.T) {
key, _ := defaultTestKey()
auth := SetCodeAuthorization{
Address: common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678"),
Nonce: 7,
}

signed, err := SignSetCode(key, auth)
if err != nil {
t.Fatalf("SignSetCode returned error: %v", err)
}
if signed.Address != auth.Address {
t.Fatalf("address mismatch: have %s want %s", signed.Address, auth.Address)
}
if signed.Nonce != auth.Nonce {
t.Fatalf("nonce mismatch: have %d want %d", signed.Nonce, auth.Nonce)
}
if signed.R.IsZero() || signed.S.IsZero() {
t.Fatal("expected non-zero signature values")
}
if signed.V > 1 {
t.Fatalf("unexpected y parity: %d", signed.V)
}
}
Loading
Loading