Skip to content

Commit

Permalink
update: register2 contract with smtReplicator, move some parameters i…
Browse files Browse the repository at this point in the history
…n config file, adjust signature to be compatible with the contract
  • Loading branch information
mhrynenko committed Dec 5, 2024
1 parent 686a805 commit 981335b
Show file tree
Hide file tree
Showing 10 changed files with 1,883 additions and 48 deletions.
6 changes: 5 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contracts:
address: null
lightweight_state:
address: null
register2:
smt_replicator:
address: "0xA25a197d26Cad659A8fFf7F268cA4F9e0283de03"
block: 4939333 # Block is optional field for contract listeners, default value is 0 if nothing set

Expand All @@ -24,11 +24,15 @@ db:
url: db_url

pinger:
blocks_distance: 10000
timeout: 5s # timeout to ping logs when 'subscribed' via http
normal_period: 10s
min_abnormal_period: 10s
max_abnormal_period: 10s

replicator:
source_smt: 0xc1534912902BBe8C54626e2D69288C76a843bc0E
root_prefix: Rarimo root

listener:
addr: :8000
Expand Down
13 changes: 13 additions & 0 deletions internal/assets/migrations/002_timestamp.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- +migrate Up

ALTER TABLE state
DROP COLUMN created_at;
ALTER TABLE state
ADD COLUMN timestamp BIGINT NOT NULL default 0;

-- +migrate Down

ALTER TABLE state
DROP COLUMN timestamp;
ALTER TABLE state
ADD COLUMN created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP;
4 changes: 2 additions & 2 deletions internal/config/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ const (
Proposer = "proposer"
VotingRegistry = "voting_registry"
LightweightState = "lightweight_state"
Register2 = "register2"
SMTReplicator = "smt_replicator"
)

var (
errMissingContract = errors.New("missing contract")
contracts = []string{Proposer, VotingRegistry, LightweightState, Register2}
contracts = []string{Proposer, VotingRegistry, LightweightState, SMTReplicator}
)

