Skip to content

Commit

Permalink
go-ethereum v1.14.4 update
Browse files Browse the repository at this point in the history
Vendored go-ethereum is now:

v1.14.4
  • Loading branch information
attente committed Jun 6, 2024
1 parent d096aa7 commit 102ffdc
Show file tree
Hide file tree
Showing 218 changed files with 13,700 additions and 13,372 deletions.
101 changes: 40 additions & 61 deletions go-ethereum/README.md

Large diffs are not rendered by default.

78 changes: 67 additions & 11 deletions go-ethereum/accounts/abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import (
"errors"
"fmt"
"io"
"math/big"

"github.com/0xsequence/ethkit/go-ethereum/common"
"github.com/0xsequence/ethkit/go-ethereum/crypto"
)

// The ABI holds information about a contract's context and available
// invokable methods. It will allow you to type check function calls and
// invocable methods. It will allow you to type check function calls and
// packs data accordingly.
type ABI struct {
Constructor Method
Expand Down Expand Up @@ -87,7 +88,7 @@ func (abi ABI) getArguments(name string, data []byte) (Arguments, error) {
var args Arguments
if method, ok := abi.Methods[name]; ok {
if len(data)%32 != 0 {
return nil, fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data)
return nil, fmt.Errorf("abi: improperly formatted output: %q - Bytes: %+v", data, data)
}
args = method.Outputs
}
Expand Down Expand Up @@ -222,6 +223,17 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
return nil, fmt.Errorf("no event with id: %#x", topic.Hex())
}

// ErrorByID looks up an error by the 4-byte id,
// returns nil if none found.
func (abi *ABI) ErrorByID(sigdata [4]byte) (*Error, error) {
for _, errABI := range abi.Errors {
if bytes.Equal(errABI.ID[:4], sigdata[:]) {
return &errABI, nil
}
}
return nil, fmt.Errorf("no error with id: %#x", sigdata[:])
}

