aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/database_util_test.go4
-rw-r--r--core/state/journal.go5
-rw-r--r--core/state/statedb.go69
-rw-r--r--core/state_processor.go2
-rw-r--r--core/types/receipt.go141
-rw-r--r--core/types/transaction.go2
-rw-r--r--rlp/decode.go2
-rw-r--r--rlp/decode_test.go35
-rw-r--r--tests/block_test.go1
9 files changed, 117 insertions, 144 deletions
diff --git a/core/database_util_test.go b/core/database_util_test.go
index 5c75d53d0..e91f1b593 100644
--- a/core/database_util_test.go
+++ b/core/database_util_test.go
@@ -340,7 +340,7 @@ func TestBlockReceiptStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
receipt1 := &types.Receipt{
- PostState: []byte{0x01},
+ Failed: true,
CumulativeGasUsed: big.NewInt(1),
Logs: []*types.Log{
{Address: common.BytesToAddress([]byte{0x11})},
@@ -351,7 +351,7 @@ func TestBlockReceiptStorage(t *testing.T) {
GasUsed: big.NewInt(111111),
}
receipt2 := &types.Receipt{
- PostState: []byte{0x02},
+ PostState: common.Hash{2}.Bytes(),
CumulativeGasUsed: big.NewInt(2),
Logs: []*types.Log{
{Address: common.BytesToAddress([]byte{0x22})},
diff --git a/core/state/journal.go b/core/state/journal.go
index b5c8ca9a2..ddb76f1a2 100644
--- a/core/state/journal.go
+++ b/core/state/journal.go
@@ -91,11 +91,6 @@ func (ch suicideChange) undo(s *StateDB) {
if obj != nil {
obj.suicided = ch.prev
obj.setBalance(ch.prevbalance)
- // if the object wasn't suicided before, remove
- // it from the list of destructed objects as well.
- if !obj.suicided {
- delete(s.stateObjectsDestructed, *ch.account)
- }
}
}
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 694374f82..002fa6249 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -46,9 +46,8 @@ type StateDB struct {
trie Trie
// This map holds 'live' objects, which will get modified while processing a state transition.
- stateObjects map[common.Address]*stateObject
- stateObjectsDirty map[common.Address]struct{}
- stateObjectsDestructed map[common.Address]struct{}
+ stateObjects map[common.Address]*stateObject
+ stateObjectsDirty map[common.Address]struct{}
// DB error.
// State objects are used by the consensus core and VM which are
@@ -83,14 +82,13 @@ func New(root common.Hash, db Database) (*StateDB, error) {
return nil, err
}
return &StateDB{
- db: db,
- trie: tr,
- stateObjects: make(map[common.Address]*stateObject),
- stateObjectsDirty: make(map[common.Address]struct{}),
- stateObjectsDestructed: make(map[common.Address]struct{}),
- refund: new(big.Int),
- logs: make(map[common.Hash][]*types.Log),
- preimages: make(map[common.Hash][]byte),
+ db: db,
+ trie: tr,
+ stateObjects: make(map[common.Address]*stateObject),
+ stateObjectsDirty: make(map[common.Address]struct{}),
+ refund: new(big.Int),
+ logs: make(map[common.Hash][]*types.Log),
+ preimages: make(map[common.Hash][]byte),
}, nil
}
@@ -115,7 +113,6 @@ func (self *StateDB) Reset(root common.Hash) error {
self.trie = tr
self.stateObjects = make(map[common.Address]*stateObject)
self.stateObjectsDirty = make(map[common.Address]struct{})
- self.stateObjectsDestructed = make(map[common.Address]struct{})
self.thash = common.Hash{}
self.bhash = common.Hash{}
self.txIndex = 0
@@ -323,7 +320,6 @@ func (self *StateDB) Suicide(addr common.Address) bool {
})
stateObject.markSuicided()
stateObject.data.Balance = new(big.Int)
- self.stateObjectsDestructed[addr] = struct{}{}
return true
}
@@ -456,23 +452,19 @@ func (self *StateDB) Copy() *StateDB {
// Copy all the basic fields, initialize the memory ones
state := &StateDB{
- db: self.db,
- trie: self.trie,
- stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)),
- stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
- stateObjectsDestructed: make(map[common.Address]struct{}, len(self.stateObjectsDestructed)),
- refund: new(big.Int).Set(self.refund),
- logs: make(map[common.Hash][]*types.Log, len(self.logs)),
- logSize: self.logSize,
- preimages: make(map[common.Hash][]byte),
+ db: self.db,
+ trie: self.trie,
+ stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)),
+ stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
+ refund: new(big.Int).Set(self.refund),
+ logs: make(map[common.Hash][]*types.Log, len(self.logs)),
+ logSize: self.logSize,
+ preimages: make(map[common.Hash][]byte),
}
// Copy the dirty states, logs, and preimages
for addr := range self.stateObjectsDirty {
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty)
state.stateObjectsDirty[addr] = struct{}{}
- if self.stateObjects[addr].suicided {
- state.stateObjectsDestructed[addr] = struct{}{}
- }
}
for hash, logs := range self.logs {
state.logs[hash] = make([]*types.Log, len(logs))
@@ -520,10 +512,9 @@ func (self *StateDB) GetRefund() *big.Int {
return self.refund
}
-// IntermediateRoot computes the current root hash of the state trie.
-// It is called in between transactions to get the root hash that
-// goes into transaction receipts.
-func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
+// Finalise finalises the state by removing the self destructed objects
+// and clears the journal as well as the refunds.
+func (s *StateDB) Finalise(deleteEmptyObjects bool) {
for addr := range s.stateObjectsDirty {
stateObject := s.stateObjects[addr]
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
@@ -535,6 +526,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
}
// Invalidate journal because reverting across transactions is not allowed.
s.clearJournalAndRefund()
+}
+
+// IntermediateRoot computes the current root hash of the state trie.
+// It is called in between transactions to get the root hash that
+// goes into transaction receipts.
+func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
+ s.Finalise(deleteEmptyObjects)
return s.trie.Hash()
}
@@ -546,19 +544,6 @@ func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) {
self.txIndex = ti
}
-// Finalise finalises the state by removing the self destructed objects
-// in the current stateObjectsDestructed buffer and clears the journal
-// as well as the refunds.
-//
-// Please note that Finalise is used by EIP#98 and is used instead of
-// IntermediateRoot.
-func (s *StateDB) Finalise() {
- for addr := range s.stateObjectsDestructed {
- s.deleteStateObject(s.stateObjects[addr])
- }
- s.clearJournalAndRefund()
-}
-
// DeleteSuicides flags the suicided objects for deletion so that it
// won't be referenced again when called / queried up on.
//
diff --git a/core/state_processor.go b/core/state_processor.go
index a4b554b10..4115eab8c 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -106,7 +106,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
// Update the state with pending changes
var root []byte
if config.IsMetropolis(header.Number) {
- statedb.Finalise()
+ statedb.Finalise(true)
} else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index b54bd7b4f..4f3b7357e 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -17,6 +17,7 @@
package types
import (
+ "bytes"
"fmt"
"io"
"math/big"
@@ -28,9 +29,9 @@ import (
//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
-const (
- receiptStatusSuccessful = byte(0x01)
- receiptStatusFailed = byte(0x00)
+var (
+ receiptStatusFailed = []byte{}
+ receiptStatusSuccessful = []byte{0x01}
)
// Receipt represents the results of a transaction.
@@ -54,22 +55,22 @@ type receiptMarshaling struct {
GasUsed *hexutil.Big
}
-// homesteadReceiptRLP contains the receipt's Homestead consensus fields, used
-// during RLP serialization.
-type homesteadReceiptRLP struct {
- PostState []byte
+// receiptRLP is the consensus encoding of a receipt.
+type receiptRLP struct {
+ PostStateOrStatus []byte
CumulativeGasUsed *big.Int
Bloom Bloom
Logs []*Log
}
-// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used
-// during RLP serialization.
-type metropolisReceiptRLP struct {
- Status byte
+type receiptStorageRLP struct {
+ PostStateOrStatus []byte
CumulativeGasUsed *big.Int
Bloom Bloom
- Logs []*Log
+ TxHash common.Hash
+ ContractAddress common.Address
+ Logs []*LogForStorage
+ GasUsed *big.Int
}
// NewReceipt creates a barebone transaction receipt, copying the init fields.
@@ -80,69 +81,46 @@ func NewReceipt(root []byte, failed bool, cumulativeGasUsed *big.Int) *Receipt {
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
// into an RLP stream. If no post state is present, metropolis fork is assumed.
func (r *Receipt) EncodeRLP(w io.Writer) error {
- if r.PostState == nil {
- status := receiptStatusSuccessful
- if r.Failed {
- status = receiptStatusFailed
- }
- return rlp.Encode(w, &metropolisReceiptRLP{status, r.CumulativeGasUsed, r.Bloom, r.Logs})
- }
- return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
+ return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs})
}
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
// from an RLP stream.
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
- // Load the raw bytes since we have multiple possible formats
- raw, err := s.Raw()
- if err != nil {
+ var dec receiptRLP
+ if err := s.Decode(&dec); err != nil {
return err
}
- content, _, err := rlp.SplitList(raw)
- if err != nil {
+ if err := r.setStatus(dec.PostStateOrStatus); err != nil {
return err
}
- kind, cnt, _, err := rlp.Split(content)
- if err != nil {
- return err
- }
- // Deserialize based on the first component type.
- switch {
- case kind == rlp.Byte || (kind == rlp.String && len(cnt) == 0):
- // The first component of metropolis receipts is Byte (0x01), or the empty
- // string (0x80, decoded as a byte with 0x00 value).
- var metro metropolisReceiptRLP
- if err := rlp.DecodeBytes(raw, &metro); err != nil {
- return err
- }
- switch metro.Status {
- case receiptStatusSuccessful:
- r.Failed = false
- case receiptStatusFailed:
- r.Failed = true
- default:
- return fmt.Errorf("invalid status byte: 0x%x", metro.Status)
- }
- r.CumulativeGasUsed = metro.CumulativeGasUsed
- r.Bloom = metro.Bloom
- r.Logs = metro.Logs
- return nil
-
- case kind == rlp.String:
- // The first component of homestead receipts is non-empty String.
- var home homesteadReceiptRLP
- if err := rlp.DecodeBytes(raw, &home); err != nil {
- return err
- }
- r.PostState = home.PostState[:]
- r.CumulativeGasUsed = home.CumulativeGasUsed
- r.Bloom = home.Bloom
- r.Logs = home.Logs
- return nil
+ r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs
+ return nil
+}
+func (r *Receipt) setStatus(postStateOrStatus []byte) error {
+ switch {
+ case bytes.Equal(postStateOrStatus, receiptStatusSuccessful):
+ r.Failed = false
+ case bytes.Equal(postStateOrStatus, receiptStatusFailed):
+ r.Failed = true
+ case len(postStateOrStatus) == len(common.Hash{}):
+ r.PostState = postStateOrStatus
default:
- return fmt.Errorf("invalid first receipt component: %v", kind)
+ return fmt.Errorf("invalid receipt status %x", postStateOrStatus)
}
+ return nil
+}
+
+func (r *Receipt) statusEncoding() []byte {
+ if len(r.PostState) == 0 {
+ if r.Failed {
+ return receiptStatusFailed
+ } else {
+ return receiptStatusSuccessful
+ }
+ }
+ return r.PostState
}
// String implements the Stringer interface.
@@ -160,38 +138,39 @@ type ReceiptForStorage Receipt
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
// into an RLP stream.
func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
- logs := make([]*LogForStorage, len(r.Logs))
+ enc := &receiptStorageRLP{
+ PostStateOrStatus: (*Receipt)(r).statusEncoding(),
+ CumulativeGasUsed: r.CumulativeGasUsed,
+ Bloom: r.Bloom,
+ TxHash: r.TxHash,
+ ContractAddress: r.ContractAddress,
+ Logs: make([]*LogForStorage, len(r.Logs)),
+ GasUsed: r.GasUsed,
+ }
for i, log := range r.Logs {
- logs[i] = (*LogForStorage)(log)
+ enc.Logs[i] = (*LogForStorage)(log)
}
- return rlp.Encode(w, []interface{}{r.PostState, r.Failed, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
+ return rlp.Encode(w, enc)
}
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
// fields of a receipt from an RLP stream.
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
- var receipt struct {
- PostState []byte
- Failed bool
- CumulativeGasUsed *big.Int
- Bloom Bloom
- TxHash common.Hash
- ContractAddress common.Address
- Logs []*LogForStorage
- GasUsed *big.Int
+ var dec receiptStorageRLP
+ if err := s.Decode(&dec); err != nil {
+ return err
}
- if err := s.Decode(&receipt); err != nil {
+ if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil {
return err
}
// Assign the consensus fields
- r.PostState, r.Failed, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.Failed, receipt.CumulativeGasUsed, receipt.Bloom
- r.Logs = make([]*Log, len(receipt.Logs))
- for i, log := range receipt.Logs {
+ r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom
+ r.Logs = make([]*Log, len(dec.Logs))
+ for i, log := range dec.Logs {
r.Logs[i] = (*Log)(log)
}
// Assign the implementation fields
- r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed
-
+ r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
return nil
}
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 8e108b2a3..947fc85d6 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -300,7 +300,7 @@ func (tx *Transaction) String() string {
Hex: %x
`,
tx.Hash(),
- len(tx.data.Recipient) == 0,
+ tx.data.Recipient == nil,
from,
to,
tx.data.AccountNonce,
diff --git a/rlp/decode.go b/rlp/decode.go
index 78ccf6275..60d9dab2b 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -693,7 +693,7 @@ func (s *Stream) Raw() ([]byte, error) {
return nil, err
}
if kind == String {
- puthead(buf, 0x80, 0xB8, size)
+ puthead(buf, 0x80, 0xB7, size)
} else {
puthead(buf, 0xC0, 0xF7, size)
}
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index d762e195d..4d8abd001 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -256,16 +256,31 @@ func TestStreamList(t *testing.T) {
}
func TestStreamRaw(t *testing.T) {
- s := NewStream(bytes.NewReader(unhex("C58401010101")), 0)
- s.List()
-
- want := unhex("8401010101")
- raw, err := s.Raw()
- if err != nil {
- t.Fatal(err)
- }
- if !bytes.Equal(want, raw) {
- t.Errorf("raw mismatch: got %x, want %x", raw, want)
+ tests := []struct {
+ input string
+ output string
+ }{
+ {
+ "C58401010101",
+ "8401010101",
+ },
+ {
+ "F842B84001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101",
+ "B84001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101",
+ },
+ }
+ for i, tt := range tests {
+ s := NewStream(bytes.NewReader(unhex(tt.input)), 0)
+ s.List()
+
+ want := unhex(tt.output)
+ raw, err := s.Raw()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(want, raw) {
+ t.Errorf("test %d: raw mismatch: got %x, want %x", i, raw, want)
+ }
}
}
diff --git a/tests/block_test.go b/tests/block_test.go
index 066f28034..56e1e1e8d 100644
--- a/tests/block_test.go
+++ b/tests/block_test.go
@@ -37,7 +37,6 @@ func TestBlockchain(t *testing.T) {
// Still failing tests
bt.skipLoad(`^bcWalletTest.*_Byzantium$`)
- bt.skipLoad(`^bcStateTests/suicideCoinbase.json.*_Byzantium$`)
bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
if err := bt.checkFailure(t, name, test.Run()); err != nil {