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

Add input type to allow function selector decoding #101

Merged
merged 2 commits into from
Jan 17, 2024
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
2 changes: 1 addition & 1 deletion eth/block_from_raw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func TestBlock_FromRaw_EIP2930(t *testing.T) {
Gas: *eth.MustQuantity("0x7a120"),
GasPrice: eth.MustQuantity("0x1"),
Hash: *eth.MustHash("0x0503e1a4ead116b0d1c942c47d54d54d10ed5eaf3a57d2e974bc5cb2e8ee0c47"),
Input: *eth.MustData("0x1a8451e600000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000001000"),
Input: *eth.MustInput("0x1a8451e600000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000001000"),
Nonce: *eth.MustQuantity("0xd"),
To: eth.MustAddress("0xcccccccccccccccccccccccccccccccccccccccc"),
Index: eth.MustQuantity("0xd"),
Expand Down
4 changes: 2 additions & 2 deletions eth/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func TestMainnetGethBlocks(t *testing.T) {
require.Equal(t, eth.Data("0xd783010302844765746887676f312e352e31856c696e7578"), block.ExtraData)
require.Equal(t, true, block.Transactions[0].Populated)
require.Equal(t, int64(0), block.Transactions[0].Index.Int64())
require.Equal(t, eth.Data("0x"), block.Transactions[0].Input)
require.Equal(t, eth.Input("0x"), block.Transactions[0].Input)

j, err := json.Marshal(&block)
require.NoError(t, err)
Expand Down Expand Up @@ -179,7 +179,7 @@ func TestMainnetParityBlocks(t *testing.T) {
require.Equal(t, eth.Data("0xd783010302844765746887676f312e352e31856c696e7578"), block.ExtraData)
require.Equal(t, true, block.Transactions[0].Populated)
require.Equal(t, int64(0), block.Transactions[0].Index.Int64())
require.Equal(t, eth.Data("0x"), block.Transactions[0].Input)
require.Equal(t, eth.Input("0x"), block.Transactions[0].Input)

j, err := json.Marshal(&block)
require.NoError(t, err)
Expand Down
20 changes: 20 additions & 0 deletions eth/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

type Data string
type Data4 Data
type Data8 Data
type Data20 Data
type Data32 Data
Expand All @@ -31,6 +32,16 @@ func NewData(value string) (*Data, error) {
return &d, nil
}

func NewData4(value string) (*Data4, error) {
parsed, err := validateHex(value, 4, "data")
if err != nil {
return nil, err
}

d := Data4(parsed)
return &d, nil
}

func NewData8(value string) (*Data8, error) {
parsed, err := validateHex(value, 8, "data")
if err != nil {
Expand Down Expand Up @@ -88,6 +99,15 @@ func MustData(value string) *Data {
return d
}

func MustData4(value string) *Data4 {
d, err := NewData4(value)
if err != nil {
panic(err)
}

return d
}

func MustData8(value string) *Data8 {
d, err := NewData8(value)
if err != nil {
Expand Down
51 changes: 51 additions & 0 deletions eth/input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package eth

import (
"github.com/INFURA/go-ethlibs/rlp"
"github.com/pkg/errors"
"strings"
)

type Input Data

func NewInput(value string) (*Input, error) {
if !strings.HasPrefix(value, "0x") {
return nil, errors.Errorf("invalid input: %s", value)
}

a := Input(value)
return &a, nil
}

func MustInput(value string) *Input {
a, err := NewInput(value)
if err != nil {
panic(err)
}

return a
}

func (i Input) String() string {
return string(i)
}

func (i Input) Bytes() []byte {
return Data(i).Bytes()
}

// RLP returns the Input as an RLP-encoded string, note Input can never be null
func (i Input) RLP() rlp.Value {
return rlp.Value{
String: strings.ToLower(i.String()),
}
}

func (i Input) FunctionSelector() *Data4 {
if len(i) >= 10 {
b := Data4(i[:10])
return &b
}

return nil
}
33 changes: 33 additions & 0 deletions eth/input_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package eth

import (
"github.com/stretchr/testify/require"
"testing"
)

func TestInput_FunctionSelector(t *testing.T) {
t.Run("empty input is nil", func(t *testing.T) {
input, err := NewInput("0x")
require.NoError(t, err)
require.Nil(t, input.FunctionSelector())
})

t.Run("short input is nil", func(t *testing.T) {
input, err := NewInput("0x1234")
require.NoError(t, err)
require.Nil(t, input.FunctionSelector())
})

t.Run("exact input returns selector", func(t *testing.T) {
input, err := NewInput("0x2fbbe334")
require.NoError(t, err)
require.Equal(t, input.FunctionSelector(), MustData4("0x2fbbe334"))
})

t.Run("input with arg returns selector", func(t *testing.T) {
input, err := NewInput("0xa41368620000000000000000000000000000000000000000000000000000000000000020")
require.NoError(t, err)
require.Equal(t, input.FunctionSelector(), MustData4("0xa4136862"))
})

}
4 changes: 2 additions & 2 deletions eth/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Transaction struct {
From Address `json:"from"`
Gas Quantity `json:"gas"`
Hash Hash `json:"hash"`
Input Data `json:"input"`
Input Input `json:"input"`
antonydenyer marked this conversation as resolved.
Show resolved Hide resolved
Nonce Quantity `json:"nonce"`
To *Address `json:"to"`
Index *Quantity `json:"transactionIndex"`
Expand Down Expand Up @@ -366,7 +366,7 @@ func (t Transaction) MarshalJSON() ([]byte, error) {
Gas Quantity `json:"gas"`
GasPrice *Quantity `json:"gasPrice"`
Hash Hash `json:"hash"`
Input Data `json:"input"`
Input Input `json:"input"`
Nonce Quantity `json:"nonce"`
To *Address `json:"to"`
Index *Quantity `json:"transactionIndex"`
Expand Down
18 changes: 12 additions & 6 deletions eth/transaction_from_raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (t *Transaction) FromRaw(input string) error {
maxFeePerGas Quantity
to *Address
value Quantity
data Data
data Input
v Quantity
r Quantity
s Quantity
Expand Down Expand Up @@ -332,11 +332,11 @@ func (t *Transaction) FromRaw(input string) error {
// Note that when calling this function, the receivers MUST be pointers never values, and for "optional" receivers
// such as Address a pointer to a pointer must be passed. For example:
//
// var (
// addr *eth.Address
// nonce eth.Quantity
// )
// err := rlpDecodeList(payload, &addr, &nonce)
// var (
// addr *eth.Address
// nonce eth.Quantity
// )
// err := rlpDecodeList(payload, &addr, &nonce)
//
// TODO: Consider making this function public once all receiver types in the eth package are supported.
func rlpDecodeList(input interface{}, receivers ...interface{}) error {
Expand Down Expand Up @@ -375,6 +375,12 @@ func rlpDecodeList(input interface{}, receivers ...interface{}) error {
}
*receiver = a
}
case *Input:
d, err := NewInput(value.String)
if err != nil {
return errors.Wrapf(err, "could not decode list item %d to Input", i)
}
*receiver = *d
case *Data:
d, err := NewData(value.String)
if err != nil {
Expand Down
10 changes: 5 additions & 5 deletions eth/transaction_signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestTransaction_Sign(t *testing.T) {
Gas: eth.QuantityFromUInt64(90000),
To: eth.MustAddress("0xc149Be1bcDFa69a94384b46A1F91350E5f81c1AB"),
Value: eth.QuantityFromUInt64(950000000000000000),
Input: *eth.MustData("0x"),
Input: *eth.MustInput("0x"),
}

// This purposefully uses the already highly compromised keypair from the go-ethereum book:
Expand Down Expand Up @@ -65,7 +65,7 @@ func TestTransaction_Sign_2(t *testing.T) {
Gas: eth.QuantityFromUInt64(22000),
To: eth.MustAddress("0x43700db832E9Ac990D36d6279A846608643c904E"),
Value: eth.QuantityFromUInt64(1000000000),
Input: *eth.MustData("0x"),
Input: *eth.MustInput("0x"),
}

signed, err := tx.Sign("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19", chainId)
Expand Down Expand Up @@ -113,7 +113,7 @@ func TestTransaction_Sign_3(t *testing.T) {
Gas: eth.QuantityFromUInt64(22000),
To: eth.MustAddress("0x43700db832E9Ac990D36d6279A846608643c904E"),
Value: eth.QuantityFromUInt64(1000000000),
Input: *eth.MustData("0x"),
Input: *eth.MustInput("0x"),
}

signed, err := tx.Sign("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19", chainId)
Expand Down Expand Up @@ -201,7 +201,7 @@ func TestTransaction_Sign_EIP2930(t *testing.T) {
ChainId: &chainId,
Gas: eth.QuantityFromInt64(0x62d4),
GasPrice: eth.OptionalQuantityFromInt(0x3b9aca00),
Input: eth.Data("0x"),
Input: eth.Input("0x"),
Nonce: eth.QuantityFromInt64(0),
To: eth.MustAddress("0xdf0a88b2b68c673713a8ec826003676f272e3573"),
Value: eth.QuantityFromInt64(0x1),
Expand Down Expand Up @@ -276,7 +276,7 @@ func TestTransaction_Sign_EIP1559(t *testing.T) {
ChainId: &chainId,
MaxFeePerGas: eth.OptionalQuantityFromInt(15488430592 * 2),
MaxPriorityFeePerGas: eth.OptionalQuantityFromInt(15488430592),
Input: eth.Data("0x"),
Input: eth.Input("0x"),
Nonce: eth.QuantityFromInt64(0),
To: eth.MustAddress("0xdf0a88b2b68c673713a8ec826003676f272e3573"),
Value: eth.QuantityFromInt64(0x1),
Expand Down