aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2017-08-24 21:17:02 +0800
committerFelix Lange <fjl@twurst.com>2017-08-25 05:51:50 +0800
commitad16aeb0a2e79ef6e9db30667152d73565715391 (patch)
treedda210a8733ab7bbc9d11ab26f57879cd0f00eff /core
parent68955ed2eb12165416411dc30b1ac4d74aa49307 (diff)
downloaddexon-ad16aeb0a2e79ef6e9db30667152d73565715391.tar.gz
dexon-ad16aeb0a2e79ef6e9db30667152d73565715391.tar.zst
dexon-ad16aeb0a2e79ef6e9db30667152d73565715391.zip
core/types: encode receipt status in PostState field
This fixes a regression where the new Failed field in ReceiptForStorage rejected previously stored receipts. Fix it by removing the new field and store status in the PostState field. This also removes massive RLP hackery around the status field.
Diffstat (limited to 'core')
-rw-r--r--core/database_util_test.go4
-rw-r--r--core/types/receipt.go141
2 files changed, 62 insertions, 83 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/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
}