type ContractsConfiger interface {
Expand Down
5 changes: 4 additions & 1 deletion internal/config/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Config interface {
ContractsConfiger

Pinger() Pinger
Replicator() Replicator
}

type config struct {
Expand All @@ -29,7 +30,9 @@ type config struct {

NetworkConfiger
ContractsConfiger
pinger comfig.Once

pinger comfig.Once
replicator comfig.Once
}

func New(getter kv.Getter) Config {
Expand Down
2 changes: 2 additions & 0 deletions internal/config/pinger.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
)

type Pinger struct {
BlocksDistance uint64 `fig:"blocks_distance"`
Timeout time.Duration `fig:"timeout"`
NormalPeriod time.Duration `fig:"normal_period"`
MinAbnormalPeriod time.Duration `fig:"min_abnormal_period"`
Expand All @@ -23,6 +24,7 @@ type Pinger struct {
func (c *config) Pinger() Pinger {
return c.pinger.Do(func() interface{} {
var result = Pinger{
BlocksDistance: 0,
Timeout: 5 * time.Second,
NormalPeriod: 30 * time.Second,
MinAbnormalPeriod: 30 * time.Second,
Expand Down
35 changes: 35 additions & 0 deletions internal/config/replicator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package config

import (
"github.com/ethereum/go-ethereum/common"
"gitlab.com/distributed_lab/figure/v3"
"gitlab.com/distributed_lab/kit/kv"
"gitlab.com/distributed_lab/logan/v3"
"gitlab.com/distributed_lab/logan/v3/errors"
)

const (
replicatorYamlKey = "replicator"
)

type Replicator struct {
SourceSMT common.Address `fig:"source_smt,required"`
RootPrefix string `fig:"root_prefix,required"`
}

func (c *config) Replicator() Replicator {
return c.replicator.Do(func() interface{} {
var result Replicator

err := figure.
Out(&result).
With(figure.BaseHooks, figure.EthereumHooks).
From(kv.MustGetStringMap(c.getter, replicatorYamlKey)).
Please()
if err != nil {
panic(errors.Wrap(err, "failed to figure out config", logan.F{"key": replicatorYamlKey}))
}

return result
}).(Replicator)
}
1,753 changes: 1,753 additions & 0 deletions internal/contracts/RegistrationSMTReplicator.go

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions internal/data/state.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package data

import "time"

type SortOrder string

type StateQ interface {
Expand All @@ -17,11 +15,11 @@ type StateQ interface {
}

type State struct {
ID string `db:"id" structs:"-"`
Root string `db:"root" structs:"root"`
TxHash string `db:"tx_hash" structs:"tx_hash"`
Block uint64 `db:"block" structs:"block"`
CreatedAt time.Time `db:"created_at" structs:"created_at"`
ID string `db:"id" structs:"-"`
Root string `db:"root" structs:"root"`
TxHash string `db:"tx_hash" structs:"tx_hash"`
Block uint64 `db:"block" structs:"block"`
Timestamp uint64 `db:"timestamp" structs:"timestamp"`
}

const (
Expand Down
21 changes: 19 additions & 2 deletions internal/service/api/handlers/get_signed_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package handlers

import (
"encoding/hex"
"math/big"
"net/http"

"github.com/ethereum/go-ethereum/crypto"
"github.com/rarimo/proof-verification-relayer/internal/config"
"github.com/rarimo/proof-verification-relayer/internal/data"
"github.com/rarimo/proof-verification-relayer/internal/service/api/requests"
"github.com/rarimo/proof-verification-relayer/resources"
Expand Down Expand Up @@ -57,17 +59,32 @@ func GetSignedState(w http.ResponseWriter, r *http.Request) {
},
Attributes: resources.StateAttributes{
Signature: hex.EncodeToString(signature),
Timestamp: state.CreatedAt.Unix(),
Timestamp: int64(state.Timestamp),
},
})
}

func signState(state data.State, r *http.Request) ([]byte, error) {
digest, err := hex.DecodeString(state.Root)
rootBytes, err := hex.DecodeString(state.Root)
if err != nil {
return nil, errors.Wrap(err, "failed to decode signature digest", logan.F{"root": state.Root})
}

//keccak256(abi.encodePacked(
// REGISTRATION_ROOT_PREFIX,
// sourceSMT,
// address(this),
// newRoot_,
// transitionTimestamp_
//));
digest := crypto.Keccak256(
[]byte(Config(r).Replicator().RootPrefix),
Config(r).Replicator().SourceSMT.Bytes(),
Config(r).ContractsConfig()[config.SMTReplicator].Address.Bytes(),
rootBytes,
new(big.Int).SetUint64(state.Timestamp).Bytes(),
)

signature, err := crypto.Sign(digest, Config(r).NetworkConfig().PrivateKey)
if err != nil {
return nil, errors.Wrap(err, "failed to sign state")
Expand Down
80 changes: 45 additions & 35 deletions internal/service/listener/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/rarimo/proof-verification-relayer/internal/config"
"github.com/rarimo/proof-verification-relayer/internal/contracts"
"github.com/rarimo/proof-verification-relayer/internal/data"
"github.com/rarimo/proof-verification-relayer/internal/data/pg"
"gitlab.com/distributed_lab/logan/v3"
Expand All @@ -19,41 +20,46 @@ import (
)

const (
blocksDistanceDelta = 10000
serviceName = "listener"
RootUpdatedEventTopic = "0x2cbc14f49c068133583f7cb530018af451c87c1cf1327cf2a4ff4698c4730aa4"
)

var (
ErrInvalidEventDataLen = errors.New("invalid data length for event")
serviceName = "listener"
RootTransitionedEventTopic = "0x287d7075e3fdd1ee3cb7eef1d33839a4b50939e7bc33a68d8f6031eb3a1a14c6"
)

type Listener interface {
Start(ctx context.Context)
}

type listener struct {
log *logan.Entry
client *ethclient.Client
stateQ data.StateQ
contract config.ContractConfig
pinger config.Pinger
log *logan.Entry
client *ethclient.Client
stateQ data.StateQ
smtReplicator *contracts.RegistrationSMTReplicator
contractCfg config.ContractConfig
pinger config.Pinger
}

func NewListener(
cfg config.Config,
) Listener {
register2Contract := cfg.ContractsConfig()[config.Register2]
) (Listener, error) {
smtReplicatorCfg := cfg.ContractsConfig()[config.SMTReplicator]
smtReplicatorContract, err := contracts.NewRegistrationSMTReplicator(
smtReplicatorCfg.Address,
cfg.NetworkConfig().Client,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create smtReplicator contractCfg")
}

return &listener{
log: cfg.Log().WithFields(logan.F{
"service": serviceName,
"address": register2Contract.Address.String(),
"address": smtReplicatorCfg.Address.String(),
}),
client: cfg.NetworkConfig().Client,
stateQ: pg.NewStateQ(cfg.DB().Clone()),
contract: register2Contract,
pinger: cfg.Pinger(),
}
client: cfg.NetworkConfig().Client,
stateQ: pg.NewStateQ(cfg.DB().Clone()),
smtReplicator: smtReplicatorContract,
contractCfg: smtReplicatorCfg,
pinger: cfg.Pinger(),
}, nil
}

func (l *listener) Start(ctx context.Context) {
Expand Down Expand Up @@ -88,14 +94,14 @@ func (l *listener) getStartBlockNumber(ctx context.Context) (uint64, error) {

state, err := l.stateQ.SortByBlockHeight(data.DESC).Get()
if err != nil {
return 0, errors.Wrap(err, "failed to get states", logan.F{"chain_id": chainID.Uint64(), "address": l.contract.Address.String()})
return 0, errors.Wrap(err, "failed to get states", logan.F{"chain_id": chainID.Uint64(), "address": l.contractCfg.Address.String()})
}

if state == nil {
return l.contract.Block, nil
return l.contractCfg.Block, nil
}

return max(l.contract.Block, state.Block), nil
return max(l.contractCfg.Block, state.Block), nil
}

func (l *listener) readEvents(ctx context.Context, block uint64) (uint64, error) {
Expand All @@ -106,16 +112,16 @@ func (l *listener) readEvents(ctx context.Context, block uint64) (uint64, error)
return block, errors.Wrap(err, "failed to get latest block header")
}

for ; block < header.Number.Uint64(); block = min(header.Number.Uint64(), block+blocksDistanceDelta) {
toBlock := min(header.Number.Uint64(), block+blocksDistanceDelta)
for ; block < header.Number.Uint64(); block = min(header.Number.Uint64(), block+l.pinger.BlocksDistance) {
toBlock := min(header.Number.Uint64(), block+l.pinger.BlocksDistance)
logs, err := l.client.FilterLogs(ctx, ethereum.FilterQuery{
Topics: [][]common.Hash{{common.HexToHash(RootUpdatedEventTopic)}},
Addresses: []common.Address{l.contract.Address},
Topics: [][]common.Hash{{common.HexToHash(RootTransitionedEventTopic)}},
Addresses: []common.Address{l.contractCfg.Address},
FromBlock: new(big.Int).SetUint64(block),
ToBlock: new(big.Int).SetUint64(toBlock),
})
if err != nil {
return block, errors.Wrap(err, "failed to filter logs", logan.F{"address": l.contract.Address, "start_block": block})
return block, errors.Wrap(err, "failed to filter logs", logan.F{"address": l.contractCfg.Address, "start_block": block})
}

for _, event := range logs {
Expand Down Expand Up @@ -159,17 +165,16 @@ func (l *listener) listenEvents(ctx context.Context, block uint64) error {
}

func (l *listener) handleLog(event types.Log) error {
var root [32]byte
if len(event.Data) != 32 {
return ErrInvalidEventDataLen
rootTransitioned, err := l.smtReplicator.ParseRootTransitioned(event)
if err != nil {
return errors.Wrap(err, "failed to parse root transitioned event")
}
copy(root[:], event.Data[:32])

if err := l.stateQ.Upsert(data.State{
TxHash: hex.EncodeToString(event.TxHash.Bytes()),
Block: event.BlockNumber,
Root: hex.EncodeToString(root[:]),
CreatedAt: time.Now(),
Root: hex.EncodeToString(rootTransitioned.NewRoot[:]),
Timestamp: rootTransitioned.TransitionTimestamp.Uint64(),
}); err != nil {
return errors.Wrap(err, "failed to insert new root state")
}
Expand All @@ -178,5 +183,10 @@ func (l *listener) handleLog(event types.Log) error {
}

func Run(ctx context.Context, cfg config.Config) {
NewListener(cfg).Start(ctx)
pinger, err := NewListener(cfg)
if err != nil {
panic(errors.Wrap(err, "failed to create listener"))
}

pinger.Start(ctx)
}

0 comments on commit 981335b

Please sign in to comment.