Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tx Encoding and decoding fix #33

Merged
merged 4 commits into from
Aug 13, 2019
Merged
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
106 changes: 106 additions & 0 deletions core/database_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,112 @@ func TestReceiptStorage(t *testing.T) {
}
}

func TestReceiptStorageEncoding(t *testing.T) {
var w bytes.Buffer
r := &types.ReceiptForStorage{
PostState: []byte{0x01, 0x02},
Status: types.TxSuccess,
CumulativeGasUsed: big.NewInt(1),
Logs: vm.Logs{
&vm.Log{Address: common.BytesToAddress([]byte{0x11})},
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})},
},
TxHash: common.BytesToHash([]byte{0x12, 0x11}),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
GasUsed: big.NewInt(111111),
}

r.EncodeRLP(&w)

var encodedReceipt types.ReceiptForStorage
stream := rlp.NewStream(bytes.NewReader(w.Bytes()), 0)
encodedReceipt.DecodeRLP(stream)

if bytes.Compare(encodedReceipt.PostState, r.PostState) != 0 {
t.Errorf("Old storage receipt PostState: have (%v) want (%v)", encodedReceipt.PostState, r.PostState)
}
if encodedReceipt.Status != r.Status {
t.Errorf("Old storage receipt status: have (%v) want (%v)", encodedReceipt.Status, r.Status)
}
if encodedReceipt.CumulativeGasUsed.Cmp(r.CumulativeGasUsed) != 0 {
t.Errorf("Old storage receipt CumulativeGasUsed: have (%v) want (%v)", encodedReceipt.CumulativeGasUsed, r.CumulativeGasUsed)
}
if encodedReceipt.TxHash != r.TxHash {
t.Errorf("Old storage receipt TxHash: have (%v) want (%v)", encodedReceipt.TxHash, r.TxHash)
}
if encodedReceipt.ContractAddress != r.ContractAddress {
t.Errorf("Old storage receipt ContractAddress: have (%v) want (%v)", encodedReceipt.ContractAddress, r.ContractAddress)
}
if encodedReceipt.GasUsed.Cmp(r.GasUsed) != 0 {
t.Errorf("Old storage receipt GasUsed: have (%v) want (%v)", encodedReceipt.GasUsed, r.GasUsed)
}
for i, log := range r.Logs {
if bytes.Compare(r.Logs[i].Data, log.Data) != 0 {
t.Errorf("Old storage receipt Log: have (%v) want (%v)", log.Data, r.Logs[i].Data)
}
}
}

func TestOldReceiptStorageTransition(t *testing.T) {
var w bytes.Buffer
r := &types.Receipt{
PostState: []byte{0x24, 0x12},
Status: types.TxSuccess,
CumulativeGasUsed: big.NewInt(1),
Logs: vm.Logs{
&vm.Log{Address: common.BytesToAddress([]byte{0x11})},
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})},
},
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
GasUsed: big.NewInt(111111),
}

logs := make([]*vm.LogForStorage, len(r.Logs))
for i, log := range r.Logs {
logs[i] = (*vm.LogForStorage)(log)
}

rlp.Encode(&w, []interface{}{
r.PostState,
r.CumulativeGasUsed,
r.Bloom,
r.TxHash,
r.ContractAddress,
logs,
r.GasUsed,
r.Status,
})

var encodedReceipt types.ReceiptForStorage
stream := rlp.NewStream(bytes.NewReader(w.Bytes()), 0)
encodedReceipt.DecodeRLP(stream)

if bytes.Compare(encodedReceipt.PostState, r.PostState) != 0 {
t.Errorf("Old storage receipt PostState: have (%v) want (%v)", encodedReceipt.PostState, r.PostState)
}
if encodedReceipt.Status != r.Status {
t.Errorf("Old storage receipt status: have (%v) want (%v)", encodedReceipt.Status, r.Status)
}
if encodedReceipt.CumulativeGasUsed.Cmp(r.CumulativeGasUsed) != 0 {
t.Errorf("Old storage receipt CumulativeGasUsed: have (%v) want (%v)", encodedReceipt.CumulativeGasUsed, r.CumulativeGasUsed)
}
if encodedReceipt.TxHash != r.TxHash {
t.Errorf("Old storage receipt TxHash: have (%v) want (%v)", encodedReceipt.TxHash, r.TxHash)
}
if encodedReceipt.ContractAddress != r.ContractAddress {
t.Errorf("Old storage receipt ContractAddress: have (%v) want (%v)", encodedReceipt.ContractAddress, r.ContractAddress)
}
if encodedReceipt.GasUsed.Cmp(r.GasUsed) != 0 {
t.Errorf("Old storage receipt GasUsed: have (%v) want (%v)", encodedReceipt.GasUsed, r.GasUsed)
}
for i, log := range r.Logs {
if bytes.Compare(r.Logs[i].Data, log.Data) != 0 {
t.Errorf("Old storage receipt Log: have (%v) want (%v)", log.Data, r.Logs[i].Data)
}
}
}

