Skip to content

Commit

Permalink
fix erc20_bridge config
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaiba committed Feb 20, 2025
1 parent 7a97e74 commit eb9af22
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 51 deletions.
8 changes: 1 addition & 7 deletions app/node/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,6 @@ func buildConsensusEngine(_ context.Context, d *coreDependencies, db *pg.DB,
}

func buildErc20RWignerMgr(d *coreDependencies) *signersvc.ServiceMgr {
cfg := d.cfg.Erc20Bridge

if err := cfg.Validate(); err != nil {
failBuild(err, "invalid erc20 bridge config")
}

// create shared state
stateFile := signersvc.StateFilePath(d.rootDir)

Expand All @@ -533,7 +527,7 @@ func buildErc20RWignerMgr(d *coreDependencies) *signersvc.ServiceMgr {

rpcUrl := "http://" + d.cfg.RPC.ListenAddress

mgr, err := signersvc.NewServiceMgr(rpcUrl, cfg, state, d.logger.New("EVMRW"))
mgr, err := signersvc.NewServiceMgr(rpcUrl, d.cfg.Erc20Bridge, state, d.logger.New("EVMRW"))
if err != nil {
failBuild(err, "Failed to create erc20 bridge signer service manager")
}
Expand Down
30 changes: 20 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
"strings"
"time"

"github.com/pelletier/go-toml/v2"

"github.com/kwilteam/kwil-db/core/crypto"
"github.com/kwilteam/kwil-db/core/crypto/auth"
"github.com/kwilteam/kwil-db/core/log"
"github.com/kwilteam/kwil-db/core/types"

"github.com/pelletier/go-toml/v2"
"github.com/kwilteam/kwil-db/node/exts/evm-sync/chains"
)

var (
Expand Down Expand Up @@ -450,15 +451,24 @@ type Checkpoint struct {
}

type ERC20BridgeConfig struct {
RPC map[string]string `toml:"rpc" comment:"evm RPC; format: chain_name='rpc_url'"`
BlockSyncChuckSize map[string]string `toml:"block_sync_chuck_size" comment:"block sync chunk size; format: chain_name='chunk_size'"`
Signer map[string]string `toml:"signer" comment:"signer service configuration; format: chain_name='target:file_path_to_private_key'"`
}
RPC map[string]string `toml:"rpc" comment:"evm websocket RPC; format: chain_name='rpc_url'"`
BlockSyncChuckSize map[string]string `toml:"block_sync_chuck_size" comment:"rpc option block sync chunk size; format: chain_name='chunk_size'"`
Signer map[string]string `toml:"signer" comment:"signer service configuration; format: target='chain_name:file_path_to_private_key'"`
}

// ValidateRpc validates the bridge rpc config, other validations will be performed
// when correspond components derive config from it.
// BlockSyncChuckSize config will be validated by evm-sync listener.
// Signer config will be validated by erc20 signerSvc.
func (cfg ERC20BridgeConfig) ValidateRpc() error {
for chain, rpc := range cfg.RPC {
if err := chains.Chain(chain).Valid(); err != nil {
return fmt.Errorf("erc20_bridge.rpc: %s", chain)
}

func (cfg ERC20BridgeConfig) Validate() error {
for chain := range cfg.Signer {
if _, ok := cfg.RPC[chain]; !ok {
return fmt.Errorf("signer service: chain '%s' is not in rpc", chain)
// enforce websocket
if !strings.HasPrefix(rpc, "wss://") && !strings.HasPrefix(rpc, "ws://") {
return fmt.Errorf("erc20_bridge.rpc: must start with wss:// or ws://")
}
}

Expand Down
77 changes: 50 additions & 27 deletions node/exts/erc20-bridge/signersvc/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,53 +317,76 @@ func (s *rewardSigner) sync(ctx context.Context) {
s.lastVoteBlock = finalizedEpoch.EndHeight // update after all operations succeed
}

// ServiceMgr manages multiple rewardSigner instances running in parallel.
type ServiceMgr struct {
syncInterval time.Duration
signers []*rewardSigner
logger log.Logger
type signerConfig struct {
target string // erc20 bridge target name
chainRPC string
privateKeyPath string // file path to private key
}

func NewServiceMgr(
kwilRpc string,
cfg config.ERC20BridgeConfig,
state *State,
logger log.Logger) (*ServiceMgr, error) {
// GetSignerCfgs verifies config and returns a list of config for erc20 signerSvc.
func getSignerCfgs(cfg config.ERC20BridgeConfig) ([]signerConfig, error) {
if err := cfg.ValidateRpc(); err != nil {
return nil, err
}

signerCfgDelimiter := ":"

var signers []*rewardSigner
for chain, value := range cfg.Signer {
chainRpc, ok := cfg.RPC[chain]
if !ok {
return nil, fmt.Errorf("chain %s not found in rpc config", chain)
}

// we need websocket endpoint
if !strings.HasPrefix(chainRpc, "wss://") && !strings.HasPrefix(chainRpc, "ws://") {
return nil, fmt.Errorf("chain %s rpc must start with wss:// or ws://", chain)
}
var signerCfg []signerConfig

for target, value := range cfg.Signer {
if !strings.Contains(value, signerCfgDelimiter) {
return nil, fmt.Errorf("invalid signer config: %s", value)
}

segs := strings.SplitN(value, signerCfgDelimiter, 2)

target := segs[0]
chain := segs[0]
pkPath := segs[1]

chainRpc, ok := cfg.RPC[chain]
if !ok {
return nil, fmt.Errorf("chain '%s' not found in erc20_bridge.rpc config", chain)
}

if !ethCommon.FileExist(pkPath) {
return nil, fmt.Errorf("private key file %s not found", pkPath)
}

pkBytes, err := os.ReadFile(pkPath)
signerCfg = append(signerCfg, signerConfig{
target: target,
chainRPC: chainRpc,
privateKeyPath: pkPath,
})
}

return signerCfg, nil
}

// ServiceMgr manages multiple rewardSigner instances running in parallel.
type ServiceMgr struct {
syncInterval time.Duration
signers []*rewardSigner
logger log.Logger
}

func NewServiceMgr(
kwilRpc string,
cfg config.ERC20BridgeConfig,
state *State,
logger log.Logger) (*ServiceMgr, error) {
signerCfgs, err := getSignerCfgs(cfg)
if err != nil {
return nil, fmt.Errorf("get erc20 bridge signer config failed: %w", err)
}

var signers []*rewardSigner
for _, cfg := range signerCfgs {
pkBytes, err := os.ReadFile(cfg.privateKeyPath)
if err != nil {
return nil, fmt.Errorf("read private key file %s failed: %w", pkPath, err)
return nil, fmt.Errorf("read private key file %s failed: %w", cfg.privateKeyPath, err)
}

svc, err := newRewardSigner(kwilRpc, target, chainRpc, strings.TrimSpace(string(pkBytes)),
state, logger.New("EVMRW."+target))
svc, err := newRewardSigner(kwilRpc, cfg.target, cfg.chainRPC, strings.TrimSpace(string(pkBytes)),
state, logger.New("EVMRW."+cfg.target))
if err != nil {
return nil, fmt.Errorf("create erc20 bridge signer service failed: %w", err)
}
Expand Down
13 changes: 6 additions & 7 deletions node/exts/evm-sync/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"io"
"sort"
"strconv"
"strings"
"time"

ethcommon "github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -107,19 +106,19 @@ func (c *syncConfig) load(m map[string]string) error {

// getChainConf gets the chain config from the node's local configuration.
func getChainConf(cfg config.ERC20BridgeConfig, chain chains.Chain) (*chainConfig, error) {
err := cfg.ValidateRpc()
if err != nil {
return nil, err
}

var ok bool
var provider string
var syncChunk string
switch chain {
case chains.Ethereum, chains.Sepolia:
provider, ok = cfg.RPC[chain.String()]
if !ok {
return nil, errors.New("local configuration does not have an ethereum_sync config")
}

// we need websocket endpoint
if !strings.HasPrefix(provider, "wss://") && !strings.HasPrefix(provider, "ws://") {
return nil, fmt.Errorf("chain %s rpc must start with wss:// or ws://", chain)
return nil, fmt.Errorf("local configuration does not have an '%s' config", chain.String())
}

syncChunk, ok = cfg.BlockSyncChuckSize[chains.Ethereum.String()]
Expand Down

0 comments on commit eb9af22

Please sign in to comment.