Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version abstraction part 2 #180

Merged
merged 33 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ef17ad6
Price reg wip
connorwstein Sep 28, 2023
5229810
Wip
connorwstein Sep 28, 2023
d114b00
Wip
connorwstein Oct 2, 2023
4bd69cb
Merge branch 'ccip-develop' into feature/backwards-compat-part2
connorwstein Oct 2, 2023
5c27967
Progress on config versioning
connorwstein Oct 2, 2023
9a9d094
Report encoding
connorwstein Oct 2, 2023
b444c0a
More cleanup
connorwstein Oct 2, 2023
c2751bf
Regen mocks
connorwstein Oct 2, 2023
30076f3
TODOs
connorwstein Oct 3, 2023
b877f2a
Filter testing
connorwstein Oct 3, 2023
02b1958
Fix a test, generate mocks
connorwstein Oct 3, 2023
1ae17d2
Compiling
connorwstein Oct 3, 2023
e08837f
Fix some tests and lints
connorwstein Oct 3, 2023
461170b
First pass self review
connorwstein Oct 3, 2023
629a789
fix commit plugin observation test case
matYang Oct 4, 2023
28421b3
fix da tests
dimkouv Oct 4, 2023
ea2b720
tiny commit plugin test prettify
matYang Oct 4, 2023
d4a8544
Fix lint and metatx
connorwstein Oct 4, 2023
87aea9b
Merge branch 'ccip-develop' into feature/backwards-compat-part2
connorwstein Oct 4, 2023
437df74
Merge branch 'feature/backwards-compat-part2' of github.com:smartcont…
connorwstein Oct 4, 2023
6d071cf
Fix several bugs
connorwstein Oct 4, 2023
6565148
Fix commit reader encoding
connorwstein Oct 4, 2023
7b393f1
Add lock for dynamic config
connorwstein Oct 4, 2023
7c3abd6
Fix exec encoding
connorwstein Oct 4, 2023
a9198c6
Fix meta test
connorwstein Oct 4, 2023
c20ec9b
Fix test
connorwstein Oct 4, 2023
f280c55
Permit empty gas prices
connorwstein Oct 4, 2023
0274a89
PR comments
connorwstein Oct 5, 2023
f8de232
Fix tests and regen
connorwstein Oct 5, 2023
57da55f
Fix tests
connorwstein Oct 5, 2023
4432504
Update mock
connorwstein Oct 5, 2023
b7869ea
Comments
connorwstein Oct 5, 2023
1f6878e
Fix tests
connorwstein Oct 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions core/services/metatx/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey"
"github.com/smartcontractkit/chainlink/v2/core/services/metatx"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
integrationtesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/integration"
)
Expand Down Expand Up @@ -235,7 +234,7 @@ merge [type=merge left="{}" right="{\\\"%s\\\":$(link_parse), \\\"%s\\\":$(eth_p

executionLogs := ccipContracts.AllNodesHaveExecutedSeqNums(t, geCurrentSeqNum, geCurrentSeqNum)
assert.Len(t, executionLogs, 1)
ccipContracts.AssertExecState(t, executionLogs[0], abihelpers.ExecutionStateSuccess)
ccipContracts.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)

// source token is locked in the token pool
lockedTokenBal, err := sourceToken.BalanceOf(nil, sourcePoolAddress)
Expand Down
223 changes: 15 additions & 208 deletions core/services/ocr2/plugins/ccip/abihelpers/abi_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,101 +10,40 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry"
"github.com/smartcontractkit/chainlink/v2/core/utils"
)

// MessageExecutionState defines the execution states of CCIP messages.
type MessageExecutionState uint8

const (
ExecutionStateUntouched MessageExecutionState = iota
ExecutionStateInProgress
ExecutionStateSuccess
ExecutionStateFailure
)

