Skip to content

Commit

Permalink
Simplify chain reader's bindings.
Browse files Browse the repository at this point in the history
  • Loading branch information
nolag committed Dec 20, 2023
1 parent c287971 commit 5be5410
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 170 deletions.
135 changes: 135 additions & 0 deletions core/services/relay/evm/binding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package evm

import (
"context"
"fmt"
"strings"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"

evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)

type binding interface {
GetLatestValue(ctx context.Context, params any) ([]byte, error)
Rebind(binding commontypes.BoundContract) error
SetCodec(codec commontypes.Codec)
Register() error
Unregister() error
}

type methodBinding struct {
address common.Address
contractName string
method string
client evmclient.Client
codec commontypes.Codec
}

var _ binding = &methodBinding{}

func (m *methodBinding) SetCodec(codec commontypes.Codec) {
m.codec = codec
}

func (m *methodBinding) Register() error {
return nil
}

func (m *methodBinding) Unregister() error {
return nil
}

func (m *methodBinding) GetLatestValue(ctx context.Context, params any) ([]byte, error) {
data, err := m.codec.Encode(ctx, params, wrapItemType(m.contractName, m.method, true))
if err != nil {
return nil, err
}

callMsg := ethereum.CallMsg{
To: &m.address,
From: m.address,
Data: data,
}

return m.client.CallContract(ctx, callMsg, nil)
}

func (m *methodBinding) Rebind(binding commontypes.BoundContract) error {
m.address = common.HexToAddress(binding.Address)
return nil
}

type eventBinding struct {
address common.Address
contractName string
eventName string
lp logpoller.LogPoller
hash common.Hash
codec commontypes.Codec
pending bool
subscribed bool
}

func (e *eventBinding) SetCodec(codec commontypes.Codec) {
e.codec = codec
}

func (e *eventBinding) Register() error {
if err := e.lp.RegisterFilter(logpoller.Filter{
Name: wrapItemType(e.contractName, e.eventName, false),
EventSigs: evmtypes.HashArray{e.hash},
Addresses: evmtypes.AddressArray{e.address},
}); err != nil {
return fmt.Errorf("%w: %w", commontypes.ErrInternal, err)
}
e.subscribed = true
return nil
}

func (e *eventBinding) Unregister() error {
if err := e.lp.UnregisterFilter(wrapItemType(e.contractName, e.eventName, false)); err != nil {
return fmt.Errorf("%w: %w", commontypes.ErrInternal, err)
}
e.subscribed = false
return nil
}

var _ binding = &eventBinding{}

func (e *eventBinding) GetLatestValue(_ context.Context, _ any) ([]byte, error) {
confs := logpoller.Finalized
if e.pending {
confs = logpoller.Unconfirmed
}
log, err := e.lp.LatestLogByEventSigWithConfs(e.hash, e.address, confs)
if err != nil {
errStr := err.Error()
if strings.Contains(errStr, "not found") || strings.Contains(errStr, "no rows") {
return nil, nil
}
return nil, err
}

return log.Data, nil
}

func (e *eventBinding) Rebind(binding commontypes.BoundContract) error {
wasSubscribed := e.subscribed
if wasSubscribed {
if err := e.Unregister(); err != nil {
return err
}
}
e.address = common.HexToAddress(binding.Address)
e.pending = binding.Pending

if wasSubscribed {
return e.Register()
}
return nil
}
55 changes: 23 additions & 32 deletions core/services/relay/evm/bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,39 @@ package evm
import (
"fmt"

"github.com/ethereum/go-ethereum/common"

"github.com/smartcontractkit/chainlink-common/pkg/types"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
)

type Bindings map[string]methodBindings

func (b Bindings) addEvent(contractName, typeName string, evt common.Hash) error {
ae, err := b.getBinding(contractName, typeName, true)
if err != nil {
return err
}
type bindings map[string]map[string]binding

ae.evt = &evt
return nil
}

func (b Bindings) getBinding(contractName, methodName string, isConfig bool) (*addrEvtBinding, error) {
errType := types.ErrInvalidType
if isConfig {
errType = types.ErrInvalidConfig
}
methodNames, ok := b[contractName]
func (b bindings) GetBinding(contractName, readName string) (binding, error) {
methodReaders, ok := b[contractName]
if !ok {
return nil, fmt.Errorf("%w: contract %s not found", errType, contractName)
return nil, fmt.Errorf("%w: no contract named %s", commontypes.ErrInvalidType, contractName)
}

ae, ok := methodNames[methodName]
reader, ok := methodReaders[readName]
if !ok {
return nil, fmt.Errorf("%w: method %s not found in contract %s", errType, methodName, contractName)
return nil, fmt.Errorf("%w: no readName named %s in contract%s", commontypes.ErrInvalidType, readName, contractName)
}

return ae, nil
return reader, nil
}

type methodBindings map[string]*addrEvtBinding

func NewAddrEvtFromAddress(address common.Address) *addrEvtBinding {
return &addrEvtBinding{addr: address}
func (b bindings) AddBinding(contractName, readName string, reader binding) {
mb, ok := b[contractName]
if !ok {
b[contractName] = map[string]binding{}
}
mb[readName] = reader
}

type addrEvtBinding struct {
addr common.Address
evt *common.Hash
func (b bindings) ForEach(fn func(binding) error) error {
for _, readers := range b {
for _, reader := range readers {
if err := fn(reader); err != nil {
return err
}
}
}
return nil
}
Loading

0 comments on commit 5be5410

Please sign in to comment.