Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
huangzhen1997 committed Jan 29, 2025
1 parent 9939559 commit 6e6441d
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 104 deletions.
56 changes: 56 additions & 0 deletions core/capabilities/ccip/ccipevm/extradatadecoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package ccipevm

import (
"fmt"

cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
)

func DecodeDestExecDataToMap(DestExecData cciptypes.Bytes) (map[string]interface{}, error) {
destGasAmount, err := abiDecodeUint32(DestExecData)
if err != nil {
return nil, fmt.Errorf("decode dest gas amount: %w", err)
}

return map[string]interface{}{
evmDestExecDataKey: destGasAmount,
}, nil
}

func DecodeExtraArgsToMap(extraArgs []byte) (map[string]any, error) {
if len(extraArgs) < 4 {
return nil, fmt.Errorf("extra args too short: %d, should be at least 4 (i.e the extraArgs tag)", len(extraArgs))
}

var method string
var extraByteOffset int
switch string(extraArgs[:4]) {
case string(evmExtraArgsV1Tag):
// for EVMExtraArgs, the first four bytes is the method name
method = evmV1DecodeName
extraByteOffset = 4
case string(evmExtraArgsV2Tag):
method = evmV2DecodeName
extraByteOffset = 4
case string(svmExtraArgsV1Tag):
// for SVMExtraArgs there's the four bytes plus another 32 bytes padding for the dynamic array
// https://github.com/smartcontractkit/chainlink/blob/33c0bda696b0ed97f587a46eacd5c65bed9fb2c1/contracts/src/v0.8/ccip/libraries/Client.sol#L57
// this is a temporary solution, the evm on-chain side will fix it, so the offset should just be 4 instead of 36
method = svmV1DecodeName
extraByteOffset = 36
default:
return nil, fmt.Errorf("unknown extra args tag: %x", extraArgs)
}

output := make(map[string]any)
args := make(map[string]interface{})
err := messageHasherABI.Methods[method].Inputs.UnpackIntoMap(args, extraArgs[extraByteOffset:])
if err != nil {
return nil, fmt.Errorf("abi decode extra args %v: %w", method, err)
}

for k, val := range args {
output[k] = val
}
return output, nil
}
105 changes: 105 additions & 0 deletions core/capabilities/ccip/ccipevm/extradatadecoder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package ccipevm

import (
"math/big"
"math/rand"
"testing"

"github.com/gagliardetto/solana-go"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/message_hasher"
)

func Test_decodeExtraData(t *testing.T) {
d := testSetup(t)
gasLimit := big.NewInt(rand.Int63())

t.Run("decode extra args into map evm v1", func(t *testing.T) {
encoded, err := d.contract.EncodeEVMExtraArgsV1(nil, message_hasher.ClientEVMExtraArgsV1{
GasLimit: gasLimit,
})
require.NoError(t, err)

m, err := DecodeExtraArgsToMap(encoded)
require.NoError(t, err)
require.Len(t, m, 1)

gl, exist := m["gasLimit"]
require.True(t, exist)
require.Equal(t, gl, gasLimit)
})

t.Run("decode extra args into map evm v2", func(t *testing.T) {
encoded, err := d.contract.EncodeEVMExtraArgsV2(nil, message_hasher.ClientEVMExtraArgsV2{
GasLimit: gasLimit,
AllowOutOfOrderExecution: true,
})
require.NoError(t, err)

m, err := DecodeExtraArgsToMap(encoded)
require.NoError(t, err)
require.Len(t, m, 2)

gl, exist := m["gasLimit"]
require.True(t, exist)
require.Equal(t, gl, gasLimit)

ooe, exist := m["allowOutOfOrderExecution"]
require.True(t, exist)
require.Equal(t, true, ooe)
})

t.Run("decode extra args into map svm", func(t *testing.T) {
key, err := solana.NewRandomPrivateKey()
require.NoError(t, err)
cu := uint32(10000)
bitmap := uint64(4)
ooe := false
tokenReceiver := [32]byte(key.PublicKey().Bytes())
accounts := [][32]byte{[32]byte(key.PublicKey().Bytes())}
decoded, err := d.contract.DecodeSVMExtraArgsV1(nil, cu, bitmap, ooe, tokenReceiver, accounts)
if err != nil {
return
}
encoded, err := d.contract.EncodeSVMExtraArgsV1(nil, decoded)
require.NoError(t, err)

m, err := DecodeExtraArgsToMap(encoded)
require.NoError(t, err)
require.Len(t, m, 5)

cuDecoded, exist := m["computeUnits"]
require.True(t, exist)
require.Equal(t, cuDecoded, cu)

bitmapDecoded, exist := m["accountIsWritableBitmap"]
require.True(t, exist)
require.Equal(t, bitmapDecoded, bitmap)

ooeDecoded, exist := m["allowOutOfOrderExecution"]
require.True(t, exist)
require.Equal(t, ooeDecoded, ooe)

tokenReceiverDecoded, exist := m["tokenReceiver"]
require.True(t, exist)
require.Equal(t, tokenReceiverDecoded, tokenReceiver)

accountsDecoded, exist := m["accounts"]
require.True(t, exist)
require.Equal(t, accountsDecoded, accounts)
})

t.Run("decode dest exec data into map", func(t *testing.T) {
destGasAmount := uint32(10000)
encoded, err := abiEncodeUint32(destGasAmount)
require.NoError(t, err)
m, err := DecodeDestExecDataToMap(encoded)
require.NoError(t, err)
require.Len(t, m, 1)

decoded, exist := m[evmDestExecDataKey]
require.True(t, exist)
require.Equal(t, destGasAmount, decoded)
})
}
50 changes: 0 additions & 50 deletions core/capabilities/ccip/ccipevm/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
)

