mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
CORE-2543 Investigate geth fork
This commit is contained in:
parent
9fd3f8a0dd
commit
c16b1a357b
6 changed files with 2551 additions and 6352 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8506
signer/core/apitypes/testdata/typed-data.json
vendored
8506
signer/core/apitypes/testdata/typed-data.json
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -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 {
|
||||||
|
input = *args.Input
|
||||||
|
} else if args.Data != nil {
|
||||||
|
input = *args.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
var data types.TxData
|
var data types.TxData
|
||||||
switch {
|
switch {
|
||||||
case args.BlobHashes != nil:
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return false
|
||||||
|
|
||||||
// Checks if the primitive value is valid
|
|
||||||
func isPrimitiveTypeValid(primitiveType string) bool {
|
|
||||||
input := strings.Split(primitiveType, "[")[0]
|
|
||||||
_, 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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue