Skip to content

Commit f102724

Browse files
Unheilbarreductionista
authored andcommitted
implement extended evm service interface (#17496)
* implement extended evm service interface * bump evm, solana, common * make tidy * generate * tidy * generate * gen config docs * add tests * update common * add tests * bump common * bump common * bump deps * bump deps * make config docs * bump common * bump common * update types * bump deps * tidy * bump depl framework * make generate * revert modified * tidy * rm mocked * bump common * fix tests * bump common * bump dependncies * bump dependencies
1 parent 272982c commit f102724

File tree

3 files changed

+445
-5
lines changed

3 files changed

+445
-5
lines changed

core/services/relay/evm/evm.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import (
3535
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
3636
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
3737
cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
38-
commonevmtypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm"
3938
coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core"
4039
"github.com/smartcontractkit/chainlink-evm/pkg/config/chaintype"
4140
"github.com/smartcontractkit/chainlink-evm/pkg/keys"
@@ -1002,10 +1001,6 @@ func (r *Relayer) EVM() (commontypes.EVMService, error) {
10021001
return r, nil
10031002
}
10041003

1005-
func (r *Relayer) GetTransactionFee(ctx context.Context, transactionID string) (*commonevmtypes.TransactionFee, error) {
1006-
return r.chain.TxManager().GetTransactionFee(ctx, transactionID)
1007-
}
1008-
10091004
func (r *Relayer) NewMedianProvider(ctx context.Context, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.MedianProvider, error) {
10101005
lggr := logger.Sugared(r.lggr).Named("MedianProvider").Named(rargs.ExternalJobID.String())
10111006
relayOpts := types.NewRelayOpts(rargs)
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
package evm
2+
3+
import (
4+
"context"
5+
"math/big"
6+
7+
"github.com/ethereum/go-ethereum"
8+
"github.com/ethereum/go-ethereum/common"
9+
gethtypes "github.com/ethereum/go-ethereum/core/types"
10+
"github.com/pkg/errors"
11+
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
12+
"github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm"
13+
evmtypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm"
14+
15+
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
16+
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
17+
"github.com/smartcontractkit/chainlink-evm/pkg/heads"
18+
"github.com/smartcontractkit/chainlink-evm/pkg/logpoller"
19+
"github.com/smartcontractkit/chainlink-evm/pkg/types"
20+
"github.com/smartcontractkit/chainlink-framework/chains"
21+
)
22+
23+
// Direct RPC
24+
func (r *Relayer) CallContract(ctx context.Context, msg *evmtypes.CallMsg, blockNumber *big.Int) ([]byte, error) {
25+
return r.chain.Client().CallContract(ctx, toEthMsg(msg), blockNumber)
26+
}
27+
28+
func (r *Relayer) FilterLogs(ctx context.Context, filterQuery evmtypes.FilterQuery) ([]*evmtypes.Log, error) {
29+
logs, err := r.chain.Client().FilterLogs(ctx, convertEthFilter(filterQuery))
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
ret := make([]*evmtypes.Log, 0, len(logs))
35+
36+
for _, l := range logs {
37+
ret = append(ret, convertLog(&l))
38+
}
39+
40+
return ret, nil
41+
}
42+
43+
func (r *Relayer) BalanceAt(ctx context.Context, account evmtypes.Address, blockNumber *big.Int) (*big.Int, error) {
44+
return r.chain.Client().BalanceAt(ctx, account, blockNumber)
45+
}
46+
47+
func (r *Relayer) EstimateGas(ctx context.Context, call *evmtypes.CallMsg) (uint64, error) {
48+
return r.chain.Client().EstimateGas(ctx, toEthMsg(call))
49+
}
50+
51+
func (r *Relayer) TransactionByHash(ctx context.Context, hash evmtypes.Hash) (*evmtypes.Transaction, error) {
52+
tx, err := r.chain.Client().TransactionByHash(ctx, hash)
53+
if err != nil {
54+
return nil, err
55+
}
56+
57+
return convertTransaction(tx), nil
58+
}
59+
60+
func (r *Relayer) TransactionReceipt(ctx context.Context, txHash evmtypes.Hash) (*evmtypes.Receipt, error) {
61+
receipt, err := r.chain.Client().TransactionReceipt(ctx, txHash)
62+
if err != nil {
63+
return nil, err
64+
}
65+
66+
return convertReceipt(receipt), nil
67+
}
68+
69+
// ChainService
70+
func (r *Relayer) GetTransactionFee(ctx context.Context, transactionID commontypes.IdempotencyKey) (*evmtypes.TransactionFee, error) {
71+
return r.chain.TxManager().GetTransactionFee(ctx, transactionID)
72+
}
73+
74+
func (r *Relayer) LatestAndFinalizedHead(ctx context.Context) (evmtypes.Head, evmtypes.Head, error) {
75+
latest, finalized, err := r.chain.HeadTracker().LatestAndFinalizedBlock(ctx)
76+
if err != nil {
77+
return evmtypes.Head{}, evmtypes.Head{}, err
78+
}
79+
80+
return convertHead(latest), convertHead(finalized), nil
81+
}
82+
83+
func (r *Relayer) QueryTrackedLogs(ctx context.Context, filterQuery []query.Expression,
84+
limitAndSort query.LimitAndSort, confidenceLevel primitives.ConfidenceLevel) ([]*evmtypes.Log, error) {
85+
// TODO move evm specific expressions to common
86+
// TODO check if required filters[event sig and address] are set
87+
// TODO specify query name BCFR-1328
88+
// BCFR-1328
89+
conformations := confidenceToConformations(confidenceLevel)
90+
filterQuery = append(filterQuery, logpoller.NewConfirmationsFilter(conformations))
91+
logs, err := r.chain.LogPoller().FilteredLogs(ctx, filterQuery, limitAndSort, "")
92+
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
return convertLPLogs(logs), nil
98+
}
99+
100+
func (r *Relayer) RegisterLogTracking(ctx context.Context, filter evmtypes.LPFilterQuery) error {
101+
lpfilter, err := convertLPFilter(filter)
102+
if err != nil {
103+
return err
104+
}
105+
if r.chain.LogPoller().HasFilter(lpfilter.Name) {
106+
return nil
107+
}
108+
109+
return r.chain.LogPoller().RegisterFilter(ctx, lpfilter)
110+
}
111+
112+
func (r *Relayer) UnregisterLogTracking(ctx context.Context, filterName string) error {
113+
if filterName == "" {
114+
return errEmptyFilterName
115+
}
116+
if !r.chain.LogPoller().HasFilter(filterName) {
117+
return nil
118+
}
119+
120+
return r.chain.LogPoller().UnregisterFilter(ctx, filterName)
121+
}
122+
123+
func (r *Relayer) GetTransactionStatus(ctx context.Context, transactionID commontypes.IdempotencyKey) (commontypes.TransactionStatus, error) {
124+
status, err := r.chain.TxManager().GetTransactionStatus(ctx, transactionID)
125+
if err != nil {
126+
return commontypes.Unknown, err
127+
}
128+
129+
return commontypes.TransactionStatus(status), nil
130+
}
131+
132+
func blockFromConfidence(ctx context.Context, ht heads.Tracker, confidence primitives.ConfidenceLevel) (*big.Int, error) {
133+
latest, finalized, err := ht.LatestAndFinalizedBlock(ctx)
134+
if err != nil {
135+
return nil, err
136+
}
137+
if confidence == primitives.Finalized {
138+
return big.NewInt(finalized.BlockNumber()), nil
139+
}
140+
141+
return big.NewInt(latest.BlockNumber()), nil
142+
}
143+
144+
func convertHead[H chains.Head[BLOCK_HASH], BLOCK_HASH chains.Hashable](h H) evmtypes.Head {
145+
return evmtypes.Head{
146+
Timestamp: uint64(h.GetTimestamp().Unix()),
147+
Hash: bytesToHash(h.BlockHash().Bytes()),
148+
Number: big.NewInt(h.BlockNumber()),
149+
ParentHash: bytesToHash(h.GetParentHash().Bytes()),
150+
}
151+
}
152+
153+
func convertReceipt(r *gethtypes.Receipt) *evmtypes.Receipt {
154+
return &evmtypes.Receipt{
155+
Status: r.Status,
156+
Logs: convertLogs(r.Logs),
157+
TxHash: r.TxHash,
158+
ContractAddress: r.ContractAddress,
159+
GasUsed: r.GasUsed,
160+
BlockHash: r.BlockHash,
161+
BlockNumber: r.BlockNumber,
162+
TransactionIndex: uint64(r.TransactionIndex),
163+
EffectiveGasPrice: r.EffectiveGasPrice,
164+
}
165+
}
166+
167+
func convertEthFilter(q evmtypes.FilterQuery) ethereum.FilterQuery {
168+
return ethereum.FilterQuery{
169+
FromBlock: q.FromBlock,
170+
ToBlock: q.ToBlock,
171+
Addresses: arraysToAddresses(q.Addresses),
172+
Topics: arraysToHashMatrix(q.Topics),
173+
}
174+
}
175+
176+
var errEmptyFilterName = errors.New("filter name can't be empty")
177+
178+
func convertLPFilter(q evmtypes.LPFilterQuery) (logpoller.Filter, error) {
179+
if q.Name == "" {
180+
return logpoller.Filter{}, errEmptyFilterName
181+
}
182+
return logpoller.Filter{
183+
Name: q.Name,
184+
Addresses: arraysToAddresses(q.Addresses),
185+
EventSigs: arraysToHashes(q.EventSigs),
186+
Topic2: arraysToHashes(q.Topic2),
187+
Topic3: arraysToHashes(q.Topic3),
188+
Topic4: arraysToHashes(q.Topic4),
189+
Retention: q.Retention,
190+
MaxLogsKept: q.MaxLogsKept,
191+
LogsPerBlock: q.LogsPerBlock,
192+
}, nil
193+
}
194+
195+
func convertTransaction(tx *gethtypes.Transaction) *evmtypes.Transaction {
196+
var to evm.Address
197+
if tx.To() != nil {
198+
to = *tx.To()
199+
}
200+
201+
return &evmtypes.Transaction{
202+
To: to,
203+
Data: tx.Data(),
204+
Hash: tx.Hash(),
205+
Nonce: tx.Nonce(),
206+
Gas: tx.Gas(),
207+
GasPrice: tx.GasPrice(),
208+
Value: tx.Value(),
209+
}
210+
}
211+
212+
func arraysToHashMatrix(input [][][32]byte) [][]common.Hash {
213+
result := make([][]common.Hash, 0, len(input))
214+
for _, row := range input {
215+
result = append(result, arraysToHashes(row))
216+
}
217+
return result
218+
}
219+
220+
func arraysToAddresses(input [][20]byte) []common.Address {
221+
res := make([]common.Address, 0, len(input))
222+
for _, s := range input {
223+
res = append(res, s)
224+
}
225+
226+
return res
227+
}
228+
229+
func arraysToHashes(input [][32]byte) []common.Hash {
230+
res := make([]common.Hash, 0, len(input))
231+
for _, s := range input {
232+
res = append(res, s)
233+
}
234+
235+
return res
236+
}
237+
238+
func hashesToArrays(input []common.Hash) [][32]byte {
239+
res := make([][32]byte, 0, len(input))
240+
for _, s := range input {
241+
res = append(res, s)
242+
}
243+
244+
return res
245+
}
246+
247+
var empty common.Address
248+
249+
func toEthMsg(msg *evmtypes.CallMsg) ethereum.CallMsg {
250+
var to *common.Address
251+
252+
if empty.Cmp(msg.To) != 0 {
253+
to = new(common.Address)
254+
*to = msg.To
255+
}
256+
257+
return ethereum.CallMsg{
258+
From: msg.From,
259+
To: to,
260+
Data: msg.Data,
261+
}
262+
}
263+
264+
func convertLogs(logs []*gethtypes.Log) []*evmtypes.Log {
265+
ret := make([]*evmtypes.Log, 0, len(logs))
266+
267+
for _, l := range logs {
268+
ret = append(ret, convertLog(l))
269+
}
270+
271+
return ret
272+
}
273+
274+
func convertLPLogs(logs []logpoller.Log) []*evmtypes.Log {
275+
ret := make([]*evmtypes.Log, 0, len(logs))
276+
for _, l := range logs {
277+
gl := l.ToGethLog()
278+
ret = append(ret, convertLog(&gl))
279+
}
280+
281+
return ret
282+
}
283+
284+
func convertLog(log *gethtypes.Log) *evmtypes.Log {
285+
topics := hashesToArrays(log.Topics)
286+
287+
var eventSig [32]byte
288+
if len(log.Topics) > 0 {
289+
eventSig = log.Topics[0]
290+
}
291+
292+
return &evmtypes.Log{
293+
LogIndex: uint32(log.Index),
294+
BlockHash: log.BlockHash,
295+
BlockNumber: new(big.Int).SetUint64(log.BlockNumber),
296+
Topics: topics,
297+
EventSig: eventSig,
298+
Address: log.Address,
299+
TxHash: log.TxHash,
300+
Data: log.Data,
301+
Removed: log.Removed,
302+
}
303+
}
304+
305+
func confidenceToConformations(conf primitives.ConfidenceLevel) types.Confirmations {
306+
if conf == primitives.Finalized {
307+
return types.Finalized
308+
}
309+
310+
return types.Unconfirmed
311+
}
312+
313+
func bytesToHash(b []byte) (h evm.Hash) {
314+
copy(h[:], b)
315+
return
316+
}

0 commit comments

Comments
 (0)