From eafd71c97692e68585b2549ae8e6e008d15d0175 Mon Sep 17 00:00:00 2001 From: Peter Broadhurst Date: Wed, 23 Oct 2024 20:48:07 -0400 Subject: [PATCH 1/4] Allow formatting of string errors separately from matching Signed-off-by: Peter Broadhurst --- pkg/abi/abi.go | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/pkg/abi/abi.go b/pkg/abi/abi.go index 8e4dc6a2..6f68dd23 100644 --- a/pkg/abi/abi.go +++ b/pkg/abi/abi.go @@ -340,29 +340,35 @@ func (a ABI) ErrorString(revertData []byte) (string, bool) { return a.ErrorStringCtx(context.Background(), revertData) } -func (a ABI) ErrorStringCtx(ctx context.Context, revertData []byte) (string, bool) { - var parsed []interface{} +func (a ABI) ErrorStringCtx(ctx context.Context, revertData []byte) (strError string, ok bool) { e, cv, ok := a.ParseErrorCtx(ctx, revertData) if ok { - if res, err := NewSerializer().SetFormattingMode(FormatAsFlatArrays).SerializeInterfaceCtx(ctx, cv); err == nil { - parsed, ok = res.([]interface{}) - } + strError = FormatErrorStringCtx(ctx, e, cv) + ok = strError != "" } - if !ok || parsed == nil { - return "", false + return strError, ok +} + +func FormatErrorStringCtx(ctx context.Context, e *Entry, cv *ComponentValue) string { + var ok bool + var parsed []interface{} + if res, err := NewSerializer().SetFormattingMode(FormatAsFlatArrays).SerializeInterfaceCtx(ctx, cv); err == nil { + parsed, ok = res.([]interface{}) } - buff := new(bytes.Buffer) - buff.WriteString(e.Name) - buff.WriteRune('(') - for i, c := range parsed { - if i > 0 { - buff.WriteRune(',') + buff := new(strings.Builder) + if ok && parsed != nil { + buff.WriteString(e.Name) + buff.WriteRune('(') + for i, c := range parsed { + if i > 0 { + buff.WriteRune(',') + } + b, _ := json.Marshal(c) + buff.Write(b) } - b, _ := json.Marshal(c) - buff.Write(b) + buff.WriteRune(')') } - buff.WriteRune(')') - return buff.String(), true + return buff.String() } // Validate processes all the components of all the parameters in this ABI entry From 13d52d4241be4088e0c6a41b1b8ccb6c5df7c80a Mon Sep 17 00:00:00 2001 From: Peter Broadhurst Date: Wed, 23 Oct 2024 21:05:04 -0400 Subject: [PATCH 2/4] Format bytes/addresses in errors with 0x Signed-off-by: Peter Broadhurst --- pkg/abi/abi.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/abi/abi.go b/pkg/abi/abi.go index 6f68dd23..ece7b8ad 100644 --- a/pkg/abi/abi.go +++ b/pkg/abi/abi.go @@ -352,7 +352,11 @@ func (a ABI) ErrorStringCtx(ctx context.Context, revertData []byte) (strError st func FormatErrorStringCtx(ctx context.Context, e *Entry, cv *ComponentValue) string { var ok bool var parsed []interface{} - if res, err := NewSerializer().SetFormattingMode(FormatAsFlatArrays).SerializeInterfaceCtx(ctx, cv); err == nil { + if res, err := NewSerializer(). + SetFormattingMode(FormatAsFlatArrays). + SetIntSerializer(Base10StringIntSerializer). + SetAddressSerializer(HexAddrSerializer0xPrefix). + SerializeInterfaceCtx(ctx, cv); err == nil { parsed, ok = res.([]interface{}) } buff := new(strings.Builder) From 6789f16d339eec6215bd7b3dcb96f3cf53a89693 Mon Sep 17 00:00:00 2001 From: Peter Broadhurst Date: Sun, 27 Oct 2024 11:12:21 -0400 Subject: [PATCH 3/4] Correct serializer for bytes Signed-off-by: Peter Broadhurst --- pkg/abi/abi.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/abi/abi.go b/pkg/abi/abi.go index ece7b8ad..9aaff0fb 100644 --- a/pkg/abi/abi.go +++ b/pkg/abi/abi.go @@ -355,6 +355,7 @@ func FormatErrorStringCtx(ctx context.Context, e *Entry, cv *ComponentValue) str if res, err := NewSerializer(). SetFormattingMode(FormatAsFlatArrays). SetIntSerializer(Base10StringIntSerializer). + SetByteSerializer(HexByteSerializer0xPrefix). SetAddressSerializer(HexAddrSerializer0xPrefix). SerializeInterfaceCtx(ctx, cv); err == nil { parsed, ok = res.([]interface{}) From 656dd986267eb37551f1b231aa5b7f5e2850a868 Mon Sep 17 00:00:00 2001 From: Peter Broadhurst Date: Sun, 27 Oct 2024 15:22:06 -0400 Subject: [PATCH 4/4] Allow round-tripping of unsigned EIP-1559 signature payloads Signed-off-by: Peter Broadhurst --- pkg/ethsigner/transaction.go | 25 ++++++++++++++++------- pkg/ethsigner/transaction_test.go | 33 ++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/pkg/ethsigner/transaction.go b/pkg/ethsigner/transaction.go index 22ea6a0a..26a2bb6b 100644 --- a/pkg/ethsigner/transaction.go +++ b/pkg/ethsigner/transaction.go @@ -299,8 +299,7 @@ func recoverCommon(tx *Transaction, message []byte, chainID int64, v int64, r, s }, nil } -func RecoverEIP1559Transaction(ctx context.Context, rawTx ethtypes.HexBytes0xPrefix, chainID int64) (*ethtypes.Address0xHex, *TransactionWithOriginalPayload, error) { - +func decodeEIP1559SignaturePayload(ctx context.Context, rawTx ethtypes.HexBytes0xPrefix, chainID int64, rlpMinLen int) (rlp.List, *Transaction, error) { if len(rawTx) == 0 || rawTx[0] != TransactionType1559 { return nil, nil, i18n.NewError(ctx, signermsgs.MsgInvalidEIP1559Transaction, "TransactionType") } @@ -311,18 +310,17 @@ func RecoverEIP1559Transaction(ctx context.Context, rawTx ethtypes.HexBytes0xPre log.L(ctx).Errorf("Invalid EIP-1559 transaction data '%s': %s", rawTx, err) return nil, nil, i18n.NewError(ctx, signermsgs.MsgInvalidEIP1559Transaction, err) } + rlpList := decoded.(rlp.List) - if decoded == nil || len(decoded.(rlp.List)) < 12 { - log.L(ctx).Errorf("Invalid EIP-1559 transaction data '%s': EOF", rawTx) + if len(rlpList) < rlpMinLen { + log.L(ctx).Errorf("Invalid EIP-1559 transaction data (%d RLP elements)", rlpList) return nil, nil, i18n.NewError(ctx, signermsgs.MsgInvalidEIP1559Transaction, "EOF") } - rlpList := decoded.(rlp.List) - encodedChainID := rlpList[0].ToData().IntOrZero().Int64() if encodedChainID != chainID { return nil, nil, i18n.NewError(ctx, signermsgs.MsgInvalidChainID, chainID, encodedChainID) } - tx := &Transaction{ + return rlpList, &Transaction{ Nonce: (*ethtypes.HexInteger)(rlpList[1].ToData().Int()), MaxPriorityFeePerGas: (*ethtypes.HexInteger)(rlpList[2].ToData().Int()), MaxFeePerGas: (*ethtypes.HexInteger)(rlpList[3].ToData().Int()), @@ -331,6 +329,19 @@ func RecoverEIP1559Transaction(ctx context.Context, rawTx ethtypes.HexBytes0xPre Value: (*ethtypes.HexInteger)(rlpList[6].ToData().Int()), Data: ethtypes.HexBytes0xPrefix(rlpList[7].ToData()), // No access list support + }, nil +} + +func DecodeEIP1559SignaturePayload(ctx context.Context, rawTx ethtypes.HexBytes0xPrefix, chainID int64) (*Transaction, error) { + _, tx, err := decodeEIP1559SignaturePayload(ctx, rawTx, chainID, 9 /* no signature data */) + return tx, err +} + +func RecoverEIP1559Transaction(ctx context.Context, rawTx ethtypes.HexBytes0xPrefix, chainID int64) (*ethtypes.Address0xHex, *TransactionWithOriginalPayload, error) { + + rlpList, tx, err := decodeEIP1559SignaturePayload(ctx, rawTx, chainID, 12 /* with signature data */) + if err != nil { + return nil, nil, err } return recoverCommon(tx, diff --git a/pkg/ethsigner/transaction_test.go b/pkg/ethsigner/transaction_test.go index d34bd4e5..ee0020a9 100644 --- a/pkg/ethsigner/transaction_test.go +++ b/pkg/ethsigner/transaction_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 Kaleido, Inc. +// Copyright © 2024 Kaleido, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -31,6 +31,7 @@ import ( "github.com/hyperledger/firefly-signer/pkg/secp256k1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" ) func TestEncodeExistingLegacyEIP155(t *testing.T) { @@ -294,6 +295,36 @@ func TestRecoverEIP1559BadStructure(t *testing.T) { assert.Regexp(t, "FF22084.*EOF", err) } +func TestDecodeEIP1559SignaturePayloadEmpty(t *testing.T) { + _, err := DecodeEIP1559SignaturePayload(context.Background(), []byte{}, 1001) + assert.Regexp(t, "FF22084.*TransactionType", err) +} + +func TestRoundTripEIP1559Payload(t *testing.T) { + + txIn := Transaction{ + Nonce: ethtypes.NewHexInteger64(3), + GasLimit: ethtypes.NewHexInteger64(40574), + MaxPriorityFeePerGas: ethtypes.NewHexInteger64(505050), + MaxFeePerGas: ethtypes.NewHexInteger64(606060), + To: ethtypes.MustNewAddress("0x497eedc4299dea2f2a364be10025d0ad0f702de3"), + Data: ethtypes.MustNewHexBytes0xPrefix("0xfeedbeef"), + Value: ethtypes.NewHexInteger64(100000000), + } + abiData := txIn.SignaturePayloadEIP1559(1001).Bytes() + + txOut, err := DecodeEIP1559SignaturePayload(context.Background(), abiData, 1001) + require.NoError(t, err) + + jsonIn, err := json.Marshal(txIn) + require.NoError(t, err) + jsonOut, err := json.Marshal(txOut) + require.NoError(t, err) + + require.JSONEq(t, string(jsonIn), string(jsonOut)) + +} + func TestRecoverEIP1559BadChainID(t *testing.T) { _, _, err := RecoverEIP1559Transaction(context.Background(), append([]byte{TransactionType1559}, (rlp.List{ rlp.WrapInt(big.NewInt(111)),