diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 16c8808360..7de1eb6949 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -304,7 +304,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash(), vmContext.BlockNumber.Uint64(), blockHash) - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.Bloom = types.CreateBloom(receipt) + // These three are non-consensus fields: //receipt.BlockHash //receipt.BlockNumber @@ -376,7 +377,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, StateRoot: root, TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)), ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)), - Bloom: types.CreateBloom(receipts), + Bloom: types.MergeBloom(receipts), LogsHash: rlpHash(statedb.Logs()), Receipts: receipts, Rejected: rejectedTxs, diff --git a/core/block_validator.go b/core/block_validator.go index 5885df9ee2..591e472bc1 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -129,7 +129,11 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. - rbloom := types.CreateBloom(res.Receipts) + // + // Receipts must go through MakeReceipt to calculate the receipt's bloom + // already. Merge the receipt's bloom together instead of recalculating + // everything. + rbloom := types.MergeBloom(res.Receipts) if rbloom != header.Bloom { return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index b9684f8e17..efd16d5fa7 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -338,7 +338,7 @@ func TestBlockReceiptStorage(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), GasUsed: 111111, } - receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) + receipt1.Bloom = types.CreateBloom(receipt1) receipt2 := &types.Receipt{ PostState: common.Hash{2}.Bytes(), @@ -351,7 +351,7 @@ func TestBlockReceiptStorage(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), GasUsed: 222222, } - receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) + receipt2.Bloom = types.CreateBloom(receipt2) receipts := []*types.Receipt{receipt1, receipt2} // Check that no receipt entries are in a pristine database @@ -679,7 +679,7 @@ func TestReadLogs(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), GasUsed: 111111, } - receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) + receipt1.Bloom = types.CreateBloom(receipt1) receipt2 := &types.Receipt{ PostState: common.Hash{2}.Bytes(), @@ -692,7 +692,7 @@ func TestReadLogs(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), GasUsed: 222222, } - receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) + receipt2.Bloom = types.CreateBloom(receipt2) receipts := []*types.Receipt{receipt1, receipt2} hash := common.BytesToHash([]byte{0x03, 0x14}) diff --git a/core/state_processor.go b/core/state_processor.go index 902ff582e8..2c74f6f407 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -189,7 +189,7 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.Bloom = types.CreateBloom(receipt) receipt.BlockHash = blockHash receipt.BlockNumber = blockNumber receipt.TransactionIndex = uint(statedb.TxIndex()) diff --git a/core/types/block.go b/core/types/block.go index c3db4d89e8..b284fb3b16 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -237,6 +237,9 @@ type extblock struct { // // The body elements and the receipts are used to recompute and overwrite the // relevant portions of the header. +// +// The receipt's bloom must already calculated for the block's bloom to be +// correctly calculated. func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher) *Block { if body == nil { body = &Body{} @@ -260,7 +263,10 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher b.header.ReceiptHash = EmptyReceiptsHash } else { b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher) - b.header.Bloom = CreateBloom(receipts) + // Receipts must go through MakeReceipt to calculate the receipt's bloom + // already. Merge the receipt's bloom together instead of recalculating + // everything. + b.header.Bloom = MergeBloom(receipts) } if len(uncles) == 0 { diff --git a/core/types/bloom9.go b/core/types/bloom9.go index a560a20724..962ba46d47 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -100,32 +100,35 @@ func (b *Bloom) UnmarshalText(input []byte) error { return hexutil.UnmarshalFixedText("Bloom", input, b[:]) } -// CreateBloom creates a bloom filter out of the give Receipts (+Logs) -func CreateBloom(receipts Receipts) Bloom { - buf := make([]byte, 6) - var bin Bloom - for _, receipt := range receipts { - for _, log := range receipt.Logs { - bin.add(log.Address.Bytes(), buf) - for _, b := range log.Topics { - bin.add(b[:], buf) - } +// CreateBloom creates a bloom filter out of the give Receipt (+Logs) +func CreateBloom(receipt *Receipt) Bloom { + var ( + bin Bloom + buf = make([]byte, 6) + ) + for _, log := range receipt.Logs { + bin.add(log.Address.Bytes(), buf) + for _, b := range log.Topics { + bin.add(b[:], buf) } } return bin } -// LogsBloom returns the bloom bytes for the given logs -func LogsBloom(logs []*Log) []byte { - buf := make([]byte, 6) +// MergeBloom merges the precomputed bloom filters in the Receipts without +// recalculating them. It assumes that each receipt’s Bloom field is already +// correctly populated. +func MergeBloom(receipts Receipts) Bloom { var bin Bloom - for _, log := range logs { - bin.add(log.Address.Bytes(), buf) - for _, b := range log.Topics { - bin.add(b[:], buf) + for _, receipt := range receipts { + if len(receipt.Logs) != 0 { + bl := receipt.Bloom.Bytes() + for i := range bin { + bin[i] |= bl[i] + } } } - return bin[:] + return bin } // Bloom9 returns the bloom filter for the given data diff --git a/core/types/bloom9_test.go b/core/types/bloom9_test.go index d3178d112e..07f6446a97 100644 --- a/core/types/bloom9_test.go +++ b/core/types/bloom9_test.go @@ -126,26 +126,70 @@ func BenchmarkCreateBloom(b *testing.B) { for i := 0; i < 200; i += 2 { copy(rLarge[i:], rSmall) } - b.Run("small", func(b *testing.B) { + b.Run("small-createbloom", func(b *testing.B) { b.ReportAllocs() + for i := 0; i < b.N; i++ { + for _, receipt := range rSmall { + receipt.Bloom = CreateBloom(receipt) + } + } + b.StopTimer() + + bl := MergeBloom(rSmall) + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") + got := crypto.Keccak256Hash(bl.Bytes()) + if got != exp { + b.Errorf("Got %x, exp %x", got, exp) + } + }) + b.Run("large-createbloom", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + for _, receipt := range rLarge { + receipt.Bloom = CreateBloom(receipt) + } + } + b.StopTimer() + + bl := MergeBloom(rLarge) + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") + got := crypto.Keccak256Hash(bl.Bytes()) + if got != exp { + b.Errorf("Got %x, exp %x", got, exp) + } + }) + b.Run("small-mergebloom", func(b *testing.B) { + for _, receipt := range rSmall { + receipt.Bloom = CreateBloom(receipt) + } + b.ReportAllocs() + b.ResetTimer() + var bl Bloom for i := 0; i < b.N; i++ { - bl = CreateBloom(rSmall) + bl = MergeBloom(rSmall) } b.StopTimer() + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") got := crypto.Keccak256Hash(bl.Bytes()) if got != exp { b.Errorf("Got %x, exp %x", got, exp) } }) - b.Run("large", func(b *testing.B) { + b.Run("large-mergebloom", func(b *testing.B) { + for _, receipt := range rLarge { + receipt.Bloom = CreateBloom(receipt) + } b.ReportAllocs() + b.ResetTimer() + var bl Bloom for i := 0; i < b.N; i++ { - bl = CreateBloom(rLarge) + bl = MergeBloom(rLarge) } b.StopTimer() + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") got := crypto.Keccak256Hash(bl.Bytes()) if got != exp { diff --git a/core/types/receipt.go b/core/types/receipt.go index 47f16d950a..e52a0c6477 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -291,7 +291,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { } r.CumulativeGasUsed = stored.CumulativeGasUsed r.Logs = stored.Logs - r.Bloom = CreateBloom(Receipts{(*Receipt)(r)}) + r.Bloom = CreateBloom((*Receipt)(r)) return nil } diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index fc51eb11a5..78b43c7e49 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -394,7 +394,7 @@ func TestTypedReceiptEncodingDecoding(t *testing.T) { func TestReceiptMarshalBinary(t *testing.T) { // Legacy Receipt - legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt}) + legacyReceipt.Bloom = CreateBloom(legacyReceipt) have, err := legacyReceipt.MarshalBinary() if err != nil { t.Fatalf("marshal binary error: %v", err) @@ -421,7 +421,7 @@ func TestReceiptMarshalBinary(t *testing.T) { // 2930 Receipt buf.Reset() - accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt}) + accessListReceipt.Bloom = CreateBloom(accessListReceipt) have, err = accessListReceipt.MarshalBinary() if err != nil { t.Fatalf("marshal binary error: %v", err) @@ -439,7 +439,7 @@ func TestReceiptMarshalBinary(t *testing.T) { // 1559 Receipt buf.Reset() - eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt}) + eip1559Receipt.Bloom = CreateBloom(eip1559Receipt) have, err = eip1559Receipt.MarshalBinary() if err != nil { t.Fatalf("marshal binary error: %v", err) @@ -463,7 +463,7 @@ func TestReceiptUnmarshalBinary(t *testing.T) { if err := gotLegacyReceipt.UnmarshalBinary(legacyBinary); err != nil { t.Fatalf("unmarshal binary error: %v", err) } - legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt}) + legacyReceipt.Bloom = CreateBloom(legacyReceipt) if !reflect.DeepEqual(gotLegacyReceipt, legacyReceipt) { t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotLegacyReceipt, legacyReceipt) } @@ -474,7 +474,7 @@ func TestReceiptUnmarshalBinary(t *testing.T) { if err := gotAccessListReceipt.UnmarshalBinary(accessListBinary); err != nil { t.Fatalf("unmarshal binary error: %v", err) } - accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt}) + accessListReceipt.Bloom = CreateBloom(accessListReceipt) if !reflect.DeepEqual(gotAccessListReceipt, accessListReceipt) { t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotAccessListReceipt, accessListReceipt) } @@ -485,7 +485,7 @@ func TestReceiptUnmarshalBinary(t *testing.T) { if err := got1559Receipt.UnmarshalBinary(eip1559RctBinary); err != nil { t.Fatalf("unmarshal binary error: %v", err) } - eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt}) + eip1559Receipt.Bloom = CreateBloom(eip1559Receipt) if !reflect.DeepEqual(got1559Receipt, eip1559Receipt) { t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", got1559Receipt, eip1559Receipt) } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 6a3057326d..e2790d91eb 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -42,7 +42,7 @@ func makeReceipt(addr common.Address) *types.Receipt { receipt.Logs = []*types.Log{ {Address: addr}, } - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.Bloom = types.CreateBloom(receipt) return receipt }