Skip to content

Commit 76378f1

Browse files
committed
test observation next
1 parent cbace54 commit 76378f1

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed

commit/plugin_next_test.go

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
package commit
2+
3+
import (
4+
"errors"
5+
"math/big"
6+
"testing"
7+
"time"
8+
9+
chainsel "github.com/smartcontractkit/chain-selectors"
10+
"github.com/smartcontractkit/chainlink-common/pkg/logger"
11+
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
12+
"github.com/smartcontractkit/libocr/commontypes"
13+
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
14+
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"
15+
"github.com/stretchr/testify/mock"
16+
"github.com/stretchr/testify/require"
17+
18+
"github.com/smartcontractkit/chainlink-ccip/commit/chainfee"
19+
"github.com/smartcontractkit/chainlink-ccip/commit/committypes"
20+
"github.com/smartcontractkit/chainlink-ccip/commit/merkleroot"
21+
"github.com/smartcontractkit/chainlink-ccip/commit/metrics"
22+
"github.com/smartcontractkit/chainlink-ccip/commit/tokenprice"
23+
"github.com/smartcontractkit/chainlink-ccip/mocks/internal_/plugincommon"
24+
reader2 "github.com/smartcontractkit/chainlink-ccip/mocks/internal_/reader"
25+
"github.com/smartcontractkit/chainlink-ccip/mocks/pkg/reader"
26+
v1 "github.com/smartcontractkit/chainlink-ccip/pkg/ocrtypecodec/v1"
27+
"github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
28+
)
29+
30+
func Test_observationNext_prices(t *testing.T) {
31+
destChainSel := chainsel.ABSTRACT_TESTNET.Selector
32+
fDestChain := 2
33+
testCases := []struct {
34+
name string
35+
oracleSupportsDestChain bool
36+
currentRoundOcrSeqNum uint64
37+
inflightOcrSeqNum uint64
38+
remainingChecks int
39+
onchainOcrSeqNum uint64
40+
rpcErr error
41+
expObservedOnChainOcrSeqNum uint64
42+
expObservedPrices bool
43+
}{
44+
{
45+
name: "no inflight prices, no onchain prices, initial state",
46+
oracleSupportsDestChain: true,
47+
currentRoundOcrSeqNum: 1,
48+
inflightOcrSeqNum: 0,
49+
remainingChecks: 0,
50+
onchainOcrSeqNum: 0,
51+
expObservedOnChainOcrSeqNum: 0,
52+
expObservedPrices: false,
53+
},
54+
{
55+
name: "initial prices observed on this round",
56+
oracleSupportsDestChain: true,
57+
currentRoundOcrSeqNum: 2,
58+
inflightOcrSeqNum: 0,
59+
remainingChecks: 0,
60+
onchainOcrSeqNum: 0,
61+
expObservedOnChainOcrSeqNum: 0,
62+
expObservedPrices: true,
63+
},
64+
{
65+
name: "inflight prices from previous round not seen on-chain",
66+
oracleSupportsDestChain: true,
67+
currentRoundOcrSeqNum: 3,
68+
inflightOcrSeqNum: 2,
69+
remainingChecks: 10,
70+
onchainOcrSeqNum: 0,
71+
expObservedOnChainOcrSeqNum: 0,
72+
expObservedPrices: false,
73+
},
74+
{
75+
name: "inflight prices from previous round are seen on-chain",
76+
oracleSupportsDestChain: true,
77+
currentRoundOcrSeqNum: 5,
78+
inflightOcrSeqNum: 2,
79+
remainingChecks: 10,
80+
onchainOcrSeqNum: 2, // <--
81+
expObservedOnChainOcrSeqNum: 2,
82+
expObservedPrices: false,
83+
},
84+
{
85+
name: "inflight prices seen on-chain but oracle des not support dest",
86+
oracleSupportsDestChain: false,
87+
currentRoundOcrSeqNum: 5,
88+
inflightOcrSeqNum: 2,
89+
remainingChecks: 10,
90+
onchainOcrSeqNum: 2,
91+
expObservedOnChainOcrSeqNum: 0, // <-- observes 0
92+
expObservedPrices: false,
93+
},
94+
{
95+
name: "no inflight prices, no onchain prices, later state",
96+
oracleSupportsDestChain: true,
97+
currentRoundOcrSeqNum: 5678,
98+
inflightOcrSeqNum: 0,
99+
remainingChecks: 0,
100+
onchainOcrSeqNum: 5600,
101+
expObservedOnChainOcrSeqNum: 0,
102+
expObservedPrices: true,
103+
},
104+
{
105+
name: "inflight prices, later state",
106+
oracleSupportsDestChain: true,
107+
currentRoundOcrSeqNum: 5678,
108+
inflightOcrSeqNum: 5670, // <--
109+
remainingChecks: 50,
110+
onchainOcrSeqNum: 5600,
111+
expObservedOnChainOcrSeqNum: 5600,
112+
expObservedPrices: false,
113+
},
114+
{
115+
name: "rpc error while getting on chain seq num",
116+
oracleSupportsDestChain: true,
117+
currentRoundOcrSeqNum: 5678,
118+
inflightOcrSeqNum: 5670,
119+
remainingChecks: 50,
120+
onchainOcrSeqNum: 5600,
121+
rpcErr: errors.New("some rpc error"),
122+
expObservedOnChainOcrSeqNum: 0, // <----
123+
expObservedPrices: false,
124+
},
125+
}
126+
127+
for _, tc := range testCases {
128+
t.Run(tc.name, func(t *testing.T) {
129+
// setup mock dependencies
130+
ctx := tests.Context(t)
131+
cs := plugincommon.NewMockChainSupport(t)
132+
ccr := reader.NewMockCCIPReader(t)
133+
mrp := plugincommon.NewMockPluginProcessor[merkleroot.Query, merkleroot.Observation, merkleroot.Outcome](t)
134+
tpp := plugincommon.NewMockPluginProcessor[tokenprice.Query, tokenprice.Observation, tokenprice.Outcome](t)
135+
cfp := plugincommon.NewMockPluginProcessor[chainfee.Query, chainfee.Observation, chainfee.Outcome](t)
136+
home := reader2.NewMockHomeChain(t)
137+
138+
// initialize plugin
139+
p := &Plugin{
140+
lggr: logger.Test(t),
141+
ocrTypeCodec: v1.NewCommitCodecProto(),
142+
merkleRootProcessor: mrp,
143+
tokenPriceProcessor: tpp,
144+
chainFeeProcessor: cfp,
145+
metricsReporter: &metrics.Noop{},
146+
chainSupport: cs,
147+
ccipReader: ccr,
148+
destChain: ccipocr3.ChainSelector(destChainSel),
149+
homeChain: home,
150+
oracleID: commontypes.OracleID(9),
151+
}
152+
153+
// set expectations
154+
home.EXPECT().GetFChain().Return(map[ccipocr3.ChainSelector]int{
155+
ccipocr3.ChainSelector(destChainSel): fDestChain,
156+
}, nil)
157+
158+
cs.EXPECT().SupportsDestChain(p.oracleID).Return(tc.oracleSupportsDestChain, nil).Maybe()
159+
160+
mrp.EXPECT().Observation(mock.Anything, mock.Anything, mock.Anything).Return(merkleroot.Observation{}, nil)
161+
162+
ccr.EXPECT().GetLatestPriceSeqNr(mock.Anything).Return(tc.onchainOcrSeqNum, tc.rpcErr).Maybe()
163+
164+
tokenPriceObs := tokenprice.Observation{}
165+
if tc.expObservedPrices {
166+
tokenPriceObs.FeedTokenPrices = map[ccipocr3.UnknownEncodedAddress]ccipocr3.BigInt{
167+
"123": ccipocr3.NewBigIntFromInt64(2),
168+
}
169+
}
170+
tpp.EXPECT().Observation(mock.Anything, mock.Anything, mock.Anything).Return(tokenPriceObs, nil).Maybe()
171+
172+
chainFeeObs := chainfee.Observation{}
173+
if tc.expObservedPrices {
174+
chainFeeObs.ChainFeeUpdates = map[ccipocr3.ChainSelector]chainfee.Update{
175+
ccipocr3.ChainSelector(destChainSel): {
176+
Timestamp: time.Now(),
177+
ChainFee: chainfee.ComponentsUSDPrices{
178+
ExecutionFeePriceUSD: big.NewInt(2),
179+
DataAvFeePriceUSD: big.NewInt(3),
180+
},
181+
},
182+
}
183+
}
184+
cfp.EXPECT().Observation(mock.Anything, mock.Anything, mock.Anything).Return(chainFeeObs, nil).Maybe()
185+
186+
// encode previous outcome and call observation function
187+
prevOutcome, err := p.ocrTypeCodec.EncodeOutcome(committypes.Outcome{
188+
MainOutcome: committypes.MainOutcome{
189+
InflightPriceOcrSequenceNumber: ccipocr3.SeqNum(tc.inflightOcrSeqNum),
190+
RemainingPriceChecks: tc.remainingChecks,
191+
},
192+
})
193+
require.NoError(t, err)
194+
195+
obsBytes, err := p.observationNext(ctx, ocr3types.OutcomeContext{
196+
SeqNr: tc.currentRoundOcrSeqNum,
197+
PreviousOutcome: prevOutcome,
198+
}, types.Query{})
199+
require.NoError(t, err)
200+
201+
// assert results are the expected
202+
obs, err := p.ocrTypeCodec.DecodeObservation(obsBytes)
203+
require.NoError(t, err)
204+
205+
require.Equal(t, tc.expObservedOnChainOcrSeqNum, obs.OnChainPriceOcrSeqNum)
206+
if tc.expObservedPrices {
207+
require.NotEmpty(t, obs.TokenPriceObs.FeedTokenPrices)
208+
require.NotEmpty(t, obs.ChainFeeObs.ChainFeeUpdates)
209+
}
210+
})
211+
}
212+
}

0 commit comments

Comments
 (0)