Skip to content

Commit

Permalink
proposed multicodec types
Browse files Browse the repository at this point in the history
  • Loading branch information
i-norden committed Aug 4, 2021
1 parent ede2453 commit c7d7c0c
Show file tree
Hide file tree
Showing 6 changed files with 956 additions and 5 deletions.
330 changes: 330 additions & 0 deletions log/log_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
package log_test

import (
"bytes"
"encoding/binary"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ipld/go-ipld-prime"

dageth "github.com/vulcanize/go-codec-dageth"
"github.com/vulcanize/go-codec-dageth/rct"
)

var (
mockHash = crypto.Keccak256([]byte{1, 2, 3, 4, 5})
legacyReceipt = &types.Receipt{
Status: types.ReceiptStatusSuccessful,
CumulativeGasUsed: 1,
Logs: []*types.Log{
{
Address: common.BytesToAddress([]byte{0x11}),
Topics: []common.Hash{common.HexToHash("hello"), common.HexToHash("world")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: common.BytesToAddress([]byte{0x01, 0x11}),
Topics: []common.Hash{common.HexToHash("goodbye"), common.HexToHash("world")},
Data: []byte{0x01, 0x00, 0xff},
},
},
Type: types.LegacyTxType,
}
accessListReceipt = &types.Receipt{
PostState: mockHash,
CumulativeGasUsed: 1,
Logs: []*types.Log{
{
Address: common.BytesToAddress([]byte{0x11}),
Topics: []common.Hash{common.HexToHash("hello"), common.HexToHash("world")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: common.BytesToAddress([]byte{0x01, 0x11}),
Topics: []common.Hash{common.HexToHash("goodbye"), common.HexToHash("world")},
Data: []byte{0x01, 0x00, 0xff},
},
},
Type: types.AccessListTxType,
}
dynamicFeeReceipt = &types.Receipt{
Status: types.ReceiptStatusSuccessful,
CumulativeGasUsed: 1,
Logs: []*types.Log{
{
Address: common.BytesToAddress([]byte{0x11}),
Topics: []common.Hash{common.HexToHash("hello"), common.HexToHash("world")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: common.BytesToAddress([]byte{0x01, 0x11}),
Topics: []common.Hash{common.HexToHash("goodbye"), common.HexToHash("world")},
Data: []byte{0x01, 0x00, 0xff},
},
},
Type: types.DynamicFeeTxType,
}

lReceiptConsensusEnc, alReceiptConsensusEnc, dfReceiptConsensusEnc []byte
legacyReceiptNode, accessListReceiptNode, dynamicFeeReceiptNode ipld.Node
)

/* IPLD Schemas
type Topics [Hash]
type Log struct {
Address Address
Topics Topics
Data Bytes
}
type Logs [Log]
type Receipt struct {
TxType TxType
Status nullable Uint
PostState nullable Hash
CumulativeGasUsed Uint
Bloom Bloom
Logs Logs
}
type Receipts [Receipt]
*/

func TestReceiptCodec(t *testing.T) {
var err error
lReceiptConsensusEnc, err = legacyReceipt.MarshalBinary()
if err != nil {
t.Fatalf("unable to marshal legacy receipt binary: %v", err)
}
alReceiptConsensusEnc, err = accessListReceipt.MarshalBinary()
if err != nil {
t.Fatalf("unable to marshal access list receipt binary: %v", err)
}
testReceiptDecoding(t)
testAccessListReceiptNodeContents(t)
testLegacyReceiptNodeContents(t)
testReceiptEncoding(t)
}

func testReceiptDecoding(t *testing.T) {
legacyRctBuilder := dageth.Type.Receipt.NewBuilder()
legacyRctReader := bytes.NewReader(lReceiptConsensusEnc)
if err := rct.Decode(legacyRctBuilder, legacyRctReader); err != nil {
t.Fatalf("unable to decode legacy receipt into an IPLD node: %v", err)
}
legacyReceiptNode = legacyRctBuilder.Build()

alRctBuilder := dageth.Type.Receipt.NewBuilder()
alRctReader := bytes.NewReader(alReceiptConsensusEnc)
if err := rct.Decode(alRctBuilder, alRctReader); err != nil {
t.Fatalf("unable to decode access list receipt into an IPLD node: %v", err)
}
accessListReceiptNode = alRctBuilder.Build()
}

func testAccessListReceiptNodeContents(t *testing.T) {
verifySharedContent(t, accessListReceiptNode, accessListReceipt)
statusNode, err := accessListReceiptNode.LookupByString("Status")
if err != nil {
t.Fatalf("receipt is missing Status: %v", err)
}
if !statusNode.IsNull() {
t.Fatalf("receipt Status should be null")
}

postStateNode, err := accessListReceiptNode.LookupByString("PostState")
if err != nil {
t.Fatalf("receipt is missing PostState: %v", err)
}
if postStateNode.IsNull() {
t.Errorf("receipt PostState should not be null")
}
postStateBy, err := postStateNode.AsBytes()
if err != nil {
t.Fatalf("receipt PostState should be of type Bytes: %v", err)
}
if !bytes.Equal(postStateBy, accessListReceipt.PostState) {
t.Errorf("receipt post state (%d) does not match expected post state (%d)", postStateBy, accessListReceipt.PostState)
}
}

func testDynamicFeeReceiptNodeContents(t *testing.T) {
verifySharedContent(t, dynamicFeeReceiptNode, dynamicFeeReceipt)
statusNode, err := dynamicFeeReceiptNode.LookupByString("Status")
if err != nil {
t.Fatalf("receipt is missing Status: %v", err)
}
if statusNode.IsNull() {
t.Fatalf("receipt Status should not be null")
}
statusBy, err := statusNode.AsBytes()
if err != nil {
t.Fatalf("receipt Status should be of type Bytes: %v", err)
}
status := binary.BigEndian.Uint64(statusBy)
if status != dynamicFeeReceipt.Status {
t.Errorf("receipt status (%d) does not match expected status (%d)", status, dynamicFeeReceipt.Status)
}

postStateNode, err := dynamicFeeReceiptNode.LookupByString("PostState")
if err != nil {
t.Fatalf("receipt is missing PostState: %v", err)
}
if !postStateNode.IsNull() {
t.Errorf("receipt PostState should be null")
}
}

func testLegacyReceiptNodeContents(t *testing.T) {
verifySharedContent(t, legacyReceiptNode, legacyReceipt)
statusNode, err := legacyReceiptNode.LookupByString("Status")
if err != nil {
t.Fatalf("receipt is missing Status: %v", err)
}
if statusNode.IsNull() {
t.Fatalf("receipt Status should not be null")
}
statusBy, err := statusNode.AsBytes()
if err != nil {
t.Fatalf("receipt Status should be of type Bytes: %v", err)
}
status := binary.BigEndian.Uint64(statusBy)
if status != legacyReceipt.Status {
t.Errorf("receipt status (%d) does not match expected status (%d)", status, legacyReceipt.Status)
}

postStateNode, err := legacyReceiptNode.LookupByString("PostState")
if err != nil {
t.Fatalf("receipt is missing PostState: %v", err)
}
if !postStateNode.IsNull() {
t.Errorf("receipt PostState should be null")
}
}

func verifySharedContent(t *testing.T, rctNode ipld.Node, rct *types.Receipt) {
typeNode, err := rctNode.LookupByString("TxType")
if err != nil {
t.Fatalf("receipt is missing TxType: %v", err)
}
typeBy, err := typeNode.AsBytes()
if err != nil {
t.Fatalf("receipt TxType should be of type Bytes: %v", err)
}
if len(typeBy) != 1 {
t.Fatalf("receipt TxType should be a single byte")
}
if typeBy[0] != rct.Type {
t.Errorf("receipt tx type (%d) does not match expected tx type (%d)", typeBy[0], rct.Type)
}

cguNode, err := rctNode.LookupByString("CumulativeGasUsed")
if err != nil {
t.Fatalf("receipt is missing CumulativeGasUsed: %v", err)
}
cguBy, err := cguNode.AsBytes()
if err != nil {
t.Fatalf("receipt CumulativeGasUsed should be of type Bytes: %v", err)
}
cgu := binary.BigEndian.Uint64(cguBy)
if cgu != rct.CumulativeGasUsed {
t.Errorf("receipt cumulative gas used (%d) does not match expected cumulative gas used (%d)", cgu, rct.CumulativeGasUsed)
}

bloomNode, err := rctNode.LookupByString("Bloom")
if err != nil {
t.Fatalf("receipt is missing Bloom: %v", err)
}
bloomBy, err := bloomNode.AsBytes()
if err != nil {
t.Fatalf("receipt Bloom should be of type Bytes: %v", err)
}
if !bytes.Equal(bloomBy, rct.Bloom.Bytes()) {
t.Errorf("receipt bloom (%x) does not match expected bloom (%x)", bloomBy, rct.Bloom.Bytes())
}

logsNode, err := rctNode.LookupByString("Logs")
if err != nil {
t.Fatalf("receipt is missing Logs: %v", err)
}
if logsNode.Length() != int64(len(rct.Logs)) {
t.Fatalf("receipt should have %d logs", len(rct.Logs))
}
logsLI := logsNode.ListIterator()
for !logsLI.Done() {
i, logNode, err := logsLI.Next()
if err != nil {
t.Fatalf("receipt log iterator error: %v", err)
}
currentLog := rct.Logs[i]
addrNode, err := logNode.LookupByString("Address")
if err != nil {
t.Fatalf("receipt log is missing Address: %v", err)
}
addrBy, err := addrNode.AsBytes()
if err != nil {
t.Fatalf("receipt log Address should be of type Bytes: %v", err)
}
if !bytes.Equal(addrBy, currentLog.Address.Bytes()) {
t.Errorf("receipt log address (%x) does not match expected address (%x)", addrBy, currentLog.Address.Bytes())
}
dataNode, err := logNode.LookupByString("Data")
if err != nil {
t.Fatalf("receipt log is missing Data: %v", err)
}
data, err := dataNode.AsBytes()
if err != nil {
t.Fatalf("receipt log Data should be of type Bytes: %v", err)
}
if !bytes.Equal(data, currentLog.Data) {
t.Errorf("receipt log data (%x) does not match expected data (%x)", data, currentLog.Data)
}
topicsNode, err := logNode.LookupByString("Topics")
if err != nil {
t.Fatalf("receipt log is missing Topics: %v", err)
}
if topicsNode.Length() != 2 {
t.Fatal("receipt log should have two topics")
}
topicsLI := topicsNode.ListIterator()
for !topicsLI.Done() {
j, topicNode, err := topicsLI.Next()
if err != nil {
t.Fatalf("receipt log topic iterator error: %v", err)
}
currentTopic := currentLog.Topics[j].Bytes()
topicBy, err := topicNode.AsBytes()
if err != nil {
t.Fatalf("receipt log Topic should be of type Bytes: %v", err)
}
if !bytes.Equal(topicBy, currentTopic) {
t.Errorf("receipt log topic%d bytes (%x) does not match expected bytes (%x)", j, topicBy, currentTopic)
}
}
}
}

func testReceiptEncoding(t *testing.T) {
legRctWriter := new(bytes.Buffer)
if err := rct.Encode(legacyReceiptNode, legRctWriter); err != nil {
t.Fatalf("unable to encode legacy receipt into writer: %v", err)
}
legRctBytes := legRctWriter.Bytes()
if !bytes.Equal(legRctBytes, lReceiptConsensusEnc) {
t.Errorf("legacy receipt encoding (%x) does not match the expected consensus encoding (%x)", legRctBytes, lReceiptConsensusEnc)
}

alRctWriter := new(bytes.Buffer)
if err := rct.Encode(accessListReceiptNode, alRctWriter); err != nil {
t.Fatalf("unable to encode access list receipt into writer: %v", err)
}
alRctBytes := alRctWriter.Bytes()
if !bytes.Equal(alRctBytes, alReceiptConsensusEnc) {
t.Errorf("access list receipt encoding (%x) does not match the expected consensus encoding (%x)", alRctBytes, alReceiptConsensusEnc)
}
}
2 changes: 1 addition & 1 deletion log/multicodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var (
_ ipld.Decoder = Decode
_ ipld.Encoder = Encode

MultiCodecType = uint64(0x9000) // TBD
MultiCodecType = uint64(0x9a) // Proposed
MultiHashType = uint64(multihash.KECCAK_256)
)

Expand Down
2 changes: 1 addition & 1 deletion log/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

// Decode provides an IPLD codec decode interface for eth log IPLDs.
// This function is registered via the go-ipld-prime link loader for multicodec
// code TBD when this package is invoked via init.
// code 0x9a when this package is invoked via init.
func Decode(na ipld.NodeAssembler, in io.Reader) error {
var src []byte
if buf, ok := in.(interface{ Bytes() []byte }); ok {
Expand Down
Loading

0 comments on commit c7d7c0c

Please sign in to comment.