CORE-2543 Investigate geth fork

This commit is contained in:
Alex Karolis 2025-05-26 13:39:08 +12:00
parent 9fd3f8a0dd
commit c16b1a357b
No known key found for this signature in database
GPG key ID: 8529C2F0B10D0658
6 changed files with 2551 additions and 6352 deletions

View file

@ -734,7 +734,7 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
"to": msg.To, "to": msg.To,
} }
if len(msg.Data) > 0 { if len(msg.Data) > 0 {
arg["input"] = hexutil.Bytes(msg.Data) arg["data"] = hexutil.Bytes(msg.Data)
} }
if msg.Value != nil { if msg.Value != nil {
arg["value"] = (*hexutil.Big)(msg.Value) arg["value"] = (*hexutil.Big)(msg.Value)

View file

@ -225,7 +225,7 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
"to": msg.To, "to": msg.To,
} }
if len(msg.Data) > 0 { if len(msg.Data) > 0 {
arg["input"] = hexutil.Bytes(msg.Data) arg["data"] = hexutil.Bytes(msg.Data)
} }
if msg.Value != nil { if msg.Value != nil {
arg["value"] = (*hexutil.Big)(msg.Value) arg["value"] = (*hexutil.Big)(msg.Value)

View file

@ -250,31 +250,28 @@ func TestConvertAddressDataToSlice(t *testing.T) {
func TestTypedDataArrayValidate(t *testing.T) { func TestTypedDataArrayValidate(t *testing.T) {
t.Parallel() t.Parallel()
type testDataInput struct { type TestDataInput struct {
Name string `json:"name"` Name string `json:"name"`
Domain TypedDataDomain `json:"domain"` TypedData TypedData `json:"typedData"`
PrimaryType string `json:"primaryType"` DomainHash string `json:"domainHash"`
Types Types `json:"types"` MessageHash string `json:"messageHash"`
Message TypedDataMessage `json:"data"`
Digest string `json:"digest"` Digest string `json:"digest"`
} }
fc, err := os.ReadFile("./testdata/typed-data.json") fc, err := os.ReadFile("./testdata/typed-data.json")
require.NoError(t, err, "error reading test data file") require.NoError(t, err, "error reading test data file")
var tests []testDataInput var tests []TestDataInput
err = json.Unmarshal(fc, &tests) err = json.Unmarshal(fc, &tests)
require.NoError(t, err, "error unmarshalling test data file contents") require.NoError(t, err, "error unmarshalling test data file contents")
for _, tc := range tests { for _, tt := range tests {
tc := tt
t.Run(tc.Name, func(t *testing.T) { t.Run(tc.Name, func(t *testing.T) {
t.Parallel() t.Parallel()
td := TypedData{ td := tc.TypedData
Types: tc.Types,
PrimaryType: tc.PrimaryType,
Domain: tc.Domain,
Message: tc.Message,
}
domainSeparator, tErr := td.HashStruct("EIP712Domain", td.Domain.Map()) domainSeparator, tErr := td.HashStruct("EIP712Domain", td.Domain.Map())
assert.NoError(t, tErr, "failed to hash domain separator: %v", tErr) assert.NoError(t, tErr, "failed to hash domain separator: %v", tErr)
@ -282,10 +279,13 @@ func TestTypedDataArrayValidate(t *testing.T) {
messageHash, tErr := td.HashStruct(td.PrimaryType, td.Message) messageHash, tErr := td.HashStruct(td.PrimaryType, td.Message)
assert.NoError(t, tErr, "failed to hash message: %v", tErr) assert.NoError(t, tErr, "failed to hash message: %v", tErr)
digest := crypto.Keccak256Hash(fmt.Appendf(nil, "%s%s%s", "\x19\x01", string(domainSeparator), string(messageHash))) digest := crypto.Keccak256Hash([]byte(fmt.Sprintf("%s%s%s", "\x19\x01", string(domainSeparator), string(messageHash))))
assert.Equal(t, tc.Digest, digest.String(), "digest doesn't not match")
assert.NoError(t, td.validate(), "validation failed", tErr) assert.Equal(t, tc.Digest, digest.String(), "digest doesn't not match")
assert.Equal(t, tc.DomainHash, domainSeparator.String(), "domain separator hashes do not match")
assert.Equal(t, tc.MessageHash, messageHash.String(), "message hashes do not match")
assert.NoError(t, td.validate(), "expected typed data to pass validation, got: %v", tErr)
}) })
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -18,14 +18,12 @@ package apitypes
import ( import (
"bytes" "bytes"
"crypto/sha256"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"reflect" "reflect"
"regexp" "regexp"
"slices"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -36,8 +34,6 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/holiman/uint256"
) )
var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Za-z](\w*)(\[\d*\])*$`) var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Za-z](\w*)(\[\d*\])*$`)
@ -66,10 +62,10 @@ func (vs *ValidationMessages) Info(msg string) {
vs.Messages = append(vs.Messages, ValidationInfo{INFO, msg}) vs.Messages = append(vs.Messages, ValidationInfo{INFO, msg})
} }
// GetWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present // getWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present
func (vs *ValidationMessages) GetWarnings() error { func (v *ValidationMessages) GetWarnings() error {
var messages []string var messages []string
for _, msg := range vs.Messages { for _, msg := range v.Messages {
if msg.Typ == WARN || msg.Typ == CRIT { if msg.Typ == WARN || msg.Typ == CRIT {
messages = append(messages, msg.Message) messages = append(messages, msg.Message)
} }
@ -96,21 +92,12 @@ type SendTxArgs struct {
// We accept "data" and "input" for backwards-compatibility reasons. // We accept "data" and "input" for backwards-compatibility reasons.
// "input" is the newer name and should be preferred by clients. // "input" is the newer name and should be preferred by clients.
// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628 // Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
Data *hexutil.Bytes `json:"data,omitempty"` Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input,omitempty"` Input *hexutil.Bytes `json:"input,omitempty"`
// For non-legacy transactions // For non-legacy transactions
AccessList *types.AccessList `json:"accessList,omitempty"` AccessList *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"`
// For BlobTxType
BlobFeeCap *hexutil.Big `json:"maxFeePerBlobGas,omitempty"`
BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
// For BlobTxType transactions with blob sidecar
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
} }
func (args SendTxArgs) String() string { func (args SendTxArgs) String() string {
@ -121,56 +108,24 @@ func (args SendTxArgs) String() string {
return err.Error() return err.Error()
} }
// data retrieves the transaction calldata. Input field is preferred.
func (args *SendTxArgs) data() []byte {
if args.Input != nil {
return *args.Input
}
if args.Data != nil {
return *args.Data
}
return nil
}
// ToTransaction converts the arguments to a transaction. // ToTransaction converts the arguments to a transaction.
func (args *SendTxArgs) ToTransaction() (*types.Transaction, error) { func (args *SendTxArgs) ToTransaction() *types.Transaction {
// Add the To-field, if specified // Add the To-field, if specified
var to *common.Address var to *common.Address
if args.To != nil { if args.To != nil {
dstAddr := args.To.Address() dstAddr := args.To.Address()
to = &dstAddr to = &dstAddr
} }
if err := args.validateTxSidecar(); err != nil {
return nil, err var input []byte
} if args.Input != nil {
var data types.TxData input = *args.Input
switch { } else if args.Data != nil {
case args.BlobHashes != nil: input = *args.Data
al := types.AccessList{}
if args.AccessList != nil {
al = *args.AccessList
}
data = &types.BlobTx{
To: *to,
ChainID: uint256.MustFromBig((*big.Int)(args.ChainID)),
Nonce: uint64(args.Nonce),
Gas: uint64(args.Gas),
GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
Value: uint256.MustFromBig((*big.Int)(&args.Value)),
Data: args.data(),
AccessList: al,
BlobHashes: args.BlobHashes,
BlobFeeCap: uint256.MustFromBig((*big.Int)(args.BlobFeeCap)),
}
if args.Blobs != nil {
data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{
Blobs: args.Blobs,
Commitments: args.Commitments,
Proofs: args.Proofs,
}
} }
var data types.TxData
switch {
case args.MaxFeePerGas != nil: case args.MaxFeePerGas != nil:
al := types.AccessList{} al := types.AccessList{}
if args.AccessList != nil { if args.AccessList != nil {
@ -184,7 +139,7 @@ func (args *SendTxArgs) ToTransaction() (*types.Transaction, error) {
GasFeeCap: (*big.Int)(args.MaxFeePerGas), GasFeeCap: (*big.Int)(args.MaxFeePerGas),
GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas),
Value: (*big.Int)(&args.Value), Value: (*big.Int)(&args.Value),
Data: args.data(), Data: input,
AccessList: al, AccessList: al,
} }
case args.AccessList != nil: case args.AccessList != nil:
@ -195,7 +150,7 @@ func (args *SendTxArgs) ToTransaction() (*types.Transaction, error) {
Gas: uint64(args.Gas), Gas: uint64(args.Gas),
GasPrice: (*big.Int)(args.GasPrice), GasPrice: (*big.Int)(args.GasPrice),
Value: (*big.Int)(&args.Value), Value: (*big.Int)(&args.Value),
Data: args.data(), Data: input,
AccessList: *args.AccessList, AccessList: *args.AccessList,
} }
default: default:
@ -205,81 +160,10 @@ func (args *SendTxArgs) ToTransaction() (*types.Transaction, error) {
Gas: uint64(args.Gas), Gas: uint64(args.Gas),
GasPrice: (*big.Int)(args.GasPrice), GasPrice: (*big.Int)(args.GasPrice),
Value: (*big.Int)(&args.Value), Value: (*big.Int)(&args.Value),
Data: args.data(), Data: input,
} }
} }
return types.NewTx(data)
return types.NewTx(data), nil
}
// validateTxSidecar validates blob data, if present
func (args *SendTxArgs) validateTxSidecar() error {
// No blobs, we're done.
if args.Blobs == nil {
return nil
}
n := len(args.Blobs)
// Assume user provides either only blobs (w/o hashes), or
// blobs together with commitments and proofs.
if args.Commitments == nil && args.Proofs != nil {
return errors.New(`blob proofs provided while commitments were not`)
} else if args.Commitments != nil && args.Proofs == nil {
return errors.New(`blob commitments provided while proofs were not`)
}
// len(blobs) == len(commitments) == len(proofs) == len(hashes)
if args.Commitments != nil && len(args.Commitments) != n {
return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n)
}
if args.Proofs != nil && len(args.Proofs) != n {
return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n)
}
if args.BlobHashes != nil && len(args.BlobHashes) != n {
return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n)
}
if args.Commitments == nil {
// Generate commitment and proof.
commitments := make([]kzg4844.Commitment, n)
proofs := make([]kzg4844.Proof, n)
for i, b := range args.Blobs {
c, err := kzg4844.BlobToCommitment(&b)
if err != nil {
return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err)
}
commitments[i] = c
p, err := kzg4844.ComputeBlobProof(&b, c)
if err != nil {
return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
}
proofs[i] = p
}
args.Commitments = commitments
args.Proofs = proofs
} else {
for i, b := range args.Blobs {
if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil {
return fmt.Errorf("failed to verify blob proof: %v", err)
}
}
}
hashes := make([]common.Hash, n)
hasher := sha256.New()
for i, c := range args.Commitments {
hashes[i] = kzg4844.CalcBlobHashV1(hasher, &c)
}
if args.BlobHashes != nil {
for i, h := range hashes {
if h != args.BlobHashes[i] {
return fmt.Errorf("blob hash verification failed (have=%s, want=%s)", args.BlobHashes[i], h)
}
}
} else {
args.BlobHashes = hashes
}
return nil
} }
type SigFormat struct { type SigFormat struct {
@ -325,11 +209,9 @@ type Type struct {
Type string `json:"type"` Type string `json:"type"`
} }
// isArray returns true if the type is a fixed or variable sized array. // isArray returns true if the type is a fixed or variable sized array
// This method may return false positives, in case the Type is not a valid
// expression, e.g. "fooo[[[[".
func (t *Type) isArray() bool { func (t *Type) isArray() bool {
return strings.IndexByte(t.Type, '[') > 0 return len(strings.Split(t.Type, "[")) > 1
} }
// typeName returns the canonical name of the type. If the type is 'Person[]' or 'Person[2]', then // typeName returns the canonical name of the type. If the type is 'Person[]' or 'Person[2]', then
@ -387,8 +269,16 @@ func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage
// Dependencies returns an array of custom types ordered by their hierarchical reference tree // Dependencies returns an array of custom types ordered by their hierarchical reference tree
func (typedData *TypedData) Dependencies(primaryType string, found []string) []string { func (typedData *TypedData) Dependencies(primaryType string, found []string) []string {
primaryType = strings.Split(primaryType, "[")[0] primaryType = strings.Split(primaryType, "[")[0]
includes := func(arr []string, str string) bool {
for _, obj := range arr {
if obj == str {
return true
}
}
return false
}
if slices.Contains(found, primaryType) { if includes(found, primaryType) {
return found return found
} }
if typedData.Types[primaryType] == nil { if typedData.Types[primaryType] == nil {
@ -397,7 +287,7 @@ func (typedData *TypedData) Dependencies(primaryType string, found []string) []s
found = append(found, primaryType) found = append(found, primaryType)
for _, field := range typedData.Types[primaryType] { for _, field := range typedData.Types[primaryType] {
for _, dep := range typedData.Dependencies(field.Type, found) { for _, dep := range typedData.Dependencies(field.Type, found) {
if !slices.Contains(found, dep) { if !includes(found, dep) {
found = append(found, dep) found = append(found, dep)
} }
} }
@ -464,9 +354,9 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter
encType := field.Type encType := field.Type
encValue := data[field.Name] encValue := data[field.Name]
if encType[len(encType)-1:] == "]" { if encType[len(encType)-1:] == "]" {
encodedData, err := typedData.encodeArrayValue(encValue, encType, depth) encodedData, encErr := typedData.encodeArrayValue(encValue, encType, depth)
if err != nil { if encErr != nil {
return nil, err return nil, encErr
} }
buffer.Write(encodedData) buffer.Write(encodedData)
} else if typedData.Types[field.Type] != nil { } else if typedData.Types[field.Type] != nil {
@ -496,23 +386,14 @@ func (typedData *TypedData) encodeArrayValue(encValue interface{}, encType strin
return nil, dataMismatchError(encType, encValue) return nil, dataMismatchError(encType, encValue)
} }
arrayBuffer := new(bytes.Buffer) arrayBuffer := bytes.Buffer{}
parsedType := strings.Split(encType, "[")[0] parsedType := strings.Split(encType, "[")[0]
for _, item := range arrayValue { for _, item := range arrayValue {
if reflect.TypeOf(item).Kind() == reflect.Slice || if reflect.TypeOf(item).Kind() == reflect.Slice ||
reflect.TypeOf(item).Kind() == reflect.Array { reflect.TypeOf(item).Kind() == reflect.Array {
var ( encodedData, encErr := typedData.encodeArrayValue(item, parsedType, depth+1)
encodedData hexutil.Bytes if encErr != nil {
err error return nil, encErr
)
if reflect.TypeOf(item).Elem().Kind() == reflect.Uint8 {
// the item type is bytes. encode the bytes array directly instead of recursing.
encodedData, err = typedData.EncodePrimitiveValue(parsedType, item, depth+1)
} else {
encodedData, err = typedData.encodeArrayValue(item, parsedType, depth+1)
}
if err != nil {
return nil, err
} }
arrayBuffer.Write(encodedData) arrayBuffer.Write(encodedData)
} else { } else {
@ -521,16 +402,16 @@ func (typedData *TypedData) encodeArrayValue(encValue interface{}, encType strin
if !ok { if !ok {
return nil, dataMismatchError(parsedType, item) return nil, dataMismatchError(parsedType, item)
} }
encodedData, err := typedData.EncodeData(parsedType, mapValue, depth+1) encodedData, encErr := typedData.EncodeData(parsedType, mapValue, depth+1)
if err != nil { if encErr != nil {
return nil, err return nil, encErr
} }
digest := crypto.Keccak256(encodedData) digest := crypto.Keccak256(encodedData)
arrayBuffer.Write(digest) arrayBuffer.Write(digest)
} else { } else {
bytesValue, err := typedData.EncodePrimitiveValue(parsedType, item, depth) bytesValue, encErr := typedData.EncodePrimitiveValue(parsedType, item, depth)
if err != nil { if encErr != nil {
return nil, err return nil, encErr
} }
arrayBuffer.Write(bytesValue) arrayBuffer.Write(bytesValue)
} }
@ -685,7 +566,7 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf
if err != nil { if err != nil {
return nil, err return nil, err
} }
return math.U256Bytes(new(big.Int).Set(b)), nil return math.U256Bytes(b), nil
} }
return nil, fmt.Errorf("unrecognized type '%s'", encType) return nil, fmt.Errorf("unrecognized type '%s'", encType)
} }
@ -838,11 +719,11 @@ func formatPrimitiveValue(encType string, encValue interface{}) (string, error)
return "", fmt.Errorf("unhandled type %v", encType) return "", fmt.Errorf("unhandled type %v", encType)
} }
// validate checks if the types object is conformant to the specs // Validate checks if the types object is conformant to the specs
func (t Types) validate() error { func (t Types) validate() error {
for typeKey, typeArr := range t { for typeKey, typeArr := range t {
if len(typeKey) == 0 { if len(typeKey) == 0 {
return errors.New("empty type key") return fmt.Errorf("empty type key")
} }
for i, typeObj := range typeArr { for i, typeObj := range typeArr {
if len(typeObj.Type) == 0 { if len(typeObj.Type) == 0 {
@ -869,36 +750,34 @@ func (t Types) validate() error {
return nil return nil
} }
var validPrimitiveTypes = map[string]struct{}{} // Checks if the primitive value is valid
func isPrimitiveTypeValid(primitiveType string) bool {
// build the set of valid primitive types primitiveType = strings.Split(primitiveType, "[")[0]
func init() { if primitiveType == "address" ||
// Types those are trivially valid primitiveType == "bool" ||
for _, t := range []string{ primitiveType == "string" ||
"address", "address[]", "bool", "bool[]", "string", "string[]", primitiveType == "bytes" ||
"bytes", "bytes[]", "int", "int[]", "uint", "uint[]", primitiveType == "int" ||
} { primitiveType == "uint" {
validPrimitiveTypes[t] = struct{}{} return true
} }
// For 'bytesN', 'bytesN[]', we allow N from 1 to 32 // For 'bytesN', 'bytesN[]', we allow N from 1 to 32
for n := 1; n <= 32; n++ { for n := 1; n <= 32; n++ {
validPrimitiveTypes[fmt.Sprintf("bytes%d", n)] = struct{}{} // e.g. 'bytes28' or 'bytes28[]'
validPrimitiveTypes[fmt.Sprintf("bytes%d[]", n)] = struct{}{} if primitiveType == fmt.Sprintf("bytes%d", n) || primitiveType == fmt.Sprintf("bytes%d[]", n) {
return true
}
} }
// For 'intN','intN[]' and 'uintN','uintN[]' we allow N in increments of 8, from 8 up to 256 // For 'intN','intN[]' and 'uintN','uintN[]' we allow N in increments of 8, from 8 up to 256
for n := 8; n <= 256; n += 8 { for n := 8; n <= 256; n += 8 {
validPrimitiveTypes[fmt.Sprintf("int%d", n)] = struct{}{} if primitiveType == fmt.Sprintf("int%d", n) || primitiveType == fmt.Sprintf("int%d[]", n) {
validPrimitiveTypes[fmt.Sprintf("int%d[]", n)] = struct{}{} return true
validPrimitiveTypes[fmt.Sprintf("uint%d", n)] = struct{}{}
validPrimitiveTypes[fmt.Sprintf("uint%d[]", n)] = struct{}{}
} }
} if primitiveType == fmt.Sprintf("uint%d", n) || primitiveType == fmt.Sprintf("uint%d[]", n) {
return true
// Checks if the primitive value is valid }
func isPrimitiveTypeValid(primitiveType string) bool { }
input := strings.Split(primitiveType, "[")[0] return false
_, ok := validPrimitiveTypes[input]
return ok
} }
// validate checks if the given domain is valid, i.e. contains at least // validate checks if the given domain is valid, i.e. contains at least

View file

@ -16,16 +16,7 @@
package apitypes package apitypes
import ( import "testing"
"crypto/sha256"
"encoding/json"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/holiman/uint256"
)
func TestIsPrimitive(t *testing.T) { func TestIsPrimitive(t *testing.T) {
t.Parallel() t.Parallel()
@ -50,99 +41,6 @@ func TestIsPrimitive(t *testing.T) {
} }
} }
func TestTxArgs(t *testing.T) {
for i, tc := range []struct {
data []byte
want common.Hash
wantType uint8
}{
{
data: []byte(`{"from":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","accessList":[],"blobVersionedHashes":["0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014"],"chainId":"0x7","gas":"0x124f8","gasPrice":"0x693d4ca8","input":"0x","maxFeePerBlobGas":"0x3b9aca00","maxFeePerGas":"0x6fc23ac00","maxPriorityFeePerGas":"0x3b9aca00","nonce":"0x0","r":"0x2a922afc784d07e98012da29f2f37cae1f73eda78aa8805d3df6ee5dbb41ec1","s":"0x4f1f75ae6bcdf4970b4f305da1a15d8c5ddb21f555444beab77c9af2baab14","to":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","type":"0x1","v":"0x0","value":"0x0","yParity":"0x0"}`),
want: common.HexToHash("0x7d53234acc11ac5b5948632c901a944694e228795782f511887d36fd76ff15c4"),
wantType: types.BlobTxType,
},
{
// on input, we don't read the type, but infer the type from the arguments present
data: []byte(`{"from":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","accessList":[],"chainId":"0x7","gas":"0x124f8","gasPrice":"0x693d4ca8","input":"0x","maxFeePerBlobGas":"0x3b9aca00","maxFeePerGas":"0x6fc23ac00","maxPriorityFeePerGas":"0x3b9aca00","nonce":"0x0","r":"0x2a922afc784d07e98012da29f2f37cae1f73eda78aa8805d3df6ee5dbb41ec1","s":"0x4f1f75ae6bcdf4970b4f305da1a15d8c5ddb21f555444beab77c9af2baab14","to":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","type":"0x12","v":"0x0","value":"0x0","yParity":"0x0"}`),
want: common.HexToHash("0x7919e2b0b9b543cb87a137b6ff66491ec7ae937cb88d3c29db4d9b28073dce53"),
wantType: types.DynamicFeeTxType,
},
} {
var txArgs SendTxArgs
if err := json.Unmarshal(tc.data, &txArgs); err != nil {
t.Fatal(err)
}
tx, err := txArgs.ToTransaction()
if err != nil {
t.Fatal(err)
}
if have := tx.Type(); have != tc.wantType {
t.Errorf("test %d, have type %d, want type %d", i, have, tc.wantType)
}
if have := tx.Hash(); have != tc.want {
t.Errorf("test %d: have %v, want %v", i, have, tc.want)
}
d2, err := json.Marshal(txArgs)
if err != nil {
t.Fatal(err)
}
var txArgs2 SendTxArgs
if err := json.Unmarshal(d2, &txArgs2); err != nil {
t.Fatal(err)
}
tx1, _ := txArgs.ToTransaction()
tx2, _ := txArgs2.ToTransaction()
if have, want := tx1.Hash(), tx2.Hash(); have != want {
t.Errorf("test %d: have %v, want %v", i, have, want)
}
}
/*
End to end testing:
$ go run ./cmd/clef --advanced --suppress-bootwarn
$ go run ./cmd/geth --nodiscover --maxpeers 0 --signer /home/user/.clef/clef.ipc console
> tx={"from":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","to":"0x1b442286e32ddcaa6e2570ce9ed85f4b4fc87425","gas":"0x124f8","maxFeePerGas":"0x6fc23ac00","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","nonce":"0x0","input":"0x","accessList":[],"maxFeePerBlobGas":"0x3b9aca00","blobVersionedHashes":["0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014"]}
> eth.signTransaction(tx)
*/
}
func TestBlobTxs(t *testing.T) {
blob := kzg4844.Blob{0x1}
commitment, err := kzg4844.BlobToCommitment(&blob)
if err != nil {
t.Fatal(err)
}
proof, err := kzg4844.ComputeBlobProof(&blob, commitment)
if err != nil {
t.Fatal(err)
}
hash := kzg4844.CalcBlobHashV1(sha256.New(), &commitment)
b := &types.BlobTx{
ChainID: uint256.NewInt(6),
Nonce: 8,
GasTipCap: uint256.NewInt(500),
GasFeeCap: uint256.NewInt(600),
Gas: 21000,
BlobFeeCap: uint256.NewInt(700),
BlobHashes: []common.Hash{hash},
Value: uint256.NewInt(100),
Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{blob},
Commitments: []kzg4844.Commitment{commitment},
Proofs: []kzg4844.Proof{proof},
},
}
tx := types.NewTx(b)
data, err := json.Marshal(tx)
if err != nil {
t.Fatal(err)
}
t.Logf("tx %v", string(data))
}
func TestType_IsArray(t *testing.T) { func TestType_IsArray(t *testing.T) {
t.Parallel() t.Parallel()
// Expected positives // Expected positives
@ -229,7 +127,7 @@ func TestType_TypeName(t *testing.T) {
}, },
} { } {
if tc.Input.typeName() != tc.Expected { if tc.Input.typeName() != tc.Expected {
t.Errorf("test %d: expected typeName value of '%v' but got '%v'", i, tc.Expected, tc.Input) t.Errorf("test %d: expected typeName value of '%v' to be '%v'", i, tc.Input, tc.Expected)
} }
} }
} }