// TODO: Deprecate in favour of version specific types
var EventSignatures struct {
// CommitStore
ReportAccepted common.Hash
// OffRamp
ExecutionStateChanged common.Hash
PoolAdded common.Hash
PoolRemoved common.Hash

// PriceRegistry
UsdPerUnitGasUpdated common.Hash
UsdPerTokenUpdated common.Hash
FeeTokenAdded common.Hash
FeeTokenRemoved common.Hash

// offset || priceUpdatesOffset || minSeqNum || maxSeqNum || merkleRoot
ReportAcceptedMaxSequenceNumberWord int
// sig || seqNum || messageId || ...
ExecutionStateChangedSequenceNumberIndex int
}

var (
MessageArgs abi.Arguments
TokenAmountsArgs abi.Arguments
CommitReportArgs abi.Arguments
ExecutionReportArgs abi.Arguments
)

func GetIDOrPanic(name string, abi2 abi.ABI) common.Hash {
func MustGetEventID(name string, abi2 abi.ABI) common.Hash {
event, ok := abi2.Events[name]
if !ok {
panic(fmt.Sprintf("missing event %s", name))
}
return event.ID
}

func init() {
commitStoreABI, err := abi.JSON(strings.NewReader(commit_store.CommitStoreABI))
if err != nil {
panic(err)
}
EventSignatures.ReportAccepted = GetIDOrPanic("ReportAccepted", commitStoreABI)
EventSignatures.ReportAcceptedMaxSequenceNumberWord = 3

offRampABI, err := abi.JSON(strings.NewReader(evm_2_evm_offramp.EVM2EVMOffRampABI))
if err != nil {
panic(err)
}
EventSignatures.ExecutionStateChanged = GetIDOrPanic("ExecutionStateChanged", offRampABI)
EventSignatures.ExecutionStateChangedSequenceNumberIndex = 1
EventSignatures.PoolAdded = GetIDOrPanic("PoolAdded", offRampABI)
EventSignatures.PoolRemoved = GetIDOrPanic("PoolRemoved", offRampABI)

priceRegistryABI, err := abi.JSON(strings.NewReader(price_registry.PriceRegistryABI))
if err != nil {
panic(err)
func MustGetEventInputs(name string, abi2 abi.ABI) abi.Arguments {
m, ok := abi2.Events[name]
if !ok {
panic(fmt.Sprintf("missing event %s", name))
}
EventSignatures.UsdPerUnitGasUpdated = GetIDOrPanic("UsdPerUnitGasUpdated", priceRegistryABI)
EventSignatures.UsdPerTokenUpdated = GetIDOrPanic("UsdPerTokenUpdated", priceRegistryABI)
EventSignatures.FeeTokenAdded = GetIDOrPanic("FeeTokenAdded", priceRegistryABI)
EventSignatures.FeeTokenRemoved = GetIDOrPanic("FeeTokenRemoved", priceRegistryABI)

CommitReportArgs = commitStoreABI.Events["ReportAccepted"].Inputs
return m.Inputs
}

manuallyExecuteMethod, ok := offRampABI.Methods["manuallyExecute"]
func MustGetMethodInputs(name string, abi2 abi.ABI) abi.Arguments {
m, ok := abi2.Methods[name]
if !ok {
panic("missing event 'manuallyExecute'")
panic(fmt.Sprintf("missing method %s", name))
}
ExecutionReportArgs = manuallyExecuteMethod.Inputs[:1]
return m.Inputs
}

func MessagesFromExecutionReport(report types.Report) ([]evm_2_evm_offramp.InternalEVM2EVMMessage, error) {
decodedExecutionReport, err := DecodeExecutionReport(report)
func MustParseABI(abiStr string) abi.ABI {
dimkouv marked this conversation as resolved.
Show resolved Hide resolved
abiParsed, err := abi.JSON(strings.NewReader(abiStr))
if err != nil {
return nil, err
panic(err)
}
return decodedExecutionReport.Messages, nil
return abiParsed
}

// ProofFlagsToBits transforms a list of boolean proof flags to a *big.Int
Expand All @@ -119,138 +58,6 @@ func ProofFlagsToBits(proofFlags []bool) *big.Int {
return encodedFlags
}

func EncodeExecutionReport(execReport evm_2_evm_offramp.InternalExecutionReport) ([]byte, error) {
return ExecutionReportArgs.PackValues([]interface{}{&execReport})
}

func DecodeExecutionReport(report []byte) (evm_2_evm_offramp.InternalExecutionReport, error) {
unpacked, err := ExecutionReportArgs.Unpack(report)
if err != nil {
return evm_2_evm_offramp.InternalExecutionReport{}, err
}
if len(unpacked) == 0 {
return evm_2_evm_offramp.InternalExecutionReport{}, errors.New("assumptionViolation: expected at least one element")
}

// Must be anonymous struct here
erStruct, ok := unpacked[0].(struct {
Messages []struct {
SourceChainSelector uint64 `json:"sourceChainSelector"`
Sender common.Address `json:"sender"`
Receiver common.Address `json:"receiver"`
SequenceNumber uint64 `json:"sequenceNumber"`
GasLimit *big.Int `json:"gasLimit"`
Strict bool `json:"strict"`
Nonce uint64 `json:"nonce"`
FeeToken common.Address `json:"feeToken"`
FeeTokenAmount *big.Int `json:"feeTokenAmount"`
Data []uint8 `json:"data"`
TokenAmounts []struct {
Token common.Address `json:"token"`
Amount *big.Int `json:"amount"`
} `json:"tokenAmounts"`
SourceTokenData [][]byte `json:"sourceTokenData"`
MessageId [32]byte `json:"messageId"`
} `json:"messages"`
OffchainTokenData [][][]byte `json:"offchainTokenData"`
Proofs [][32]uint8 `json:"proofs"`
ProofFlagBits *big.Int `json:"proofFlagBits"`
})
if !ok {
return evm_2_evm_offramp.InternalExecutionReport{}, fmt.Errorf("got %T", unpacked[0])
}
var er evm_2_evm_offramp.InternalExecutionReport
er.Messages = []evm_2_evm_offramp.InternalEVM2EVMMessage{}

for _, msg := range erStruct.Messages {
var tokensAndAmounts []evm_2_evm_offramp.ClientEVMTokenAmount
for _, tokenAndAmount := range msg.TokenAmounts {
tokensAndAmounts = append(tokensAndAmounts, evm_2_evm_offramp.ClientEVMTokenAmount{
Token: tokenAndAmount.Token,
Amount: tokenAndAmount.Amount,
})
}
er.Messages = append(er.Messages, evm_2_evm_offramp.InternalEVM2EVMMessage{
SourceChainSelector: msg.SourceChainSelector,
SequenceNumber: msg.SequenceNumber,
FeeTokenAmount: msg.FeeTokenAmount,
Sender: msg.Sender,
Nonce: msg.Nonce,
GasLimit: msg.GasLimit,
Strict: msg.Strict,
Receiver: msg.Receiver,
Data: msg.Data,
TokenAmounts: tokensAndAmounts,
SourceTokenData: msg.SourceTokenData,
FeeToken: msg.FeeToken,
MessageId: msg.MessageId,
})
}

er.OffchainTokenData = erStruct.OffchainTokenData
er.Proofs = append(er.Proofs, erStruct.Proofs...)
// Unpack will populate with big.Int{false, <allocated empty nat>} for 0 values,
// which is different from the expected big.NewInt(0). Rebuild to the expected value for this case.
er.ProofFlagBits = new(big.Int).SetBytes(erStruct.ProofFlagBits.Bytes())
return er, nil
}

// EncodeCommitReport abi encodes an offramp.InternalCommitReport.
func EncodeCommitReport(commitReport commit_store.CommitStoreCommitReport) ([]byte, error) {
return CommitReportArgs.PackValues([]interface{}{commitReport})
}

// DecodeCommitReport abi decodes a types.Report to an CommitStoreCommitReport
func DecodeCommitReport(report []byte) (commit_store.CommitStoreCommitReport, error) {
unpacked, err := CommitReportArgs.Unpack(report)
if err != nil {
return commit_store.CommitStoreCommitReport{}, err
}
if len(unpacked) != 1 {
return commit_store.CommitStoreCommitReport{}, errors.New("expected single struct value")
}

commitReport, ok := unpacked[0].(struct {
PriceUpdates struct {
TokenPriceUpdates []struct {
SourceToken common.Address `json:"sourceToken"`
UsdPerToken *big.Int `json:"usdPerToken"`
} `json:"tokenPriceUpdates"`
DestChainSelector uint64 `json:"destChainSelector"`
UsdPerUnitGas *big.Int `json:"usdPerUnitGas"`
} `json:"priceUpdates"`
Interval struct {
Min uint64 `json:"min"`
Max uint64 `json:"max"`
} `json:"interval"`
MerkleRoot [32]byte `json:"merkleRoot"`
})
if !ok {
return commit_store.CommitStoreCommitReport{}, errors.Errorf("invalid commit report got %T", unpacked[0])
}

var tokenPriceUpdates []commit_store.InternalTokenPriceUpdate
for _, u := range commitReport.PriceUpdates.TokenPriceUpdates {
tokenPriceUpdates = append(tokenPriceUpdates, commit_store.InternalTokenPriceUpdate{
SourceToken: u.SourceToken,
UsdPerToken: u.UsdPerToken,
})
}

return commit_store.CommitStoreCommitReport{
PriceUpdates: commit_store.InternalPriceUpdates{
DestChainSelector: commitReport.PriceUpdates.DestChainSelector,
UsdPerUnitGas: commitReport.PriceUpdates.UsdPerUnitGas,
TokenPriceUpdates: tokenPriceUpdates,
},
Interval: commit_store.CommitStoreInterval{
Min: commitReport.Interval.Min,
Max: commitReport.Interval.Max,
},
MerkleRoot: commitReport.MerkleRoot,
}, nil
}

type AbiDefined interface {
AbiString() string
}
Expand Down
54 changes: 0 additions & 54 deletions core/services/ocr2/plugins/ccip/abihelpers/abi_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@ import (
"fmt"
"math"
"math/big"
"math/rand"
"testing"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
"github.com/smartcontractkit/chainlink/v2/core/utils"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/test-go/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
)

func TestProofFlagToBits(t *testing.T) {
Expand Down Expand Up @@ -62,52 +54,6 @@ func TestProofFlagToBits(t *testing.T) {
}
}

func TestCommitReportEncoding(t *testing.T) {
report := commit_store.CommitStoreCommitReport{
PriceUpdates: commit_store.InternalPriceUpdates{
TokenPriceUpdates: []commit_store.InternalTokenPriceUpdate{
{
SourceToken: utils.RandomAddress(),
UsdPerToken: big.NewInt(9e18),
},
},
DestChainSelector: rand.Uint64(),
UsdPerUnitGas: big.NewInt(2000e9),
},
MerkleRoot: [32]byte{123},
Interval: commit_store.CommitStoreInterval{Min: 1, Max: 10},
}

encodedReport, err := EncodeCommitReport(report)
require.NoError(t, err)

decodedReport, err := DecodeCommitReport(encodedReport)
require.NoError(t, err)
require.Equal(t, report, decodedReport)
}

func TestExecutionReportEncoding(t *testing.T) {
// Note could consider some fancier testing here (fuzz/property)
// but I think that would essentially be testing geth's abi library
// as our encode/decode is a thin wrapper around that.
report := evm_2_evm_offramp.InternalExecutionReport{
Messages: []evm_2_evm_offramp.InternalEVM2EVMMessage{},
OffchainTokenData: [][][]byte{{}},
Proofs: [][32]byte{testutils.Random32Byte()},
ProofFlagBits: big.NewInt(133),
}
encodeExecutionReport, err := EncodeExecutionReport(evm_2_evm_offramp.InternalExecutionReport{
Messages: report.Messages,
OffchainTokenData: report.OffchainTokenData,
Proofs: report.Proofs,
ProofFlagBits: report.ProofFlagBits,
})
require.NoError(t, err)
decodeCommitReport, err := DecodeExecutionReport(encodeExecutionReport)
require.NoError(t, err)
require.Equal(t, report, decodeCommitReport)
}

func TestEvmWord(t *testing.T) {
testCases := []struct {
inp uint64
Expand Down
Loading
Loading