// HasFallback returns an indicator whether a fallback function is included.
func (abi *ABI) HasFallback() bool {
return abi.Fallback.Type == Fallback
Expand All @@ -235,21 +247,65 @@ func (abi *ABI) HasReceive() bool {
// revertSelector is a special function selector for revert reason unpacking.
var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]

// panicSelector is a special function selector for panic reason unpacking.
var panicSelector = crypto.Keccak256([]byte("Panic(uint256)"))[:4]

// panicReasons map is for readable panic codes
// see this linkage for the details
// https://docs.soliditylang.org/en/v0.8.21/control-structures.html#panic-via-assert-and-error-via-require
// the reason string list is copied from ether.js
// https://github.com/ethers-io/ethers.js/blob/fa3a883ff7c88611ce766f58bdd4b8ac90814470/src.ts/abi/interface.ts#L207-L218
var panicReasons = map[uint64]string{
0x00: "generic panic",
0x01: "assert(false)",
0x11: "arithmetic underflow or overflow",
0x12: "division or modulo by zero",
0x21: "enum overflow",
0x22: "invalid encoded storage byte array accessed",
0x31: "out-of-bounds array access; popping on an empty array",
0x32: "out-of-bounds access of an array or bytesN",
0x41: "out of memory",
0x51: "uninitialized function",
}

// UnpackRevert resolves the abi-encoded revert reason. According to the solidity
// spec https://solidity.readthedocs.io/en/latest/control-structures.html#revert,
// the provided revert reason is abi-encoded as if it were a call to a function
// `Error(string)`. So it's a special tool for it.
// the provided revert reason is abi-encoded as if it were a call to function
// `Error(string)` or `Panic(uint256)`. So it's a special tool for it.
func UnpackRevert(data []byte) (string, error) {
if len(data) < 4 {
return "", errors.New("invalid data for unpacking")
}
if !bytes.Equal(data[:4], revertSelector) {
switch {
case bytes.Equal(data[:4], revertSelector):
typ, err := NewType("string", "", nil)
if err != nil {
return "", err
}
unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
if err != nil {
return "", err
}
return unpacked[0].(string), nil
case bytes.Equal(data[:4], panicSelector):
typ, err := NewType("uint256", "", nil)
if err != nil {
return "", err
}
unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
if err != nil {
return "", err
}
pCode := unpacked[0].(*big.Int)
// uint64 safety check for future
// but the code is not bigger than MAX(uint64) now
if pCode.IsUint64() {
if reason, ok := panicReasons[pCode.Uint64()]; ok {
return reason, nil
}
}
return fmt.Sprintf("unknown panic code: %#x", pCode), nil
default:
return "", errors.New("invalid data for unpacking")
}
typ, _ := NewType("string", "", nil)
unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
if err != nil {
return "", err
}
return unpacked[0].(string), nil
}
88 changes: 74 additions & 14 deletions go-ethereum/accounts/abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ var methods = map[string]Method{
}

func TestReader(t *testing.T) {
t.Parallel()
abi := ABI{
Methods: methods,
}
Expand Down Expand Up @@ -151,6 +152,7 @@ func TestReader(t *testing.T) {
}

func TestInvalidABI(t *testing.T) {
t.Parallel()
json := `[{ "type" : "function", "name" : "", "constant" : fals }]`
_, err := JSON(strings.NewReader(json))
if err == nil {
Expand All @@ -165,10 +167,12 @@ func TestInvalidABI(t *testing.T) {

// TestConstructor tests a constructor function.
// The test is based on the following contract:
// contract TestConstructor {
// constructor(uint256 a, uint256 b) public{}
//
// contract TestConstructor {
// constructor(uint256 a, uint256 b) public{}
// }
func TestConstructor(t *testing.T) {
t.Parallel()
json := `[{ "inputs": [{"internalType": "uint256","name": "a","type": "uint256" },{ "internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]`
method := NewMethod("", "", Constructor, "nonpayable", false, false, []Argument{{"a", Uint256, false}, {"b", Uint256, false}}, nil)
// Test from JSON
Expand Down Expand Up @@ -198,6 +202,7 @@ func TestConstructor(t *testing.T) {
}

func TestTestNumbers(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata))
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -235,6 +240,7 @@ func TestTestNumbers(t *testing.T) {
}

func TestMethodSignature(t *testing.T) {
t.Parallel()
m := NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil)
exp := "foo(string,string)"
if m.Sig != exp {
Expand Down Expand Up @@ -273,6 +279,7 @@ func TestMethodSignature(t *testing.T) {
}

func TestOverloadedMethodSignature(t *testing.T) {
t.Parallel()
json := `[{"constant":true,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`
abi, err := JSON(strings.NewReader(json))
if err != nil {
Expand All @@ -296,6 +303,7 @@ func TestOverloadedMethodSignature(t *testing.T) {
}

func TestCustomErrors(t *testing.T) {
t.Parallel()
json := `[{ "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ],"name": "MyError", "type": "error"} ]`
abi, err := JSON(strings.NewReader(json))
if err != nil {
Expand All @@ -310,6 +318,7 @@ func TestCustomErrors(t *testing.T) {
}

func TestMultiPack(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata))
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -347,6 +356,7 @@ func ExampleJSON() {
}

func TestInputVariableInputLength(t *testing.T) {
t.Parallel()
const definition = `[
{ "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] },
{ "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] },
Expand Down Expand Up @@ -475,6 +485,7 @@ func TestInputVariableInputLength(t *testing.T) {
}

func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata))
if err != nil {
t.Error(err)
Expand Down Expand Up @@ -649,6 +660,7 @@ func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
}

func TestDefaultFunctionParsing(t *testing.T) {
t.Parallel()
const definition = `[{ "name" : "balance", "type" : "function" }]`

abi, err := JSON(strings.NewReader(definition))
Expand All @@ -662,6 +674,7 @@ func TestDefaultFunctionParsing(t *testing.T) {
}

func TestBareEvents(t *testing.T) {
t.Parallel()
const definition = `[
{ "type" : "event", "name" : "balance" },
{ "type" : "event", "name" : "anon", "anonymous" : true},
Expand Down Expand Up @@ -724,17 +737,21 @@ func TestBareEvents(t *testing.T) {
}

// TestUnpackEvent is based on this contract:
// contract T {
// event received(address sender, uint amount, bytes memo);
// event receivedAddr(address sender);
// function receive(bytes memo) external payable {
// received(msg.sender, msg.value, memo);
// receivedAddr(msg.sender);
// }
// }
//
// contract T {
// event received(address sender, uint amount, bytes memo);
// event receivedAddr(address sender);
// function receive(bytes memo) external payable {
// received(msg.sender, msg.value, memo);
// receivedAddr(msg.sender);
// }
// }
//
// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
//
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
func TestUnpackEvent(t *testing.T) {
t.Parallel()
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
abi, err := JSON(strings.NewReader(abiJSON))
if err != nil {
Expand Down Expand Up @@ -773,6 +790,7 @@ func TestUnpackEvent(t *testing.T) {
}

func TestUnpackEventIntoMap(t *testing.T) {
t.Parallel()
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
abi, err := JSON(strings.NewReader(abiJSON))
if err != nil {
Expand Down Expand Up @@ -823,6 +841,7 @@ func TestUnpackEventIntoMap(t *testing.T) {
}

func TestUnpackMethodIntoMap(t *testing.T) {
t.Parallel()
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
abi, err := JSON(strings.NewReader(abiJSON))
if err != nil {
Expand Down Expand Up @@ -873,6 +892,7 @@ func TestUnpackMethodIntoMap(t *testing.T) {
}

func TestUnpackIntoMapNamingConflict(t *testing.T) {
t.Parallel()
// Two methods have the same name
var abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"get","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
abi, err := JSON(strings.NewReader(abiJSON))
Expand Down Expand Up @@ -956,6 +976,7 @@ func TestUnpackIntoMapNamingConflict(t *testing.T) {
}

func TestABI_MethodById(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata))
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -988,6 +1009,7 @@ func TestABI_MethodById(t *testing.T) {
}

func TestABI_EventById(t *testing.T) {
t.Parallel()
tests := []struct {
name string
json string
Expand Down Expand Up @@ -1053,9 +1075,39 @@ func TestABI_EventById(t *testing.T) {
}
}

func TestABI_ErrorByID(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(`[
{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"},
{"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"},
{"inputs":[{"internalType":"uint256[]","name":"x","type":"uint256[]"}],"name":"MyError3","type":"error"}
]`))
if err != nil {
t.Fatal(err)
}
for name, m := range abi.Errors {
a := fmt.Sprintf("%v", &m)
var id [4]byte
copy(id[:], m.ID[:4])
m2, err := abi.ErrorByID(id)
if err != nil {
t.Fatalf("Failed to look up ABI error: %v", err)
}
b := fmt.Sprintf("%v", m2)
if a != b {
t.Errorf("Error %v (id %x) not 'findable' by id in ABI", name, id)
}
}
// test unsuccessful lookups
if _, err = abi.ErrorByID([4]byte{}); err == nil {
t.Error("Expected error: no error with this id")
}
}

// TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name
// conflict and that the second transfer method will be renamed transfer1.
func TestDoubleDuplicateMethodNames(t *testing.T) {
t.Parallel()
abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer0","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
contractAbi, err := JSON(strings.NewReader(abiJSON))
if err != nil {
Expand All @@ -1078,12 +1130,14 @@ func TestDoubleDuplicateMethodNames(t *testing.T) {
// TestDoubleDuplicateEventNames checks that if send0 already exists, there won't be a name
// conflict and that the second send event will be renamed send1.
// The test runs the abi of the following contract.
// contract DuplicateEvent {
// event send(uint256 a);
//
// contract DuplicateEvent {
// event send(uint256 a);
// event send0();
// event send();
// }
func TestDoubleDuplicateEventNames(t *testing.T) {
t.Parallel()
abiJSON := `[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "uint256","name": "a","type": "uint256"}],"name": "send","type": "event"},{"anonymous": false,"inputs": [],"name": "send0","type": "event"},{ "anonymous": false, "inputs": [],"name": "send","type": "event"}]`
contractAbi, err := JSON(strings.NewReader(abiJSON))
if err != nil {
Expand All @@ -1106,10 +1160,12 @@ func TestDoubleDuplicateEventNames(t *testing.T) {
// TestUnnamedEventParam checks that an event with unnamed parameters is
// correctly handled.
// The test runs the abi of the following contract.
// contract TestEvent {
//
// contract TestEvent {
// event send(uint256, uint256);
// }
func TestUnnamedEventParam(t *testing.T) {
t.Parallel()
abiJSON := `[{ "anonymous": false, "inputs": [{ "indexed": false,"internalType": "uint256", "name": "","type": "uint256"},{"indexed": false,"internalType": "uint256","name": "","type": "uint256"}],"name": "send","type": "event"}]`
contractAbi, err := JSON(strings.NewReader(abiJSON))
if err != nil {
Expand Down Expand Up @@ -1139,9 +1195,13 @@ func TestUnpackRevert(t *testing.T) {
{"", "", errors.New("invalid data for unpacking")},
{"08c379a1", "", errors.New("invalid data for unpacking")},
{"08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000", "revert reason", nil},
{"4e487b710000000000000000000000000000000000000000000000000000000000000000", "generic panic", nil},
{"4e487b7100000000000000000000000000000000000000000000000000000000000000ff", "unknown panic code: 0xff", nil},
}
for index, c := range cases {
index, c := index, c
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
t.Parallel()
got, err := UnpackRevert(common.Hex2Bytes(c.input))
if c.expectErr != nil {
if err == nil {
Expand Down
Loading

0 comments on commit 102ffdc

Please sign in to comment.