const (
Expand Down Expand Up @@ -51,55 +50,6 @@ func decodeExtraArgsV1V2(extraArgs []byte) (gasLimit *big.Int, err error) {
return ifaces[0].(*big.Int), nil
}

func DecodeDestExecDataToMap(DestExecData cciptypes.Bytes) (map[string]interface{}, error) {
destGasAmount, err := abiDecodeUint32(DestExecData)
if err != nil {
return nil, fmt.Errorf("decode dest gas amount: %w", err)
}

return map[string]interface{}{
evmDestExecDataKey: destGasAmount,
}, nil
}

func DecodeExtraArgsToMap(extraArgs []byte) (map[string]any, error) {
if len(extraArgs) < 4 {
return nil, fmt.Errorf("extra args too short: %d, should be at least 4 (i.e the extraArgs tag)", len(extraArgs))
}

var method string
var extraByteOffset int
switch string(extraArgs[:4]) {
case string(evmExtraArgsV1Tag):
// for EVMExtraArgs, the first four bytes is the method name
method = evmV1DecodeName
extraByteOffset = 4
case string(evmExtraArgsV2Tag):
method = evmV2DecodeName
extraByteOffset = 4
case string(svmExtraArgsV1Tag):
// for SVMExtraArgs there's the four bytes plus another 32 bytes padding for the dynamic array
// https://github.com/smartcontractkit/chainlink/blob/33c0bda696b0ed97f587a46eacd5c65bed9fb2c1/contracts/src/v0.8/ccip/libraries/Client.sol#L57
// this is a temporary solution, the evm on-chain side will fix it, so the offset should just be 4 instead of 36
method = svmV1DecodeName
extraByteOffset = 36
default:
return nil, fmt.Errorf("unknown extra args tag: %x", extraArgs)
}

output := make(map[string]any)
args := make(map[string]interface{})
err := messageHasherABI.Methods[method].Inputs.UnpackIntoMap(args, extraArgs[extraByteOffset:])
if err != nil {
return nil, fmt.Errorf("abi decode extra args %v: %w", method, err)
}

for k, val := range args {
output[k] = val
}
return output, nil
}

// abiEncodeMethodInputs encodes the inputs for a method call.
// example abi: `[{ "name" : "method", "type": "function", "inputs": [{"name": "a", "type": "uint256"}]}]`
func abiEncodeMethodInputs(abiDef abi.ABI, inputs ...interface{}) ([]byte, error) {
Expand Down
54 changes: 0 additions & 54 deletions core/capabilities/ccip/ccipevm/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"math/rand"
"testing"

"github.com/gagliardetto/solana-go"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/message_hasher"
Expand Down Expand Up @@ -74,57 +73,4 @@ func Test_decodeExtraArgs(t *testing.T) {
require.True(t, exist)
require.Equal(t, true, ooe)
})

t.Run("decode dest exec data into map", func(t *testing.T) {
destGasAmount := uint32(10000)
encoded, err := abiEncodeUint32(destGasAmount)
require.NoError(t, err)
m, err := DecodeDestExecDataToMap(encoded)
require.NoError(t, err)
require.Len(t, m, 1)

decoded, exist := m[evmDestExecDataKey]
require.True(t, exist)
require.Equal(t, destGasAmount, decoded)
})

t.Run("decode extra args into map svm", func(t *testing.T) {
key, err := solana.NewRandomPrivateKey()
require.NoError(t, err)
cu := uint32(10000)
bitmap := uint64(4)
ooe := false
tokenReceiver := [32]byte(key.PublicKey().Bytes())
accounts := [][32]byte{[32]byte(key.PublicKey().Bytes())}
decoded, err := d.contract.DecodeSVMExtraArgsV1(nil, cu, bitmap, ooe, tokenReceiver, accounts)
if err != nil {
return
}
encoded, err := d.contract.EncodeSVMExtraArgsV1(nil, decoded)
require.NoError(t, err)

m, err := DecodeExtraArgsToMap(encoded)
require.NoError(t, err)
require.Len(t, m, 5)

cuDecoded, exist := m["computeUnits"]
require.True(t, exist)
require.Equal(t, cuDecoded, cu)

bitmapDecoded, exist := m["accountIsWritableBitmap"]
require.True(t, exist)
require.Equal(t, bitmapDecoded, bitmap)

ooeDecoded, exist := m["allowOutOfOrderExecution"]
require.True(t, exist)
require.Equal(t, ooeDecoded, ooe)

tokenReceiverDecoded, exist := m["tokenReceiver"]
require.True(t, exist)
require.Equal(t, tokenReceiverDecoded, tokenReceiver)

accountsDecoded, exist := m["accounts"]
require.True(t, exist)
require.Equal(t, accountsDecoded, accounts)
})
}

0 comments on commit 6e6441d

Please sign in to comment.