// Tests that receipts associated with a single block can be stored and retrieved.
func TestBlockReceiptStorage(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
Expand Down
43 changes: 28 additions & 15 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type Receipt struct {

// storedReceiptRLP is the storage encoding of a receipt.
type storedReceiptRLP struct {
PostStateOrStatus []byte
PostState []byte
CumulativeGasUsed *big.Int
Bloom Bloom
TxHash common.Hash
Expand All @@ -66,9 +66,9 @@ type storedReceiptRLP struct {
GasUsed *big.Int
}

// storedReceiptRLP is the storage encoding of a receipt.
type oldStoredReceiptRLP struct {
PostStateOrStatus []byte
// storedReceiptRLPWithStatus is the storage encoding of a receipt.
type storedReceiptRLPWithStatus struct {
PostState []byte
CumulativeGasUsed *big.Int
Bloom Bloom
TxHash common.Hash
Expand Down Expand Up @@ -159,14 +159,15 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
for i, log := range r.Logs {
logs[i] = (*vm.LogForStorage)(log)
}
receiptToStore := &storedReceiptRLP{
PostStateOrStatus: (*Receipt)(r).statusEncoding(),
receiptToStore := &storedReceiptRLPWithStatus{
PostState: r.PostState,
CumulativeGasUsed: r.CumulativeGasUsed,
Logs: logs,
Bloom: r.Bloom,
TxHash: r.TxHash,
ContractAddress: r.ContractAddress,
GasUsed: r.GasUsed,
Status: r.Status,
}
return rlp.Encode(w, receiptToStore)
}
Expand All @@ -179,12 +180,12 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
return err
}

// Try decoding the receipt without Status first
if err := decodeStoredReceiptRLP(r, raw); err == nil {
// Try decoding the receipt with Status first
if err := decodeStoredReceiptRLPWithStatus(r, raw); err == nil {
return nil
}

return decodeOldStoredReceiptRLP(r, raw)
return decodeStoredReceiptRLP(r, raw)
}

// Decode stored receipt
Expand All @@ -205,21 +206,33 @@ func decodeStoredReceiptRLP(r *ReceiptForStorage, raw []byte) error {
r.Logs[i] = (*vm.Log)(log)
}

if err := (*Receipt)(r).setStatus(receipt.PostStateOrStatus); err != nil {
return err
}
r.decodePostStateOrStatus(receipt)

return nil
}

// Previous version encoded tx Status in place of PostState, to ensure compatibility,
// this status needs to be decoded from PostState
func (r *ReceiptForStorage) decodePostStateOrStatus(sr storedReceiptRLP) {
if bytes.Equal(sr.PostState, receiptStatusSuccessfulRLP) {
r.Status = TxSuccess
return
} else if bytes.Equal(sr.PostState, receiptStatusFailedRLP) {
r.Status = TxFailure
return
}
r.PostState = sr.PostState
r.Status = TxStatusUnknown
}

// Decode with status field included in storage
func decodeOldStoredReceiptRLP(r *ReceiptForStorage, raw []byte) error {
var receipt oldStoredReceiptRLP
func decodeStoredReceiptRLPWithStatus(r *ReceiptForStorage, raw []byte) error {
var receipt storedReceiptRLPWithStatus
if err := rlp.DecodeBytes(raw, &receipt); err != nil {
return err
}

r.PostState = receipt.PostStateOrStatus
r.PostState = receipt.PostState
r.Status = receipt.Status
r.CumulativeGasUsed = receipt.CumulativeGasUsed
r.Bloom = receipt.Bloom
Expand Down