From 802ce8eb42224a7c4ba37d2be4f29fce70695371 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Tue, 27 Jun 2023 15:48:19 +0900 Subject: [PATCH 01/22] Refactor relay --- chain/config.go | 11 +- chain/ethbr/factory.go | 54 ++++++++ chain/ethbr/receiver.go | 44 +++++-- chain/ethbr/sender.go | 2 +- chain/icon/bridge/bridge.go | 20 +-- chain/icon/btp2/btp2.go | 36 ++++-- chain/icon/client/type.go | 19 ++- chain/icon/factory.go | 65 ++++++++++ chain/icon/sender.go | 2 +- cmd/relay/linkfactory.go | 146 --------------------- cmd/relay/main.go | 173 ++----------------------- common/link/config.go | 26 ++++ common/link/link.go | 37 ++---- common/link/linkfactory.go | 246 ++++++++++++++++++++++++++++++++++++ common/link/type.go | 6 +- 15 files changed, 497 insertions(+), 390 deletions(-) create mode 100644 chain/ethbr/factory.go create mode 100644 chain/icon/factory.go delete mode 100644 cmd/relay/linkfactory.go create mode 100644 common/link/config.go create mode 100644 common/link/linkfactory.go diff --git a/chain/config.go b/chain/config.go index 8db1c21..a10c751 100644 --- a/chain/config.go +++ b/chain/config.go @@ -19,7 +19,6 @@ package chain import ( "encoding/json" - "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/types" ) @@ -29,16 +28,8 @@ type BaseConfig struct { KeyStoreData json.RawMessage `json:"key_store"` KeyStorePass string `json:"key_password,omitempty"` KeySecret string `json:"key_secret,omitempty"` - BridgeMode bool `json:"bridge_mode"` + RelayMode string `json:"relay_mode"` //trustless, bridge LatestResult bool `json:"latest_result"` FilledBlockUpdate bool `json:"filled_block_update"` Options map[string]interface{} `json:"options,omitempty"` } - -type Config struct { - config.FileConfig `json:",squash"` //instead of `mapstructure:",squash"` - Src BaseConfig `json:"src"` - Dst BaseConfig `json:"dst"` - Direction string `json:"direction"` - Offset int64 `json:"offset"` -} diff --git a/chain/ethbr/factory.go b/chain/ethbr/factory.go new file mode 100644 index 0000000..2a975af --- /dev/null +++ b/chain/ethbr/factory.go @@ -0,0 +1,54 @@ +package ethbr + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" + "github.com/icon-project/btp2/common/wallet" +) + +const ( + BRIDGE = "bridge" + TRUSTLESS = "trustless" +) + +func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { + receiver := newEthBridge(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l, srcCfg.Options) + return receiver +} + +func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (types.Sender, error) { + //TODO refactoring + w, err := Wallet(cfg.KeyStorePass, cfg.KeySecret, cfg.KeyStoreData) + if err != nil { + return nil, err + } + + return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil +} + +func Wallet(passwd, secret string, keyStore json.RawMessage) (wallet.Wallet, error) { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) +} + +func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { + if keySecret != "" { + return os.ReadFile(keySecret) + } else { + if keyStorePass != "" { + return []byte(keyStorePass), nil + } else { + //TODO + return nil, fmt.Errorf("") + } + } +} diff --git a/chain/ethbr/receiver.go b/chain/ethbr/receiver.go index 5bdad86..9fb1a57 100644 --- a/chain/ethbr/receiver.go +++ b/chain/ethbr/receiver.go @@ -3,6 +3,7 @@ package ethbr import ( "bytes" "encoding/base64" + "encoding/json" "fmt" "io" "math/big" @@ -60,28 +61,40 @@ type ethbr struct { dst btpTypes.BtpAddress c *client.Client nid int64 - rsc chan link.ReceiveStatus + rsc chan interface{} rss []*receiveStatus seq int64 startHeight int64 + opt struct { + StartHeight int64 + } } -func NewEthBridge(src, dst btpTypes.BtpAddress, endpoint string, l log.Logger) *ethbr { +func newEthBridge(src, dst btpTypes.BtpAddress, endpoint string, l log.Logger, opt map[string]interface{}) *ethbr { c := ðbr{ src: src, dst: dst, l: l, - rsc: make(chan link.ReceiveStatus), + rsc: make(chan interface{}), rss: make([]*receiveStatus, 0), } c.c = client.NewClient(endpoint, l) + b, err := json.Marshal(opt) + if err != nil { + l.Panicf("fail to marshal opt:%#v err:%+v", opt, err) + } + + if err = json.Unmarshal(b, &c.opt); err != nil { + l.Panicf("fail to unmarshal opt:%#v err:%+v", opt, err) + } return c } -func (e *ethbr) Start(bs *btpTypes.BMCLinkStatus) (<-chan link.ReceiveStatus, error) { +func (e *ethbr) Start(bls *btpTypes.BMCLinkStatus) (<-chan interface{}, error) { go func() { - err := e.Monitoring(bs) - e.l.Panicf("Unknown monitoring error occurred (err : %v)", err) + err := e.Monitoring(bls) + e.l.Debugf("Unknown monitoring error occurred (err : %v)", err) + e.rsc <- err }() return e.rsc, nil @@ -215,23 +228,30 @@ func (e *ethbr) clearReceiveStatus(bls *btpTypes.BMCLinkStatus) { } } -func (e *ethbr) Monitoring(bs *btpTypes.BMCLinkStatus) error { - //var err error +func (e *ethbr) Monitoring(bls *btpTypes.BMCLinkStatus) error { + var height int64 fq := ðereum.FilterQuery{ Addresses: []common.Address{common.HexToAddress(e.src.ContractAddress())}, Topics: [][]common.Hash{ {crypto.Keccak256Hash([]byte(EventSignature))}, }, } + + if e.opt.StartHeight > bls.Verifier.Height { + height = e.opt.StartHeight + } else { + height = bls.Verifier.Height + } + e.l.Debugf("ReceiveLoop height:%d seq:%d filterQuery[Address:%s,Topic:%s]", - bs.Verifier.Height, bs.RxSeq, fq.Addresses[0].String(), fq.Topics[0][0].Hex()) + height, bls.RxSeq, fq.Addresses[0].String(), fq.Topics[0][0].Hex()) br := &client.BlockRequest{ - Height: big.NewInt(bs.Verifier.Height), + Height: big.NewInt(height), FilterQuery: fq, } - if bs.RxSeq != 0 { - e.seq = bs.RxSeq + if bls.RxSeq != 0 { + e.seq = bls.RxSeq } return e.c.MonitorBlock(br, diff --git a/chain/ethbr/sender.go b/chain/ethbr/sender.go index 48ef29d..badca64 100644 --- a/chain/ethbr/sender.go +++ b/chain/ethbr/sender.go @@ -103,7 +103,7 @@ type sender struct { queue *Queue } -func NewSender(src, dst btpTypes.BtpAddress, w client.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) btpTypes.Sender { +func newSender(src, dst btpTypes.BtpAddress, w client.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) btpTypes.Sender { s := &sender{ src: src, dst: dst, diff --git a/chain/icon/bridge/bridge.go b/chain/icon/bridge/bridge.go index 1d3c6e9..79357fd 100644 --- a/chain/icon/bridge/bridge.go +++ b/chain/icon/bridge/bridge.go @@ -40,7 +40,7 @@ type bridge struct { dst types.BtpAddress c *client.Client nid int64 - rsc chan link.ReceiveStatus + rsc chan interface{} rss []*receiveStatus rs *receiveStatus startHeight int64 @@ -78,7 +78,7 @@ func NewBridge(src, dst types.BtpAddress, endpoint string, l log.Logger) *bridge src: src, dst: dst, l: l, - rsc: make(chan link.ReceiveStatus), + rsc: make(chan interface{}), rss: make([]*receiveStatus, 0), rs: &receiveStatus{}, } @@ -98,7 +98,7 @@ func (b *bridge) getNetworkId() error { return nil } -func (b *bridge) Start(bs *types.BMCLinkStatus) (<-chan link.ReceiveStatus, error) { +func (b *bridge) Start(bls *types.BMCLinkStatus) (<-chan interface{}, error) { if err := b.getNetworkId(); err != nil { return nil, err } @@ -108,7 +108,9 @@ func (b *bridge) Start(bs *types.BMCLinkStatus) (<-chan link.ReceiveStatus, erro } go func() { - b.Monitoring(bs) //TODO error handling + err := b.Monitoring(bls) + b.l.Debugf("Unknown monitoring error occurred (err : %v)", err) + b.rsc <- err }() return b.rsc, nil @@ -208,13 +210,13 @@ func (b *bridge) getBtpMessage(height int64) ([]string, error) { return mgs, nil } -func (b *bridge) Monitoring(bs *types.BMCLinkStatus) error { - if bs.Verifier.Height < 1 { +func (b *bridge) Monitoring(bls *types.BMCLinkStatus) error { + if bls.Verifier.Height < 1 { return fmt.Errorf("cannot catchup from zero height") } req := &client.BTPRequest{ - Height: client.NewHexInt(bs.Verifier.Height), + Height: client.NewHexInt(bls.Verifier.Height), NetworkID: client.NewHexInt(b.nid), ProofFlag: client.NewHexInt(0), } @@ -231,10 +233,10 @@ func (b *bridge) Monitoring(bs *types.BMCLinkStatus) error { } onConn := func(conn *websocket.Conn) { b.l.Debugf("ReceiveLoop monitorBTP2Block height:%d seq:%d networkId:%d connected %s", - bs.Verifier.Height, bs.TxSeq, b.nid, conn.LocalAddr().String()) + bls.Verifier.Height, bls.TxSeq, b.nid, conn.LocalAddr().String()) } - err := b.monitorBTP2Block(req, bs, onConn, onErr) + err := b.monitorBTP2Block(req, bls, onConn, onErr) if err != nil { return err } diff --git a/chain/icon/btp2/btp2.go b/chain/icon/btp2/btp2.go index 9f4e718..f739c77 100644 --- a/chain/icon/btp2/btp2.go +++ b/chain/icon/btp2/btp2.go @@ -3,6 +3,7 @@ package btp2 import ( "encoding/base64" "fmt" + "time" "github.com/gorilla/websocket" @@ -10,12 +11,17 @@ import ( "github.com/icon-project/btp2/common/codec" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/intconv" + "github.com/icon-project/btp2/common/jsonrpc" "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/mbt" "github.com/icon-project/btp2/common/types" ) +const ( + DefaultGetBtpMessageInterval = time.Second +) + type receiveStatus struct { height int64 seq int64 @@ -43,7 +49,7 @@ type btp2 struct { dst types.BtpAddress c *client.Client nid int64 - rsc chan link.ReceiveStatus + rsc chan interface{} rss []*receiveStatus rs *receiveStatus seq int64 @@ -55,7 +61,7 @@ func NewBTP2(src, dst types.BtpAddress, endpoint string, l log.Logger) *btp2 { src: src, dst: dst, l: l, - rsc: make(chan link.ReceiveStatus), + rsc: make(chan interface{}), rss: make([]*receiveStatus, 0), rs: &receiveStatus{}, } @@ -75,13 +81,22 @@ func (b *btp2) getNetworkId() error { return nil } func (b *btp2) getBtpMessage(height int64) ([]string, error) { - pr := &client.BTPBlockParam{Height: client.HexInt(intconv.FormatInt(height)), NetworkId: client.HexInt(intconv.FormatInt(b.nid))} - mgs, err := b.c.GetBTPMessage(pr) - if err != nil { - return nil, err + for { + pr := &client.BTPBlockParam{Height: client.HexInt(intconv.FormatInt(height)), NetworkId: client.HexInt(intconv.FormatInt(b.nid))} + mgs, err := b.c.GetBTPMessage(pr) + if err != nil { + if je, ok := err.(*jsonrpc.Error); ok { + switch je.Code { + case client.JsonrpcErrorCodeNotFound: + <-time.After(DefaultGetBtpMessageInterval) + continue + default: + return nil, err + } + } + } + return mgs, nil } - - return mgs, nil } func (b *btp2) getBtpHeader(height int64) ([]byte, []byte, error) { @@ -108,7 +123,7 @@ func (b *btp2) getBtpHeader(height int64) ([]byte, []byte, error) { return h, p, nil } -func (b *btp2) Start(bls *types.BMCLinkStatus) (<-chan link.ReceiveStatus, error) { +func (b *btp2) Start(bls *types.BMCLinkStatus) (<-chan interface{}, error) { if err := b.getNetworkId(); err != nil { return nil, err } @@ -119,7 +134,8 @@ func (b *btp2) Start(bls *types.BMCLinkStatus) (<-chan link.ReceiveStatus, error go func() { err := b.Monitoring(bls) - b.l.Panicf("Unknown monitoring error occurred (err : %v)", err) + b.l.Debugf("Unknown monitoring error occurred (err : %v)", err) + b.rsc <- err }() return b.rsc, nil diff --git a/chain/icon/client/type.go b/chain/icon/client/type.go index 062c793..7ac8243 100644 --- a/chain/icon/client/type.go +++ b/chain/icon/client/type.go @@ -287,7 +287,7 @@ type WSResponse struct { Message string `json:"message,omitempty"` } -//T_BIN_DATA, T_HASH +// T_BIN_DATA, T_HASH type HexBytes string func (hs HexBytes) Value() ([]byte, error) { @@ -300,7 +300,7 @@ func NewHexBytes(b []byte) HexBytes { return HexBytes("0x" + hex.EncodeToString(b)) } -//T_INT +// T_INT type HexInt string func (i HexInt) Value() (int64, error) { @@ -322,7 +322,7 @@ func NewHexInt(v int64) HexInt { return HexInt(intconv.FormatInt(v)) } -//T_ADDR_EOA, T_ADDR_SCORE +// T_ADDR_EOA, T_ADDR_SCORE type Address string func (a Address) Value() ([]byte, error) { @@ -396,7 +396,7 @@ type Event struct { Message []byte } -//T_SIG +// T_SIG type Signature string type Block struct { @@ -466,3 +466,14 @@ type BTPBlockHeader struct { MessagesRoot []byte NextProofContext []byte } +type Dir int + +const ( + DirLeft = Dir(iota) + DirRight +) + +type MerkleNode struct { + Dir Dir + Value []byte +} diff --git a/chain/icon/factory.go b/chain/icon/factory.go new file mode 100644 index 0000000..a47383a --- /dev/null +++ b/chain/icon/factory.go @@ -0,0 +1,65 @@ +package icon + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/chain/icon/bridge" + "github.com/icon-project/btp2/chain/icon/btp2" + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" + "github.com/icon-project/btp2/common/wallet" +) + +const ( + BRIDGE = "bridge" + TRUSTLESS = "trustless" +) + +func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { + var receiver link.Receiver + + switch srcCfg.RelayMode { + case BRIDGE: + receiver = bridge.NewBridge(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) + case TRUSTLESS: + receiver = btp2.NewBTP2(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) + default: + l.Panicf("Not supported for relay mod:%s", srcCfg.RelayMode) + } + return receiver +} + +func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (types.Sender, error) { + //TODO refactoring + w, err := Wallet(cfg.KeyStorePass, cfg.KeySecret, cfg.KeyStoreData) + if err != nil { + return nil, err + } + + return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil +} + +func Wallet(passwd, secret string, keyStore json.RawMessage) (wallet.Wallet, error) { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) +} + +func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { + if keySecret != "" { + return os.ReadFile(keySecret) + } else { + if keyStorePass != "" { + return []byte(keyStorePass), nil + } else { + //TODO + return nil, fmt.Errorf("") + } + } +} diff --git a/chain/icon/sender.go b/chain/icon/sender.go index f1bd763..3e01003 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -102,7 +102,7 @@ type sender struct { queue *Queue } -func NewSender(src, dst types.BtpAddress, w client.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) types.Sender { +func newSender(src, dst types.BtpAddress, w client.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) types.Sender { s := &sender{ src: src, dst: dst, diff --git a/cmd/relay/linkfactory.go b/cmd/relay/linkfactory.go deleted file mode 100644 index def67b7..0000000 --- a/cmd/relay/linkfactory.go +++ /dev/null @@ -1,146 +0,0 @@ -package main - -import ( - "fmt" - "path" - - "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/chain/ethbr" - "github.com/icon-project/btp2/chain/icon" - "github.com/icon-project/btp2/chain/icon/bridge" - "github.com/icon-project/btp2/chain/icon/btp2" - "github.com/icon-project/btp2/common/link" - "github.com/icon-project/btp2/common/log" - "github.com/icon-project/btp2/common/types" - "github.com/icon-project/btp2/common/wallet" -) - -func NewLink(cfg *Config, srcWallet wallet.Wallet, dstWallet wallet.Wallet, modLevels map[string]string) error { - var err error - linkErrCh := make(chan error) - - switch cfg.Direction { - case FrontDirection: - srcLog := setLogger(cfg, srcWallet, modLevels) - srcLog.Debugln(cfg.FilePath, cfg.BaseDir) - if cfg.BaseDir == "" { - cfg.BaseDir = path.Join(".", ".relay", cfg.Src.Address.NetworkAddress()) - } - if _, err = newLink(cfg.Src.Address.BlockChain(), cfg.Config, srcLog, dstWallet, linkErrCh); err != nil { - return err - } - - case ReverseDirection: - dstCfg := chain.Config{ - Src: cfg.Dst, - Dst: cfg.Src, - } - - dstLog := setLogger(cfg, dstWallet, modLevels) - dstLog.Debugln(cfg.FilePath, cfg.BaseDir) - if cfg.BaseDir == "" { - cfg.BaseDir = path.Join(".", ".relay", cfg.Dst.Address.NetworkAddress()) - } - if _, err = newLink(cfg.Dst.Address.BlockChain(), dstCfg, dstLog, srcWallet, linkErrCh); err != nil { - return err - } - case BothDirection: - srcLog := setLogger(cfg, srcWallet, modLevels) - srcLog.Debugln(cfg.FilePath, cfg.BaseDir) - if cfg.BaseDir == "" { - cfg.BaseDir = path.Join(".", ".relay", cfg.Src.Address.NetworkAddress()) - } - if _, err = newLink(cfg.Src.Address.BlockChain(), cfg.Config, srcLog, dstWallet, linkErrCh); err != nil { - return err - } - - dstCfg := chain.Config{ - Src: cfg.Dst, - Dst: cfg.Src, - } - - dstLog := setLogger(cfg, dstWallet, modLevels) - dstLog.Debugln(cfg.FilePath, cfg.BaseDir) - if cfg.BaseDir == "" { - cfg.BaseDir = path.Join(".", ".relay", cfg.Dst.Address.NetworkAddress()) - } - if _, err = newLink(dstCfg.Src.Address.BlockChain(), dstCfg, dstLog, srcWallet, linkErrCh); err != nil { - return err - } - default: - return fmt.Errorf("Not supported direction:%s", cfg.Direction) - } - - for { - select { - case err := <-linkErrCh: - if err != nil { - return err - } - } - } - return nil -} - -func newLink(s string, cfg chain.Config, l log.Logger, w wallet.Wallet, linkErrCh chan error) (types.Link, error) { - var lk types.Link - r := newReceiver(s, cfg, l) - lk = link.NewLink(&cfg, r, l) - - go func() { - err := lk.Start(newSender(cfg.Dst.Address.BlockChain(), cfg.Src, cfg.Dst, w, l)) - select { - case linkErrCh <- err: - default: - } - }() - - return lk, nil -} - -func newReceiver(s string, cfg chain.Config, l log.Logger) link.Receiver { - var receiver link.Receiver - - switch s { - case ICON: - if cfg.Src.BridgeMode { - receiver = bridge.NewBridge(cfg.Src.Address, cfg.Dst.Address, cfg.Src.Endpoint, l) - } else { - receiver = btp2.NewBTP2(cfg.Src.Address, cfg.Dst.Address, cfg.Src.Endpoint, l) - } - case ETH: - fallthrough - case ETH2: - fallthrough - case BSC: - fallthrough - case HARDHAT: - receiver = ethbr.NewEthBridge(cfg.Src.Address, cfg.Dst.Address, cfg.Src.Endpoint, l) - default: - l.Fatalf("Not supported for chain:%s", s) - return nil - } - return receiver -} - -func newSender(s string, srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, w wallet.Wallet, l log.Logger) types.Sender { - var sender types.Sender - - switch s { - case ICON: - sender = icon.NewSender(srcCfg.Address, dstCfg.Address, w, dstCfg.Endpoint, srcCfg.Options, l) - case ETH: - fallthrough - case ETH2: - fallthrough - case BSC: - fallthrough - case HARDHAT: - sender = ethbr.NewSender(srcCfg.Address, dstCfg.Address, w, dstCfg.Endpoint, nil, l) - default: - l.Fatalf("Not supported for chain:%s", s) - return nil - } - - return sender -} diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 8ce95b4..77bb121 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -17,23 +17,16 @@ package main import ( - "encoding/json" "fmt" - "io/ioutil" - stdlog "log" "os" "path/filepath" "strings" "github.com/spf13/cobra" - "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/common/cli" - "github.com/icon-project/btp2/common/crypto" - "github.com/icon-project/btp2/common/errors" + "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" - "github.com/icon-project/btp2/common/wallet" ) var ( @@ -41,81 +34,6 @@ var ( build = "unknown" ) -const ( - DefaultKeyStorePass = "relay" - BothDirection = "both" - FrontDirection = "front" - ReverseDirection = "reverse" - ICON = "icon" - ETH = "eth" - ETH2 = "eth2" - BSC = "bsc" - HARDHAT = "hardhat" -) - -type Config struct { - chain.Config `json:",squash"` //instead of `mapstructure:",squash"` - LogLevel string `json:"log_level"` - ConsoleLevel string `json:"console_level"` - LogForwarder *log.ForwarderConfig `json:"log_forwarder,omitempty"` - LogWriter *log.WriterConfig `json:"log_writer,omitempty"` -} - -func (c *Config) Wallet(passwd, secret string, keyStore json.RawMessage) (wallet.Wallet, error) { - pw, err := c.resolvePassword(secret, passwd) - if err != nil { - return nil, err - } - return wallet.DecryptKeyStore(keyStore, pw) -} - -func (c *Config) resolvePassword(keySecret, keyStorePass string) ([]byte, error) { - if keySecret != "" { - return ioutil.ReadFile(keySecret) - } else { - if keyStorePass == "" { - return []byte(DefaultKeyStorePass), nil - } else { - return []byte(keyStorePass), nil - } - } -} - -func (c *Config) EnsureWallet() error { - srcPw, err := c.resolvePassword(c.Src.KeySecret, c.Src.KeyStorePass) - dstPw, err := c.resolvePassword(c.Dst.KeySecret, c.Dst.KeyStorePass) - if err != nil { - return err - } - if len(c.Src.KeyStoreData) < 1 { - src_prikey, _ := crypto.GenerateKeyPair() - if ks, err := wallet.EncryptKeyAsKeyStore(src_prikey, srcPw); err != nil { - return err - } else { - c.Src.KeyStoreData = ks - } - } else { - if _, err := wallet.DecryptKeyStore(c.Src.KeyStoreData, srcPw); err != nil { - return errors.Errorf("fail to decrypt KeyStore err=%+v", err) - } - } - - if len(c.Dst.KeyStoreData) < 1 { - dst_prikey, _ := crypto.GenerateKeyPair() - if ks, err := wallet.EncryptKeyAsKeyStore(dst_prikey, dstPw); err != nil { - return err - } else { - c.Dst.KeyStoreData = ks - } - } else { - if _, err := wallet.DecryptKeyStore(c.Dst.KeyStoreData, dstPw); err != nil { - return errors.Errorf("fail to decrypt KeyStore err=%+v", err) - } - } - - return nil -} - var logoLines = []string{ " _____ _ ", " | __ \\ | | ", @@ -129,7 +47,7 @@ var logoLines = []string{ func main() { rootCmd, rootVc := cli.NewCommand(nil, nil, "relay", "BTP Relay CLI") - cfg := &Config{} + cfg := &link.Config{} rootCmd.Long = "Command Line Interface of Relay for Blockchain Transmission Protocol" cli.SetEnvKeyReplacer(rootVc, strings.NewReplacer(".", "_")) //rootVc.Debug() @@ -223,15 +141,6 @@ func main() { Use: "save [file]", Short: "Save configuration", Args: cli.ArgsWithDefaultErrorFunc(cobra.ExactArgs(1)), - PreRunE: func(cmd *cobra.Command, args []string) error { - if err := cfg.EnsureWallet(); err != nil { - return fmt.Errorf("fail to ensure src wallet err:%+v", err) - } else { - cfg.Src.KeyStorePass = "" - cfg.Dst.KeyStorePass = "" - } - return nil - }, RunE: func(cmd *cobra.Command, args []string) error { saveFilePath := args[0] cfg.FilePath, _ = filepath.Abs(saveFilePath) @@ -275,31 +184,19 @@ func main() { log.Printf("Version : %s", version) log.Printf("Build : %s", build) - var ( - err error - srcWallet wallet.Wallet - dstWallet wallet.Wallet - ) - if srcWallet, err = cfg.Wallet(cfg.Src.KeyStorePass, cfg.Src.KeySecret, cfg.Src.KeyStoreData); err != nil { - return err - } - - if dstWallet, err = cfg.Wallet(cfg.Dst.KeyStorePass, cfg.Dst.KeySecret, cfg.Dst.KeyStoreData); err != nil { - return err - } + modLevels, _ := cmd.Flags().GetStringToString("mod_level") - var srcKsData wallet.KeyStoreData - var dstKsData wallet.KeyStoreData - if err := json.Unmarshal(cfg.Src.KeyStoreData, &srcKsData); err != nil { + ls, err := link.NewLinkFactory(cfg, modLevels) + if err != nil { return err } - if err := json.Unmarshal(cfg.Dst.KeyStoreData, &dstKsData); err != nil { + s, err := link.NewSender(cfg.Src, cfg.Dst, ls[0].GetLogger()) + if err != nil { return err } - modLevels, _ := cmd.Flags().GetStringToString("mod_level") - return NewLink(cfg, srcWallet, dstWallet, modLevels) + return ls[0].Start(s) }, } rootCmd.AddCommand(startCmd) @@ -320,57 +217,3 @@ func main() { os.Exit(1) } } - -func setLogger(cfg *Config, w wallet.Wallet, modLevels map[string]string) log.Logger { - l := log.WithFields(log.Fields{log.FieldKeyWallet: w.Address()[2:]}) - log.SetGlobalLogger(l) - stdlog.SetOutput(l.WriterLevel(log.WarnLevel)) - if cfg.LogWriter != nil { - if cfg.LogWriter.Filename == "" { - log.Debugln("LogWriterConfig filename is empty string, will be ignore") - } else { - var lwCfg log.WriterConfig - lwCfg = *cfg.LogWriter - lwCfg.Filename = cfg.ResolveAbsolute(lwCfg.Filename) - w, err := log.NewWriter(&lwCfg) - if err != nil { - log.Panicf("Fail to make writer err=%+v", err) - } - err = l.SetFileWriter(w) - if err != nil { - log.Panicf("Fail to set file l err=%+v", err) - } - } - } - - if lv, err := log.ParseLevel(cfg.LogLevel); err != nil { - log.Panicf("Invalid log_level=%s", cfg.LogLevel) - } else { - l.SetLevel(lv) - } - if lv, err := log.ParseLevel(cfg.ConsoleLevel); err != nil { - log.Panicf("Invalid console_level=%s", cfg.ConsoleLevel) - } else { - l.SetConsoleLevel(lv) - } - - for mod, lvStr := range modLevels { - if lv, err := log.ParseLevel(lvStr); err != nil { - log.Panicf("Invalid mod_level mod=%s level=%s", mod, lvStr) - } else { - l.SetModuleLevel(mod, lv) - } - } - - if cfg.LogForwarder != nil { - if cfg.LogForwarder.Vendor == "" && cfg.LogForwarder.Address == "" { - log.Debugln("LogForwarderConfig vendor and address is empty string, will be ignore") - } else { - if err := log.AddForwarder(cfg.LogForwarder); err != nil { - log.Fatalf("Invalid log_forwarder err:%+v", err) - } - } - } - - return l -} diff --git a/common/link/config.go b/common/link/config.go new file mode 100644 index 0000000..a184645 --- /dev/null +++ b/common/link/config.go @@ -0,0 +1,26 @@ +package link + +import ( + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/log" +) + +type LinkConfig struct { + config.FileConfig `json:",squash"` //instead of `mapstructure:",squash"` + Src chain.BaseConfig `json:"src"` + Dst chain.BaseConfig `json:"dst"` + Direction string `json:"direction"` //front, reverse, both +} + +type LogConfig struct { + LogLevel string `json:"log_level"` + ConsoleLevel string `json:"console_level"` + LogForwarder *log.ForwarderConfig `json:"log_forwarder,omitempty"` + LogWriter *log.WriterConfig `json:"log_writer,omitempty"` +} + +type Config struct { + LinkConfig `json:",squash"` //instead of `mapstructure:",squash"` + LogConfig `json:",squash"` //instead of `mapstructure:",squash"` +} diff --git a/common/link/link.go b/common/link/link.go index 61c3306..8320f96 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -1,7 +1,6 @@ package link import ( - "fmt" "math/rand" "sync" @@ -61,39 +60,18 @@ type Link struct { s types.Sender l log.Logger mtx sync.RWMutex - src types.BtpAddress - dst types.BtpAddress rmsMtx sync.RWMutex rms []*relayMessage rss []ReceiveStatus rmi *relayMessageItem limitSize int64 - cfg *chain.Config //TODO config refactoring + srcCfg chain.BaseConfig + dstCfg chain.BaseConfig bls *types.BMCLinkStatus blsChannel chan *types.BMCLinkStatus relayState RelayState } -func NewLink(cfg *chain.Config, r Receiver, l log.Logger) types.Link { - link := &Link{ - src: cfg.Src.Address, - dst: cfg.Dst.Address, - l: l.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", cfg.Dst.Address.NetworkID())}), - cfg: cfg, - r: r, - rms: make([]*relayMessage, 0), - rss: make([]ReceiveStatus, 0), - rmi: &relayMessageItem{ - rmis: make([][]RelayMessageItem, 0), - size: 0, - }, - blsChannel: make(chan *types.BMCLinkStatus), - relayState: RUNNING, - } - link.rmi.rmis = append(link.rmi.rmis, make([]RelayMessageItem, 0)) - return link -} - func (l *Link) Start(sender types.Sender) error { l.s = sender errCh := make(chan error) @@ -132,16 +110,17 @@ func (l *Link) Stop() { func (l *Link) receiverChannel(errCh chan error) error { once := new(sync.Once) - rsc, err := l.r.Start(l.bls) + rc, err := l.r.Start(l.bls) if err != nil { return err } go func() { for { select { - case rs := <-rsc: - switch t := rs.(type) { + case rsc := <-rc: + switch t := rsc.(type) { case ReceiveStatus: + rs := t.(ReceiveStatus) l.rss = append(l.rss, t) once.Do(func() { if err = l.handleUndeliveredRelayMessage(); err != nil { @@ -220,7 +199,7 @@ func (l *Link) buildRelayMessage() error { } if mpLen == 0 { - if l.cfg.Src.FilledBlockUpdate == true { + if l.srcCfg.FilledBlockUpdate == true { if l.isOverLimit(l.rmi.size) { if err = l.appendRelayMessage(); err != nil { return err @@ -521,7 +500,7 @@ func (l *Link) result(rr *types.RelayResult) error { if rm != nil { switch rr.Err { case errors.SUCCESS: - if l.cfg.Dst.LatestResult == true { + if l.dstCfg.LatestResult == true { l.successRelayMessage(rr.Id) } else { if rr.Finalized == true { diff --git a/common/link/linkfactory.go b/common/link/linkfactory.go new file mode 100644 index 0000000..ee751b5 --- /dev/null +++ b/common/link/linkfactory.go @@ -0,0 +1,246 @@ +package link + +import ( + "fmt" + stdlog "log" + "path" + + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/chain/ethbr" + "github.com/icon-project/btp2/chain/icon" + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" +) + +const ( + BothDirection = "both" + FrontDirection = "front" + ReverseDirection = "reverse" + + ICON = "icon" + ETH = "eth" + ETH2 = "eth2" + BSC = "bsc" + HARDHAT = "hardhat" +) + +type LinkFactory struct { + link types.Link + l log.Logger +} + +func (l *LinkFactory) GetLogger() log.Logger { + return l.l +} + +func (l *LinkFactory) Start(sender types.Sender) error { + linkErrCh := make(chan error) + go func() { + err := l.link.Start(sender) + select { + case linkErrCh <- err: + default: + } + }() + + return nil +} + +//func (l *LinkFactory) Start(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig) error { +// linkErrCh := make(chan error) +// go func() { +// s, err := NewSender(srcCfg, dstCfg, l.l) +// if err != nil { +// linkErrCh <- err +// } +// +// err = l.link.Start(s) +// if err != nil { +// linkErrCh <- err +// } +// select { +// case linkErrCh <- err: +// default: +// } +// }() +// +// return nil +//} + +func NewLinkFactory(cfg *Config, modLevels map[string]string) ([]*LinkFactory, error) { + linkFactorys := make([]*LinkFactory, 0) + switch cfg.Direction { + case FrontDirection: + lf, err := newLinkFactory(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) + if err != nil { + return nil, err + } + + linkFactorys = append(linkFactorys, lf) + + case ReverseDirection: + lf, err := newLinkFactory(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) + if err != nil { + return nil, err + } + linkFactorys = append(linkFactorys, lf) + + case BothDirection: + srcLf, err := newLinkFactory(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) + if err != nil { + return nil, err + } + + linkFactorys = append(linkFactorys, srcLf) + + dstLf, err := newLinkFactory(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) + if err != nil { + return nil, err + } + linkFactorys = append(linkFactorys, dstLf) + + default: + return nil, fmt.Errorf("Not supported direction:%s", cfg.Direction) + } + + return linkFactorys, nil +} + +func newLinkFactory(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) (*LinkFactory, error) { + var lk types.Link + l := setLogger(srcCfg, dstCfg, lc, fc, modLevels) + l.Debugln(fc.FilePath, fc.BaseDir) + if fc.BaseDir == "" { + fc.BaseDir = path.Join(".", ".relay", srcCfg.Address.NetworkAddress()) + } + + r := newReceiver(srcCfg, dstCfg, l) + lk = NewLink(srcCfg, dstCfg, r, l) + lf := &LinkFactory{ + link: lk, + l: l, + } + return lf, nil +} + +func NewLink(srcCfg, dstCfg chain.BaseConfig, r Receiver, l log.Logger) types.Link { + link := &Link{ + l: l.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", dstCfg.Address.NetworkID())}), + srcCfg: srcCfg, + dstCfg: dstCfg, + r: r, + rms: make([]*relayMessage, 0), + rss: make([]ReceiveStatus, 0), + rmi: &relayMessageItem{ + rmis: make([][]RelayMessageItem, 0), + size: 0, + }, + blsChannel: make(chan *types.BMCLinkStatus), + relayState: RUNNING, + } + link.rmi.rmis = append(link.rmi.rmis, make([]RelayMessageItem, 0)) + return link +} + +func newReceiver(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, l log.Logger) Receiver { + var receiver Receiver + + switch srcCfg.Address.BlockChain() { + case ICON: + receiver = icon.NewReceiver(srcCfg, dstCfg, l) + case ETH: + fallthrough + case ETH2: + fallthrough + case BSC: + fallthrough + case HARDHAT: + receiver = ethbr.NewReceiver(srcCfg, dstCfg, l) + default: + l.Fatalf("Not supported for chain:%s", srcCfg.Address.BlockChain()) + return nil + } + return receiver +} + +func NewSender(srcCfg, dstCfg chain.BaseConfig, l log.Logger) (types.Sender, error) { + var sender types.Sender + var err error + switch srcCfg.Address.BlockChain() { + case ICON: + sender, err = icon.NewSender(srcCfg.Address, dstCfg, l) + if err != nil { + return nil, err + } + case ETH: + fallthrough + case ETH2: + fallthrough + case BSC: + fallthrough + case HARDHAT: + sender, err = ethbr.NewSender(srcCfg.Address, dstCfg, l) + if err != nil { + return nil, err + } + default: + l.Fatalf("Not supported for chain:%s", srcCfg.Address.BlockChain()) + } + + return sender, nil +} + +func setLogger(srcCfg, dstCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) log.Logger { + l := log.WithFields(log.Fields{log.FieldKeyWallet: srcCfg.Address.NetworkID() + "2" + dstCfg.Address.NetworkAddress()}) + log.SetGlobalLogger(l) + stdlog.SetOutput(l.WriterLevel(log.WarnLevel)) + if lc.LogWriter != nil { + if lc.LogWriter.Filename == "" { + log.Debugln("LogWriterConfig filename is empty string, will be ignore") + } else { + var lwCfg log.WriterConfig + lwCfg = *lc.LogWriter + lwCfg.Filename = fc.ResolveAbsolute(lwCfg.Filename) + w, err := log.NewWriter(&lwCfg) + if err != nil { + log.Panicf("Fail to make writer err=%+v", err) + } + err = l.SetFileWriter(w) + if err != nil { + log.Panicf("Fail to set file l err=%+v", err) + } + } + } + + if lv, err := log.ParseLevel(lc.LogLevel); err != nil { + log.Panicf("Invalid log_level=%s", lc.LogLevel) + } else { + l.SetLevel(lv) + } + if lv, err := log.ParseLevel(lc.ConsoleLevel); err != nil { + log.Panicf("Invalid console_level=%s", lc.ConsoleLevel) + } else { + l.SetConsoleLevel(lv) + } + + for mod, lvStr := range modLevels { + if lv, err := log.ParseLevel(lvStr); err != nil { + log.Panicf("Invalid mod_level mod=%s level=%s", mod, lvStr) + } else { + l.SetModuleLevel(mod, lv) + } + } + + if lc.LogForwarder != nil { + if lc.LogForwarder.Vendor == "" && lc.LogForwarder.Address == "" { + log.Debugln("LogForwarderConfig vendor and address is empty string, will be ignore") + } else { + if err := log.AddForwarder(lc.LogForwarder); err != nil { + log.Fatalf("Invalid log_forwarder err:%+v", err) + } + } + } + + return l +} diff --git a/common/link/type.go b/common/link/type.go index eb0e8c2..cbc3136 100644 --- a/common/link/type.go +++ b/common/link/type.go @@ -52,12 +52,12 @@ type BlockProof interface { type MessageProof interface { RelayMessageItem - StartSeqNum() int64 - LastSeqNum() int64 + StartSeqNum() int64 //TODO change + LastSeqNum() int64 //TODO change } type Receiver interface { - Start(bls *types.BMCLinkStatus) (<-chan ReceiveStatus, error) + Start(bls *types.BMCLinkStatus) (<-chan interface{}, error) Stop() GetStatus() (ReceiveStatus, error) BuildBlockUpdate(bls *types.BMCLinkStatus, limit int64) ([]BlockUpdate, error) From 1e72387089374fdcf45448f568fb119688f663ed Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Thu, 6 Jul 2023 17:32:27 +0900 Subject: [PATCH 02/22] Refactor relay --- chain/ethbr/client/client.go | 33 ++-- chain/ethbr/factory.go | 10 +- chain/ethbr/receiver.go | 16 +- chain/ethbr/sender.go | 20 +-- chain/icon/bridge/bridge.go | 18 +-- chain/icon/btp2/btp2.go | 45 ++---- chain/icon/client/client.go | 30 +++- chain/icon/factory.go | 4 +- chain/icon/sender.go | 24 +-- cmd/relay/main.go | 19 +-- common/link/link.go | 49 ++++-- common/{link => linkfactory}/config.go | 2 +- common/{link => linkfactory}/linkfactory.go | 157 ++++++++++++-------- common/types/type.go | 6 +- common/wallet/encrypted.go | 81 ---------- common/wallet/keystore.go | 3 +- common/wallet/wallet.go | 15 +- common/wallet/wallet_evm.go | 14 +- 18 files changed, 260 insertions(+), 286 deletions(-) rename common/{link => linkfactory}/config.go (97%) rename common/{link => linkfactory}/linkfactory.go (61%) delete mode 100644 common/wallet/encrypted.go diff --git a/chain/ethbr/client/client.go b/chain/ethbr/client/client.go index 640b293..6e6b6f0 100644 --- a/chain/ethbr/client/client.go +++ b/chain/ethbr/client/client.go @@ -49,19 +49,13 @@ var ( BlockRetryLimit = 5 ) -type Wallet interface { - Sign(data []byte) ([]byte, error) - Address() string -} - type Client struct { - uri string - log log.Logger - subscription *rpc.ClientSubscription - ethClient *ethclient.Client - rpcClient *rpc.Client - chainID *big.Int - stop <-chan bool + uri string + log log.Logger + ethClient *ethclient.Client + rpcClient *rpc.Client + chainID *big.Int + stop <-chan bool } func toBlockNumArg(number *big.Int) string { @@ -203,7 +197,7 @@ func (c *Client) GetBlockNumber() (uint64, error) { } // Poll deprecated -func (c *Client) Poll(cb func(bh *types.Header) error) error { +func (c *Client) Poll(cb func(bh *types.Header) error, errCb func(int64, error)) error { n, err := c.GetBlockNumber() if err != nil { return err @@ -227,7 +221,7 @@ func (c *Client) Poll(cb func(bh *types.Header) error) error { if err = cb(bh); err != nil { c.log.Errorf("Poll callback return err:%+v", err) - return err + errCb(bh.Number.Int64()-1, err) } current.Add(current, big.NewInt(1)) @@ -235,7 +229,7 @@ func (c *Client) Poll(cb func(bh *types.Header) error) error { } } -func (c *Client) MonitorBlock(br *BlockRequest, cb func(b *BlockNotification) error) error { +func (c *Client) MonitorBlock(br *BlockRequest, cb func(b *BlockNotification) error, errCb func(int64, error)) error { onBlockHeader := func(bh *types.Header) error { bn := &BlockNotification{ Hash: bh.Hash(), @@ -277,12 +271,12 @@ func (c *Client) MonitorBlock(br *BlockRequest, cb func(b *BlockNotification) er } } return onBlockHeader(bh) - }) + }, errCb) } -func (c *Client) Monitor(cb func(bh *types.Header) error) error { +func (c *Client) Monitor(cb func(bh *types.Header) error, errCb func(int64, error)) error { if strings.HasPrefix(c.uri, "http") { - return c.Poll(cb) + return c.Poll(cb, errCb) } var ( s ethereum.Subscription @@ -292,7 +286,7 @@ func (c *Client) Monitor(cb func(bh *types.Header) error) error { if s, err = c.ethClient.SubscribeNewHead(context.Background(), ch); err != nil { if rpc.ErrNotificationsUnsupported == err { c.log.Infoln("%v, try polling", err) - return c.Poll(cb) + return c.Poll(cb, errCb) } return err } @@ -312,7 +306,6 @@ func (c *Client) Monitor(cb func(bh *types.Header) error) error { func (c *Client) CloseMonitor() { c.log.Debugf("CloseMonitor %s", c.rpcClient) - c.subscription.Unsubscribe() c.ethClient.Close() c.rpcClient.Close() } diff --git a/chain/ethbr/factory.go b/chain/ethbr/factory.go index 2a975af..ddab654 100644 --- a/chain/ethbr/factory.go +++ b/chain/ethbr/factory.go @@ -6,18 +6,12 @@ import ( "os" "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" "github.com/icon-project/btp2/common/wallet" ) -const ( - BRIDGE = "bridge" - TRUSTLESS = "trustless" -) - -func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { +func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) *ethbr { receiver := newEthBridge(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l, srcCfg.Options) return receiver } @@ -32,7 +26,7 @@ func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (ty return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil } -func Wallet(passwd, secret string, keyStore json.RawMessage) (wallet.Wallet, error) { +func Wallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { pw, err := resolvePassword(secret, passwd) if err != nil { return nil, err diff --git a/chain/ethbr/receiver.go b/chain/ethbr/receiver.go index a6f949e..680e9f0 100644 --- a/chain/ethbr/receiver.go +++ b/chain/ethbr/receiver.go @@ -73,6 +73,7 @@ type ethbr struct { nid int64 rsc chan interface{} rss []*receiveStatus + rs *receiveStatus seq int64 startHeight int64 opt struct { @@ -87,6 +88,7 @@ func newEthBridge(src, dst btpTypes.BtpAddress, endpoint string, l log.Logger, o l: l, rsc: make(chan interface{}), rss: make([]*receiveStatus, 0), + rs: &receiveStatus{}, } c.c = client.NewClient(endpoint, l) b, err := json.Marshal(opt) @@ -265,6 +267,17 @@ func (e *ethbr) Monitoring(bls *btpTypes.BMCLinkStatus) error { e.seq = bls.RxSeq } + errCb := func(height int64, err error) { + e.l.Debugf("onError err:%+v", err) + e.c.CloseMonitor() + //Restart Monitoring + ls := &btpTypes.BMCLinkStatus{} + ls.RxSeq = e.seq + ls.Verifier.Height = height + e.l.Debugf("Restart Monitoring") + e.Monitoring(ls) + } + return e.c.MonitorBlock(br, func(v *client.BlockNotification) error { @@ -329,8 +342,7 @@ func (e *ethbr) Monitoring(bls *btpTypes.BMCLinkStatus) error { } return nil - }, - ) + }, errCb) } func (e *ethbr) newBlockUpdate(v *client.BlockNotification) (*client.BlockUpdate, error) { diff --git a/chain/ethbr/sender.go b/chain/ethbr/sender.go index d6c0282..3c08696 100644 --- a/chain/ethbr/sender.go +++ b/chain/ethbr/sender.go @@ -51,7 +51,7 @@ type Queue struct { } type relayMessageTx struct { - id int + id string txHash []byte } @@ -60,7 +60,7 @@ func NewQueue() *Queue { return queue } -func (q *Queue) enqueue(id int, txHash []byte) error { +func (q *Queue) enqueue(id string, txHash []byte) error { if MaxQueueSize <= len(q.values) { return fmt.Errorf("queue full") } @@ -72,7 +72,7 @@ func (q *Queue) enqueue(id int, txHash []byte) error { return nil } -func (q *Queue) dequeue(id int) { +func (q *Queue) dequeue(id string) { for i, rm := range q.values { if rm.id == id { q.values = q.values[i+1:] @@ -93,7 +93,7 @@ type sender struct { c *client.Client src btpTypes.BtpAddress dst btpTypes.BtpAddress - w client.Wallet + w btpTypes.Wallet l log.Logger opt struct { } @@ -103,7 +103,7 @@ type sender struct { queue *Queue } -func newSender(src, dst btpTypes.BtpAddress, w client.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) btpTypes.Sender { +func newSender(src, dst btpTypes.BtpAddress, w btpTypes.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) btpTypes.Sender { s := &sender{ src: src, dst: dst, @@ -156,15 +156,15 @@ func (s *sender) GetMarginForLimit() int64 { return 0 } -func (s *sender) Relay(rm btpTypes.RelayMessage) (int, error) { +func (s *sender) Relay(rm btpTypes.RelayMessage) (string, error) { //check send queue if MaxQueueSize <= s.queue.len() { - return 0, errors.InvalidStateError.New("pending queue full") + return "", errors.InvalidStateError.New("pending queue full") } thp, err := s._relay(rm) if err != nil { - return 0, err + return "", err } s.queue.enqueue(rm.Id(), thp.Hash.Bytes()) @@ -172,7 +172,7 @@ func (s *sender) Relay(rm btpTypes.RelayMessage) (int, error) { return rm.Id(), nil } -func (s *sender) result(id int, txh *client.TransactionHashParam) { +func (s *sender) result(id string, txh *client.TransactionHashParam) { _, err := s.GetResult(txh) s.queue.dequeue(id) @@ -187,7 +187,7 @@ func (s *sender) result(id int, txh *client.TransactionHashParam) { } } } else { - s.l.Debugf("result success rm id : %d , txHash : %v", id, txh.Hash) + s.l.Debugf("result success rm id : %s , txHash : %v", id, txh.Hash) s.rr <- &btpTypes.RelayResult{ Id: id, Err: -1, diff --git a/chain/icon/bridge/bridge.go b/chain/icon/bridge/bridge.go index 79357fd..6ea50d0 100644 --- a/chain/icon/bridge/bridge.go +++ b/chain/icon/bridge/bridge.go @@ -199,17 +199,6 @@ func (b *bridge) FinalizedStatus(blsc <-chan *types.BMCLinkStatus) { }() } -// TODO Refactoring reduplication func -func (b *bridge) getBtpMessage(height int64) ([]string, error) { - pr := &client.BTPBlockParam{Height: client.HexInt(intconv.FormatInt(height)), NetworkId: client.HexInt(intconv.FormatInt(b.nid))} - mgs, err := b.c.GetBTPMessage(pr) - if err != nil { - return nil, err - } - - return mgs, nil -} - func (b *bridge) Monitoring(bls *types.BMCLinkStatus) error { if bls.Verifier.Height < 1 { return fmt.Errorf("cannot catchup from zero height") @@ -226,14 +215,14 @@ func (b *bridge) Monitoring(bls *types.BMCLinkStatus) error { b.c.CloseMonitor(conn) //Restart Monitoring ls := &types.BMCLinkStatus{} - ls.TxSeq = b.rs.Seq() + ls.RxSeq = b.rs.Seq() ls.Verifier.Height = b.rs.Height() b.l.Debugf("Restart Monitoring") b.Monitoring(ls) } onConn := func(conn *websocket.Conn) { b.l.Debugf("ReceiveLoop monitorBTP2Block height:%d seq:%d networkId:%d connected %s", - bls.Verifier.Height, bls.TxSeq, b.nid, conn.LocalAddr().String()) + bls.Verifier.Height, bls.RxSeq, b.nid, conn.LocalAddr().String()) } err := b.monitorBTP2Block(req, bls, onConn, onErr) @@ -266,8 +255,9 @@ func (b *bridge) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStat if _, err = codec.RLP.UnmarshalFromBytes(h, bh); err != nil { return err } + if bh.MainHeight != b.startHeight { - msgs, err := b.getBtpMessage(bh.MainHeight) + msgs, err := b.c.GetBTPMessage(bh.MainHeight, b.nid) if err != nil { return err } diff --git a/chain/icon/btp2/btp2.go b/chain/icon/btp2/btp2.go index f739c77..d7931ab 100644 --- a/chain/icon/btp2/btp2.go +++ b/chain/icon/btp2/btp2.go @@ -3,7 +3,6 @@ package btp2 import ( "encoding/base64" "fmt" - "time" "github.com/gorilla/websocket" @@ -11,17 +10,12 @@ import ( "github.com/icon-project/btp2/common/codec" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/intconv" - "github.com/icon-project/btp2/common/jsonrpc" "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/mbt" "github.com/icon-project/btp2/common/types" ) -const ( - DefaultGetBtpMessageInterval = time.Second -) - type receiveStatus struct { height int64 seq int64 @@ -80,24 +74,6 @@ func (b *btp2) getNetworkId() error { return nil } -func (b *btp2) getBtpMessage(height int64) ([]string, error) { - for { - pr := &client.BTPBlockParam{Height: client.HexInt(intconv.FormatInt(height)), NetworkId: client.HexInt(intconv.FormatInt(b.nid))} - mgs, err := b.c.GetBTPMessage(pr) - if err != nil { - if je, ok := err.(*jsonrpc.Error); ok { - switch je.Code { - case client.JsonrpcErrorCodeNotFound: - <-time.After(DefaultGetBtpMessageInterval) - continue - default: - return nil, err - } - } - } - return mgs, nil - } -} func (b *btp2) getBtpHeader(height int64) ([]byte, []byte, error) { pr := &client.BTPBlockParam{Height: client.HexInt(intconv.FormatInt(height)), NetworkId: client.HexInt(intconv.FormatInt(b.nid))} @@ -283,7 +259,7 @@ func (b *btp2) clearReceiveStatus(bls *types.BMCLinkStatus) { } func (b *btp2) getMessage(height int64) (*mbt.MerkleBinaryTree, error) { - msgs, err := b.getBtpMessage(height) + msgs, err := b.c.GetBTPMessage(height, b.nid) if err != nil { return nil, err } @@ -319,14 +295,14 @@ func (b *btp2) Monitoring(bls *types.BMCLinkStatus) error { b.c.CloseMonitor(conn) //Restart Monitoring ls := &types.BMCLinkStatus{} - ls.TxSeq = b.rs.Seq() + ls.RxSeq = b.rs.Seq() ls.Verifier.Height = b.rs.Height() b.l.Debugf("Restart Monitoring") b.Monitoring(ls) } onConn := func(conn *websocket.Conn) { b.l.Debugf("ReceiveLoop monitorBTP2Block height:%d seq:%d networkId:%d connected %s", - bls.Verifier.Height, bls.TxSeq, b.nid, conn.LocalAddr().String()) + bls.Verifier.Height, bls.RxSeq, b.nid, conn.LocalAddr().String()) } err := b.monitorBTP2Block(req, bls, onConn, onErr) @@ -337,8 +313,14 @@ func (b *btp2) Monitoring(bls *types.BMCLinkStatus) error { } func (b *btp2) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus, scb func(conn *websocket.Conn), errCb func(*websocket.Conn, error)) error { + vs := &client.VerifierStatus{} + _, err := codec.RLP.UnmarshalFromBytes(bls.Verifier.Extra, vs) + if err != nil { + return err + } + if bls.RxSeq != 0 { - b.seq = bls.RxSeq + b.seq = bls.RxSeq + vs.SequenceOffset } if b.rs.Height() == 0 { @@ -356,9 +338,9 @@ func (b *btp2) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus if _, err = codec.RLP.UnmarshalFromBytes(h, bh); err != nil { return err } - - if bh.MainHeight != b.startHeight { - msgs, err := b.getBtpMessage(bh.MainHeight) + firstMessageSN := bh.UpdateNumber >> 1 + if firstMessageSN == b.seq && bh.MainHeight != b.startHeight { + msgs, err := b.c.GetBTPMessage(bh.MainHeight, b.nid) if err != nil { return err } @@ -373,6 +355,7 @@ func (b *btp2) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus b.l.Debugf("monitor info : Height:%d UpdateNumber:%d MessageCnt:%d Seq:%d ", bh.MainHeight, bh.UpdateNumber, len(msgs), b.seq) b.rsc <- rs } + return nil }, scb, errCb) } diff --git a/chain/icon/client/client.go b/chain/icon/client/client.go index 1d8a45c..f508916 100644 --- a/chain/icon/client/client.go +++ b/chain/icon/client/client.go @@ -34,6 +34,7 @@ import ( "github.com/icon-project/btp2/common" "github.com/icon-project/btp2/common/crypto" "github.com/icon-project/btp2/common/errors" + "github.com/icon-project/btp2/common/intconv" "github.com/icon-project/btp2/common/jsonrpc" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" @@ -42,17 +43,13 @@ import ( const ( DefaultSendTransactionRetryInterval = 3 * time.Second //3sec DefaultGetTransactionResultPollingInterval = 1500 * time.Millisecond //1.5sec + DefaultGetBtpMessageInterval = time.Second //1sec ) var ( BlockRetryLimit = 5 ) -type Wallet interface { - Sign(data []byte) ([]byte, error) - Address() string -} - type Client struct { *jsonrpc.Client conns map[string]*websocket.Conn @@ -66,7 +63,7 @@ type SendKeepaliveMessage struct { var txSerializeExcludes = map[string]bool{"signature": true} -func (c *Client) SignTransaction(w Wallet, p *TransactionParam) error { +func (c *Client) SignTransaction(w types.Wallet, p *TransactionParam) error { p.Timestamp = NewHexInt(time.Now().UnixNano() / int64(time.Microsecond)) js, err := json.Marshal(p) if err != nil { @@ -231,7 +228,26 @@ func (c *Client) GetBTPHeader(p *BTPBlockParam) (string, error) { } } -func (c *Client) GetBTPMessage(p *BTPBlockParam) ([]string, error) { +func (c *Client) GetBTPMessage(height, nid int64) ([]string, error) { + for { + pr := &BTPBlockParam{Height: HexInt(intconv.FormatInt(height)), NetworkId: HexInt(intconv.FormatInt(nid))} + mgs, err := c.getBTPMessage(pr) + if err != nil { + if je, ok := err.(*jsonrpc.Error); ok { + switch je.Code { + case JsonrpcErrorCodeNotFound: + <-time.After(DefaultGetBtpMessageInterval) + continue + default: + return nil, err + } + } + } + return mgs, nil + } +} + +func (c *Client) getBTPMessage(p *BTPBlockParam) ([]string, error) { var result []string var retry = BlockRetryLimit for { diff --git a/chain/icon/factory.go b/chain/icon/factory.go index a47383a..dd79290 100644 --- a/chain/icon/factory.go +++ b/chain/icon/factory.go @@ -43,7 +43,7 @@ func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (ty return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil } -func Wallet(passwd, secret string, keyStore json.RawMessage) (wallet.Wallet, error) { +func Wallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { pw, err := resolvePassword(secret, passwd) if err != nil { return nil, err @@ -58,7 +58,7 @@ func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { if keyStorePass != "" { return []byte(keyStorePass), nil } else { - //TODO + //TODO add error message return nil, fmt.Errorf("") } } diff --git a/chain/icon/sender.go b/chain/icon/sender.go index c240033..0d7ff10 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -50,7 +50,7 @@ type Queue struct { } type relayMessageTx struct { - id int + id string txHash []byte } @@ -59,7 +59,7 @@ func NewQueue() *Queue { return queue } -func (q *Queue) enqueue(id int, txHash []byte) error { +func (q *Queue) enqueue(id string, txHash []byte) error { if MaxQueueSize <= len(q.values) { return fmt.Errorf("queue full") } @@ -71,7 +71,7 @@ func (q *Queue) enqueue(id int, txHash []byte) error { return nil } -func (q *Queue) dequeue(id int) { +func (q *Queue) dequeue(id string) { for i, rm := range q.values { if rm.id == id { q.values = q.values[i+1:] @@ -92,7 +92,7 @@ type sender struct { c *client.Client src types.BtpAddress dst types.BtpAddress - w client.Wallet + w types.Wallet l log.Logger opt struct { StepLimit int64 @@ -102,7 +102,7 @@ type sender struct { queue *Queue } -func newSender(src, dst types.BtpAddress, w client.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) types.Sender { +func newSender(src, dst types.BtpAddress, w types.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) types.Sender { s := &sender{ src: src, dst: dst, @@ -133,21 +133,21 @@ func (s *sender) Stop() { close(s.rr) } -func (s *sender) Relay(rm types.RelayMessage) (int, error) { +func (s *sender) Relay(rm types.RelayMessage) (string, error) { //check send queue if MaxQueueSize <= s.queue.len() { - return 0, errors.InvalidStateError.New("pending queue full") + return "", errors.InvalidStateError.New("pending queue full") } s.l.Debugf("_relay src address:%s, rm id:%d, rm msg:%s", s.src.String(), rm.Id(), hex.EncodeToString(rm.Bytes()[:])) thp, err := s._relay(rm) if err != nil { - return 0, err + return "", err } b, err := thp.Hash.Value() if err != nil { - return 0, err + return "", err } s.queue.enqueue(rm.Id(), b) @@ -189,7 +189,7 @@ func (s *sender) _relay(rm types.RelayMessage) (*client.TransactionHashParam, er } } -func (s *sender) result(id int, txh *client.TransactionHashParam) { +func (s *sender) result(id string, txh *client.TransactionHashParam) { _, err := s.GetResult(txh) s.queue.dequeue(id) @@ -204,7 +204,7 @@ func (s *sender) result(id int, txh *client.TransactionHashParam) { } } } else { - s.l.Debugf("result success rm id : %d , txHash : %v", id, txh.Hash) + s.l.Debugf("result success rm id : %s , txHash : %v", id, txh.Hash) s.rr <- &types.RelayResult{ Id: id, Err: -1, @@ -256,7 +256,7 @@ func (s *sender) newTransactionParam(method string, params interface{}) *client. FromAddress: client.Address(s.w.Address()), ToAddress: client.Address(s.dst.Account()), NetworkID: client.HexInt(s.dst.NetworkID()), - StepLimit: client.NewHexInt(s.opt.StepLimit), + StepLimit: client.NewHexInt(s.opt.StepLimit), //TODO stepLimit estimate DataType: "call", Data: &client.CallData{ Method: method, diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 77bb121..3c01374 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -25,7 +25,7 @@ import ( "github.com/spf13/cobra" "github.com/icon-project/btp2/common/cli" - "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/linkfactory" "github.com/icon-project/btp2/common/log" ) @@ -47,7 +47,7 @@ var logoLines = []string{ func main() { rootCmd, rootVc := cli.NewCommand(nil, nil, "relay", "BTP Relay CLI") - cfg := &link.Config{} + cfg := &linkfactory.Config{} rootCmd.Long = "Command Line Interface of Relay for Blockchain Transmission Protocol" cli.SetEnvKeyReplacer(rootVc, strings.NewReplacer(".", "_")) //rootVc.Debug() @@ -94,7 +94,7 @@ func main() { rootPFlags.String("src.key_store", "", "Source keyStore") rootPFlags.String("src.key_password", "", "Source password of keyStore") rootPFlags.String("src.key_secret", "", "Source Secret(password) file for keyStore") - rootPFlags.Bool("src.bridge_mode", false, "Source bridge mode") + rootPFlags.String("src.relay_mode", "trustless", "Relay Mode") rootPFlags.Bool("src.latest_result", false, "Sends relay messages regardless of final status reception.") rootPFlags.Bool("src.filled_block_update", false, "Create relayMessage for all data received from the source network") @@ -104,7 +104,7 @@ func main() { rootPFlags.String("dst.key_store", "", "Destination keyStore") rootPFlags.String("dst.key_password", "", "Destination password of keyStore") rootPFlags.String("dst.key_secret", "", "Destination Secret(password) file for keyStore") - rootPFlags.Bool("dst.bridge_mode", false, "Destination bridge mode") + rootPFlags.String("dst.relay_mode", "trustless", "Relay Mode") rootPFlags.Bool("dst.latest_result", false, "Sends relay messages regardless of final status reception.") rootPFlags.Bool("dst.filled_block_update", false, "Create relayMessage for all data received from the source network") @@ -186,17 +186,12 @@ func main() { modLevels, _ := cmd.Flags().GetStringToString("mod_level") - ls, err := link.NewLinkFactory(cfg, modLevels) + lf, err := linkfactory.NewLinkFactory(cfg, modLevels) if err != nil { return err } - - s, err := link.NewSender(cfg.Src, cfg.Dst, ls[0].GetLogger()) - if err != nil { - return err - } - - return ls[0].Start(s) + + return lf.Start() }, } rootCmd.AddCommand(startCmd) diff --git a/common/link/link.go b/common/link/link.go index 8320f96..4b105fc 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -1,7 +1,7 @@ package link import ( - "math/rand" + "strconv" "sync" "github.com/icon-project/btp2/chain" @@ -18,7 +18,7 @@ const ( ) type relayMessage struct { - id int + id string bls *types.BMCLinkStatus bpHeight int64 message []byte @@ -26,7 +26,7 @@ type relayMessage struct { sendingStatus bool } -func (r *relayMessage) Id() int { +func (r *relayMessage) Id() string { return r.id } @@ -72,6 +72,25 @@ type Link struct { relayState RelayState } +func NewLink(srcCfg, dstCfg chain.BaseConfig, r Receiver, l log.Logger) types.Link { + link := &Link{ + l: l, + srcCfg: srcCfg, + dstCfg: dstCfg, + r: r, + rms: make([]*relayMessage, 0), + rss: make([]ReceiveStatus, 0), + rmi: &relayMessageItem{ + rmis: make([][]RelayMessageItem, 0), + size: 0, + }, + blsChannel: make(chan *types.BMCLinkStatus), + relayState: RUNNING, + } + link.rmi.rmis = append(link.rmi.rmis, make([]RelayMessageItem, 0)) + return link +} + func (l *Link) Start(sender types.Sender) error { l.s = sender errCh := make(chan error) @@ -249,7 +268,7 @@ func (l *Link) appendRelayMessage() error { } rm := &relayMessage{ - id: rand.Int(), + id: l.srcCfg.Address.NetworkID() + "_" + strconv.FormatInt(l.bls.Verifier.Height, 16) + "_" + strconv.FormatInt(l.bls.RxSeq, 16), bls: &types.BMCLinkStatus{}, bpHeight: l.r.GetHeightForSeq(l.bls.RxSeq), message: m, @@ -327,14 +346,27 @@ func (l *Link) handleUndeliveredRelayMessage() error { func (l *Link) buildProof(bu BlockUpdate) (int64, error) { var mpLen int64 + rs := l.getReceiveStatusForHeight(l.bls.Verifier.Height) + if rs == nil { + return 0, nil + } for { + if rs.Seq() <= l.bls.RxSeq { + break + } + mp, err := l.buildMessageProof() if err != nil { return 0, err } if mp == nil || mp.Len() == 0 { - return 0, nil + if len(l.rmi.rmis) != 0 { + l.appendRelayMessage() + continue + } else { + return 0, nil + } } mpLen += mp.Len() @@ -355,7 +387,6 @@ func (l *Link) buildProof(bu BlockUpdate) (int64, error) { } } l.appendRelayMessageItem(mp) - } return mpLen, nil } @@ -420,7 +451,7 @@ func (l *Link) getRelayMessage(bls *types.BMCLinkStatus) *relayMessage { return nil } -func (l *Link) getRelayMessageForId(id int) *relayMessage { +func (l *Link) getRelayMessageForId(id string) *relayMessage { for _, rm := range l.rms { if rm.Id() == id { return rm @@ -444,7 +475,7 @@ func (l *Link) removeAllRelayMessage() { l.rms = l.rms[:0] } -func (l *Link) updateBlockProof(id int) error { +func (l *Link) updateBlockProof(id string) error { rm := l.getRelayMessageForId(id) for _, rmi := range rm.RelayMessageItems() { @@ -472,7 +503,7 @@ func (l *Link) resetRelayMessageItem() { l.rmi.size = 0 } -func (l *Link) successRelayMessage(id int) error { +func (l *Link) successRelayMessage(id string) error { rm := l.getRelayMessageForId(id) l.removeRelayMessage(rm.BMCLinkStatus()) l.removeReceiveStatus(rm.BMCLinkStatus()) diff --git a/common/link/config.go b/common/linkfactory/config.go similarity index 97% rename from common/link/config.go rename to common/linkfactory/config.go index a184645..2fc3f46 100644 --- a/common/link/config.go +++ b/common/linkfactory/config.go @@ -1,4 +1,4 @@ -package link +package linkfactory import ( "github.com/icon-project/btp2/chain" diff --git a/common/link/linkfactory.go b/common/linkfactory/linkfactory.go similarity index 61% rename from common/link/linkfactory.go rename to common/linkfactory/linkfactory.go index ee751b5..cf46b88 100644 --- a/common/link/linkfactory.go +++ b/common/linkfactory/linkfactory.go @@ -1,4 +1,4 @@ -package link +package linkfactory import ( "fmt" @@ -9,6 +9,7 @@ import ( "github.com/icon-project/btp2/chain/ethbr" "github.com/icon-project/btp2/chain/icon" "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" ) @@ -25,21 +26,20 @@ const ( HARDHAT = "hardhat" ) -type LinkFactory struct { +type LinkInfo struct { link types.Link l log.Logger } -func (l *LinkFactory) GetLogger() log.Logger { +func (l *LinkInfo) GetLogger() log.Logger { return l.l } -func (l *LinkFactory) Start(sender types.Sender) error { - linkErrCh := make(chan error) +func (l *LinkInfo) Start(sender types.Sender, errCh chan error) error { go func() { err := l.link.Start(sender) select { - case linkErrCh <- err: + case errCh <- err: default: } }() @@ -47,6 +47,27 @@ func (l *LinkFactory) Start(sender types.Sender) error { return nil } +func (l *LinkInfo) Stop() { + l.link.Stop() +} + +func NewLinkInfo(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) (*LinkInfo, error) { + var lk types.Link + l := setLogger(srcCfg, lc, fc, modLevels) + l.Debugln(fc.FilePath, fc.BaseDir) + if fc.BaseDir == "" { + fc.BaseDir = path.Join(".", ".relay", srcCfg.Address.NetworkAddress()) + } + + r := newReceiver(srcCfg, dstCfg, l) + lk = link.NewLink(srcCfg, dstCfg, r, l) + linkInfo := &LinkInfo{ + link: lk, + l: l, + } + return linkInfo, nil +} + //func (l *LinkFactory) Start(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig) error { // linkErrCh := make(chan error) // go func() { @@ -68,83 +89,99 @@ func (l *LinkFactory) Start(sender types.Sender) error { // return nil //} -func NewLinkFactory(cfg *Config, modLevels map[string]string) ([]*LinkFactory, error) { - linkFactorys := make([]*LinkFactory, 0) +type LinkFactory struct { + linkInfos []*LinkInfo + senders []types.Sender +} + +func (l *LinkFactory) Start() error { + linkErrCh := make(chan error) + + for i, linkInfo := range l.linkInfos { + if err := linkInfo.Start(l.senders[i], linkErrCh); err != nil { + return err + } + } + + for { + select { + case err := <-linkErrCh: + if err != nil { + return err + } + } + } +} + +func (l *LinkFactory) Stop() { + for i, linkInfo := range l.linkInfos { + linkInfo.Stop() + l.senders[i].Stop() + } +} + +func NewLinkFactory(cfg *Config, modLevels map[string]string) (*LinkFactory, error) { + lf := &LinkFactory{ + linkInfos: make([]*LinkInfo, 0), + senders: make([]types.Sender, 0), + } + switch cfg.Direction { case FrontDirection: - lf, err := newLinkFactory(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) + linkInfo, err := NewLinkInfo(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) if err != nil { return nil, err } - - linkFactorys = append(linkFactorys, lf) - + sender, err := NewSender(cfg.Src, cfg.Dst, linkInfo.GetLogger()) + if err != nil { + return nil, err + } + lf.linkInfos = append(lf.linkInfos, linkInfo) + lf.senders = append(lf.senders, sender) case ReverseDirection: - lf, err := newLinkFactory(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) + linkInfo, err := NewLinkInfo(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) if err != nil { return nil, err } - linkFactorys = append(linkFactorys, lf) + sender, err := NewSender(cfg.Dst, cfg.Src, linkInfo.GetLogger()) + if err != nil { + return nil, err + } + lf.linkInfos = append(lf.linkInfos, linkInfo) + lf.senders = append(lf.senders, sender) case BothDirection: - srcLf, err := newLinkFactory(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) + srcLinkInfo, err := NewLinkInfo(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) if err != nil { return nil, err } + srcSender, err := NewSender(cfg.Src, cfg.Dst, srcLinkInfo.GetLogger()) + if err != nil { + return nil, err + } + lf.linkInfos = append(lf.linkInfos, srcLinkInfo) + lf.senders = append(lf.senders, srcSender) - linkFactorys = append(linkFactorys, srcLf) - - dstLf, err := newLinkFactory(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) + dstLinkInfo, err := NewLinkInfo(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) + if err != nil { + return nil, err + } + dstSender, err := NewSender(cfg.Dst, cfg.Src, dstLinkInfo.GetLogger()) if err != nil { return nil, err } - linkFactorys = append(linkFactorys, dstLf) + lf.linkInfos = append(lf.linkInfos, dstLinkInfo) + lf.senders = append(lf.senders, dstSender) default: return nil, fmt.Errorf("Not supported direction:%s", cfg.Direction) } - return linkFactorys, nil -} - -func newLinkFactory(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) (*LinkFactory, error) { - var lk types.Link - l := setLogger(srcCfg, dstCfg, lc, fc, modLevels) - l.Debugln(fc.FilePath, fc.BaseDir) - if fc.BaseDir == "" { - fc.BaseDir = path.Join(".", ".relay", srcCfg.Address.NetworkAddress()) - } - - r := newReceiver(srcCfg, dstCfg, l) - lk = NewLink(srcCfg, dstCfg, r, l) - lf := &LinkFactory{ - link: lk, - l: l, - } return lf, nil } -func NewLink(srcCfg, dstCfg chain.BaseConfig, r Receiver, l log.Logger) types.Link { - link := &Link{ - l: l.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", dstCfg.Address.NetworkID())}), - srcCfg: srcCfg, - dstCfg: dstCfg, - r: r, - rms: make([]*relayMessage, 0), - rss: make([]ReceiveStatus, 0), - rmi: &relayMessageItem{ - rmis: make([][]RelayMessageItem, 0), - size: 0, - }, - blsChannel: make(chan *types.BMCLinkStatus), - relayState: RUNNING, - } - link.rmi.rmis = append(link.rmi.rmis, make([]RelayMessageItem, 0)) - return link -} - -func newReceiver(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, l log.Logger) Receiver { - var receiver Receiver +func newReceiver(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { + var receiver link.Receiver switch srcCfg.Address.BlockChain() { case ICON: @@ -167,7 +204,7 @@ func newReceiver(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, l log.Logger) func NewSender(srcCfg, dstCfg chain.BaseConfig, l log.Logger) (types.Sender, error) { var sender types.Sender var err error - switch srcCfg.Address.BlockChain() { + switch dstCfg.Address.BlockChain() { case ICON: sender, err = icon.NewSender(srcCfg.Address, dstCfg, l) if err != nil { @@ -191,8 +228,8 @@ func NewSender(srcCfg, dstCfg chain.BaseConfig, l log.Logger) (types.Sender, err return sender, nil } -func setLogger(srcCfg, dstCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) log.Logger { - l := log.WithFields(log.Fields{log.FieldKeyWallet: srcCfg.Address.NetworkID() + "2" + dstCfg.Address.NetworkAddress()}) +func setLogger(srcCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) log.Logger { + l := log.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", srcCfg.Address.NetworkID())}) log.SetGlobalLogger(l) stdlog.SetOutput(l.WriterLevel(log.WarnLevel)) if lc.LogWriter != nil { diff --git a/common/types/type.go b/common/types/type.go index b5df3c3..8997536 100644 --- a/common/types/type.go +++ b/common/types/type.go @@ -25,7 +25,7 @@ import ( var BigIntOne = big.NewInt(1) type RelayMessage interface { - Id() int + Id() string Bytes() []byte Size() int64 } @@ -51,7 +51,7 @@ type BMCLinkStatus struct { } type RelayResult struct { - Id int + Id string Err errors.Code Finalized bool } @@ -60,7 +60,7 @@ type Sender interface { Start() (<-chan *RelayResult, error) Stop() GetStatus() (*BMCLinkStatus, error) - Relay(rm RelayMessage) (int, error) + Relay(rm RelayMessage) (string, error) GetMarginForLimit() int64 TxSizeLimit() int } diff --git a/common/wallet/encrypted.go b/common/wallet/encrypted.go deleted file mode 100644 index 2deca78..0000000 --- a/common/wallet/encrypted.go +++ /dev/null @@ -1,81 +0,0 @@ -package wallet - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "fmt" - "io" - - "github.com/icon-project/btp2/common/crypto" -) - -const ( - EncryptSaltSize = 4 - HKDFInfo = "BTP_SECRET_HKDF" - AES128KeySize = 16 - HKDFKeySize = 2 * AES128KeySize -) - -type Encrypted struct { - Param []byte `json:"param"` - CipherText []byte `json:"cipher_text"` -} - -func (e *Encrypted) Aes128CTRStream(w Wallet) (cipher.Stream, error) { - if len(e.Param) < EncryptSaltSize { - return nil, fmt.Errorf("invalid param length") - } - salt := e.Param[:EncryptSaltSize] - pubKey := e.Param[EncryptSaltSize:] - var err error - var secret, key []byte - if secret, err = w.ECDH(pubKey); err != nil { - return nil, err - } - if key, err = crypto.HKDF(secret, salt, []byte(HKDFInfo), HKDFKeySize); err != nil { - return nil, err - } - var blk cipher.Block - if blk, err = aes.NewCipher(key[:AES128KeySize]); err != nil { - return nil, err - } - return cipher.NewCTR(blk, key[AES128KeySize:]), nil -} - -func (e *Encrypted) Decrypt(w Wallet) ([]byte, error) { - s, err := e.Aes128CTRStream(w) - if err != nil { - return nil, err - } - b := make([]byte, len(e.CipherText)) - s.XORKeyStream(b, e.CipherText) - return b, nil -} - -func (e *Encrypted) Encrypt(w Wallet, b []byte) error { - s, err := e.Aes128CTRStream(w) - if err != nil { - return err - } - s.XORKeyStream(e.CipherText, b) - return nil -} - -func NewEncrypted(w Wallet, pubKey, b []byte) (*Encrypted, error) { - e := &Encrypted{ - Param: make([]byte, EncryptSaltSize+len(pubKey)), - CipherText: make([]byte, len(b)), - } - if _, err := io.ReadFull(rand.Reader, e.Param[:EncryptSaltSize]); err != nil { - return nil, err - } - copy(e.Param[EncryptSaltSize:], pubKey) - s, err := e.Aes128CTRStream(w) - if err != nil { - return nil, err - } - s.XORKeyStream(e.CipherText, b) - copy(e.Param[EncryptSaltSize:], w.PublicKey()) - return e, nil -} diff --git a/common/wallet/keystore.go b/common/wallet/keystore.go index 3be2f2c..c02b04c 100644 --- a/common/wallet/keystore.go +++ b/common/wallet/keystore.go @@ -16,6 +16,7 @@ import ( "github.com/icon-project/btp2/common" "github.com/icon-project/btp2/common/crypto" "github.com/icon-project/btp2/common/errors" + "github.com/icon-project/btp2/common/types" ) const ( @@ -143,7 +144,7 @@ func ReadAddressFromKeyStore(data []byte) (*common.Address, error) { return &ksData.Address, nil } -func DecryptKeyStore(data, pw []byte) (Wallet, error) { +func DecryptKeyStore(data, pw []byte) (types.Wallet, error) { ksdata, err := NewKeyStoreData(data) if err != nil { return nil, err diff --git a/common/wallet/wallet.go b/common/wallet/wallet.go index b3f3e67..b7b814e 100644 --- a/common/wallet/wallet.go +++ b/common/wallet/wallet.go @@ -5,13 +5,6 @@ import ( "github.com/icon-project/btp2/common/crypto" ) -type Wallet interface { - Address() string - Sign(data []byte) ([]byte, error) - PublicKey() []byte - ECDH(pubKey []byte) ([]byte, error) -} - type softwareWallet struct { skey *crypto.PrivateKey pkey *crypto.PublicKey @@ -21,8 +14,8 @@ func (w *softwareWallet) Address() string { return common.NewAccountAddressFromPublicKey(w.pkey).String() } -func (w *softwareWallet) Sign(data []byte) ([]byte, error) { - sig, err := crypto.NewSignature(data, w.skey) +func (w *softwareWallet) Sign(data interface{}) ([]byte, error) { + sig, err := crypto.NewSignature(data.([]byte), w.skey) if err != nil { return nil, err } @@ -33,6 +26,10 @@ func (w *softwareWallet) PublicKey() []byte { return w.pkey.SerializeCompressed() } +func (w *softwareWallet) PrivateKey() interface{} { + return w.skey.Bytes() +} + func (w *softwareWallet) ECDH(pubKey []byte) ([]byte, error) { pkey, err := crypto.ParsePublicKey(pubKey) if err != nil { diff --git a/common/wallet/wallet_evm.go b/common/wallet/wallet_evm.go index effbd65..bc37e1b 100644 --- a/common/wallet/wallet_evm.go +++ b/common/wallet/wallet_evm.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/ecies" ) type EvmWallet struct { @@ -17,17 +18,22 @@ func (w *EvmWallet) Address() string { return common.BytesToAddress(crypto.Keccak256(pubBytes[1:])[12:]).Hex() } -func (w *EvmWallet) Sign(data []byte) ([]byte, error) { - return crypto.Sign(data, w.Skey) +func (w *EvmWallet) Sign(data interface{}) ([]byte, error) { + return crypto.Sign(data.([]byte), w.Skey) } func (w *EvmWallet) PublicKey() []byte { return crypto.FromECDSAPub(w.Pkey) } +func (w *EvmWallet) PrivateKey() interface{} { + return crypto.FromECDSA(w.Skey) +} + func (w *EvmWallet) ECDH(pubKey []byte) ([]byte, error) { - //TODO: Not implemented yet - return nil, nil + pri := ecies.ImportECDSA(w.Skey) + pub := ecies.ImportECDSAPublic(w.Pkey) + return pri.GenerateShared(pub, pub.Params.KeyLen, pub.Params.KeyLen) } func NewEvmWalletFromPrivateKey(sk *ecdsa.PrivateKey) (*EvmWallet, error) { From 71cf18c0e396d62ba67824d8d57ee5514740635c Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Tue, 18 Jul 2023 14:36:58 +0900 Subject: [PATCH 03/22] Refactor relay - Add link factory - Add Database in receiver - Modify config --- chain/config.go | 29 ++- chain/ethbr/ethbrfactory.go | 89 +++++++++ chain/ethbr/factory.go | 48 ----- chain/ethbr/receiver.go | 86 +++++++-- chain/icon/bridge/bridge.go | 16 +- chain/icon/bridge/bridgefactory.go | 91 ++++++++++ chain/icon/bridge/message.go | 4 +- chain/icon/btp2/btp2.go | 100 ++++++++-- chain/icon/btp2/btpblockfactory.go | 90 +++++++++ chain/icon/client/type.go | 18 +- chain/icon/factory.go | 65 ------- chain/icon/iconfactory.go | 70 +++++++ chain/icon/sender.go | 58 +++--- cmd/relay/init.go | 13 ++ cmd/relay/main.go | 92 +++------- common/link/config.go | 32 ++++ common/link/factory.go | 155 ++++++++++++++++ common/link/link.go | 32 ++-- common/linkfactory/config.go | 26 --- common/linkfactory/linkfactory.go | 283 ----------------------------- common/relay/relay.go | 75 ++++++++ common/types/type.go | 11 +- 22 files changed, 895 insertions(+), 588 deletions(-) create mode 100644 chain/ethbr/ethbrfactory.go delete mode 100644 chain/ethbr/factory.go create mode 100644 chain/icon/bridge/bridgefactory.go create mode 100644 chain/icon/btp2/btpblockfactory.go delete mode 100644 chain/icon/factory.go create mode 100644 chain/icon/iconfactory.go create mode 100644 cmd/relay/init.go create mode 100644 common/link/config.go create mode 100644 common/link/factory.go delete mode 100644 common/linkfactory/config.go delete mode 100644 common/linkfactory/linkfactory.go create mode 100644 common/relay/relay.go diff --git a/chain/config.go b/chain/config.go index a10c751..99191e9 100644 --- a/chain/config.go +++ b/chain/config.go @@ -23,13 +23,24 @@ import ( ) type BaseConfig struct { - Address types.BtpAddress `json:"address"` - Endpoint string `json:"endpoint"` - KeyStoreData json.RawMessage `json:"key_store"` - KeyStorePass string `json:"key_password,omitempty"` - KeySecret string `json:"key_secret,omitempty"` - RelayMode string `json:"relay_mode"` //trustless, bridge - LatestResult bool `json:"latest_result"` - FilledBlockUpdate bool `json:"filled_block_update"` - Options map[string]interface{} `json:"options,omitempty"` + Address types.BtpAddress `json:"address"` + Endpoint string `json:"endpoint"` + KeyStoreData json.RawMessage `json:"key_store"` + ChainId string `json:"chain_id"` + KeyStorePass string `json:"key_password,omitempty"` + KeySecret string `json:"key_secret,omitempty"` + + Options map[string]interface{} `json:"options,omitempty"` +} + +func (b BaseConfig) GetAddress() types.BtpAddress { + return b.Address +} + +func (b BaseConfig) GetChainId() string { + return b.ChainId +} + +func (b BaseConfig) GetNetworkID() string { + return b.Address.NetworkID() } diff --git a/chain/ethbr/ethbrfactory.go b/chain/ethbr/ethbrfactory.go new file mode 100644 index 0000000..a4bd833 --- /dev/null +++ b/chain/ethbr/ethbrfactory.go @@ -0,0 +1,89 @@ +package ethbr + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" + "github.com/icon-project/btp2/common/wallet" +) + +func RegisterIconEthBr() { + link.RegisterFactory(&link.Factory{ + GetChainConfig: GetChainConfig, + CheckConfig: CheckConfig, + NewReceiver: NewReceiver, + NewSender: NewSender, + }) +} + +func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { + cfg := chain.BaseConfig{} + + jsonbody, err := json.Marshal(dict) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(jsonbody, &cfg); err != nil { + return nil, err + } + return cfg, nil +} + +func CheckConfig(cfg link.ChainConfig) bool { + baseCfg, ok := cfg.(chain.BaseConfig) + if !ok { + return false + } + + if baseCfg.ChainId == "eth_bridge" { + return true + } + + return false +} + +func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l log.Logger) (link.Receiver, error) { + src := srcCfg.(chain.BaseConfig) + + return newEthBridge(srcCfg, dstCfg.GetAddress(), src.Endpoint, l, fileCfg, src.Options) +} + +func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { + dst := dstCfg.(chain.BaseConfig) + + //TODO refactoring + w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) + if err != nil { + return nil, err + } + + return newSender(srcCfg.GetAddress(), dst, w, dst.Endpoint, dst.Options, l), nil +} + +func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) +} + +func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { + if keySecret != "" { + return os.ReadFile(keySecret) + } else { + if keyStorePass != "" { + return []byte(keyStorePass), nil + } else { + //TODO + return nil, fmt.Errorf("") + } + } +} diff --git a/chain/ethbr/factory.go b/chain/ethbr/factory.go deleted file mode 100644 index ddab654..0000000 --- a/chain/ethbr/factory.go +++ /dev/null @@ -1,48 +0,0 @@ -package ethbr - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/common/log" - "github.com/icon-project/btp2/common/types" - "github.com/icon-project/btp2/common/wallet" -) - -func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) *ethbr { - receiver := newEthBridge(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l, srcCfg.Options) - return receiver -} - -func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (types.Sender, error) { - //TODO refactoring - w, err := Wallet(cfg.KeyStorePass, cfg.KeySecret, cfg.KeyStoreData) - if err != nil { - return nil, err - } - - return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil -} - -func Wallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { - pw, err := resolvePassword(secret, passwd) - if err != nil { - return nil, err - } - return wallet.DecryptKeyStore(keyStore, pw) -} - -func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { - if keySecret != "" { - return os.ReadFile(keySecret) - } else { - if keyStorePass != "" { - return []byte(keyStorePass), nil - } else { - //TODO - return nil, fmt.Errorf("") - } - } -} diff --git a/chain/ethbr/receiver.go b/chain/ethbr/receiver.go index 680e9f0..a5f8207 100644 --- a/chain/ethbr/receiver.go +++ b/chain/ethbr/receiver.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "math/big" + "path/filepath" "sort" "unsafe" @@ -19,6 +20,8 @@ import ( "github.com/icon-project/btp2/chain/ethbr/binding" "github.com/icon-project/btp2/chain/ethbr/client" "github.com/icon-project/btp2/common/codec" + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/db" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" @@ -58,6 +61,7 @@ func newReceiveStatus(height, startSeq, lastSeq int64, rps []*client.ReceiptProo } const ( + DefaultDBType = db.GoLevelDBBackend EPOCH = 200 EventSignature = "Message(string,uint256,bytes)" EventIndexSignature = 0 @@ -66,22 +70,25 @@ const ( ) type ethbr struct { - l log.Logger - src btpTypes.BtpAddress - dst btpTypes.BtpAddress - c *client.Client - nid int64 - rsc chan interface{} - rss []*receiveStatus - rs *receiveStatus - seq int64 - startHeight int64 - opt struct { + l log.Logger + src link.ChainConfig + dst btpTypes.BtpAddress + c *client.Client + nid int64 + rsc chan interface{} + rss []*receiveStatus + rs *receiveStatus + seq int64 + startHeight int64 + receiveHeight int64 + bk db.Bucket + opt struct { StartHeight int64 } } -func newEthBridge(src, dst btpTypes.BtpAddress, endpoint string, l log.Logger, opt map[string]interface{}) *ethbr { +func newEthBridge(src link.ChainConfig, dst btpTypes.BtpAddress, endpoint string, + l log.Logger, fileCfg config.FileConfig, opt map[string]interface{}) (*ethbr, error) { c := ðbr{ src: src, dst: dst, @@ -99,7 +106,49 @@ func newEthBridge(src, dst btpTypes.BtpAddress, endpoint string, l log.Logger, o if err = json.Unmarshal(b, &c.opt); err != nil { l.Panicf("fail to unmarshal opt:%#v err:%+v", opt, err) } - return c + + bk, err := c.prepareDatabase(fileCfg) + if err != nil { + return nil, err + } + c.bk = bk + return c, nil +} + +func (e *ethbr) setHeightToDatabase() { + bytesArray := big.NewInt(e.receiveHeight).Bytes() + e.bk.Set([]byte("ReceiveHeight"), bytesArray) +} + +func (e *ethbr) prepareDatabase(fileCfg config.FileConfig) (db.Bucket, error) { + e.l.Debugln("open database", filepath.Join(fileCfg.AbsBaseDir()+e.src.GetNetworkID(), e.dst.NetworkAddress())) + database, err := db.Open(fileCfg.AbsBaseDir()+e.src.GetNetworkID(), string(DefaultDBType), e.dst.NetworkAddress()) + if err != nil { + return nil, errors.Wrap(err, "fail to open database") + } + defer func() { + if err != nil { + database.Close() + } + }() + var bk db.Bucket + if bk, err = database.GetBucket("ReceiveHeight"); err != nil { + return nil, err + } + k := []byte("ReceiveHeight") + has, err := bk.Has(k) + if err != nil { + return nil, err + } + + if has { + h, err := bk.Get(k) + if err != nil { + return nil, err + } + e.receiveHeight = new(big.Int).SetBytes(h).Int64() + } + return bk, nil } func (e *ethbr) Start(bls *btpTypes.BMCLinkStatus) (<-chan interface{}, error) { @@ -244,14 +293,14 @@ func (e *ethbr) clearReceiveStatus(bls *btpTypes.BMCLinkStatus) { func (e *ethbr) Monitoring(bls *btpTypes.BMCLinkStatus) error { var height int64 fq := ðereum.FilterQuery{ - Addresses: []common.Address{common.HexToAddress(e.src.ContractAddress())}, + Addresses: []common.Address{common.HexToAddress(e.src.GetAddress().ContractAddress())}, Topics: [][]common.Hash{ {crypto.Keccak256Hash([]byte(EventSignature))}, }, } - if e.opt.StartHeight > bls.Verifier.Height { - height = e.opt.StartHeight + if e.receiveHeight > bls.Verifier.Height { + height = e.receiveHeight } else { height = bls.Verifier.Height } @@ -280,7 +329,10 @@ func (e *ethbr) Monitoring(bls *btpTypes.BMCLinkStatus) error { return e.c.MonitorBlock(br, func(v *client.BlockNotification) error { - + e.receiveHeight = v.Height.Int64() + if v.Height.Int64()%500 == 0 { + e.setHeightToDatabase() + } if len(v.Logs) > 0 { var startSeq int64 var lastSeq int64 diff --git a/chain/icon/bridge/bridge.go b/chain/icon/bridge/bridge.go index 6ea50d0..ace1428 100644 --- a/chain/icon/bridge/bridge.go +++ b/chain/icon/bridge/bridge.go @@ -36,7 +36,7 @@ func (r *receiveStatus) ReceiptProof() *ReceiptProof { type bridge struct { l log.Logger - src types.BtpAddress + src link.ChainConfig dst types.BtpAddress c *client.Client nid int64 @@ -73,7 +73,7 @@ func newReceiveStatus(height, rxSeq int64, sn int64, msgs []string, next types.B }, nil } -func NewBridge(src, dst types.BtpAddress, endpoint string, l log.Logger) *bridge { +func newBridge(src link.ChainConfig, dst types.BtpAddress, endpoint string, l log.Logger) (*bridge, error) { c := &bridge{ src: src, dst: dst, @@ -83,12 +83,12 @@ func NewBridge(src, dst types.BtpAddress, endpoint string, l log.Logger) *bridge rs: &receiveStatus{}, } c.c = client.NewClient(endpoint, l) - return c + return c, nil } func (b *bridge) getNetworkId() error { if b.nid == 0 { - nid, err := b.c.GetBTPLinkNetworkId(b.src, b.dst) + nid, err := b.c.GetBTPLinkNetworkId(b.src.GetAddress(), b.dst) if err != nil { return err } @@ -136,7 +136,7 @@ func (b *bridge) GetHeightForSeq(seq int64) int64 { func (b *bridge) BuildBlockUpdate(bls *types.BMCLinkStatus, limit int64) ([]link.BlockUpdate, error) { bus := make([]link.BlockUpdate, 0) rs := b.nextReceiveStatus(bls) - bu := NewBlockUpdate(bls, rs.Height()) + bu := newBlockUpdate(bls, rs.Height()) bus = append(bus, bu) return bus, nil } @@ -163,14 +163,14 @@ func (b *bridge) BuildMessageProof(bls *types.BMCLinkStatus, limit int64) (link. for i := offset; i < int64(messageCnt); i++ { size := sizeOfEvent(rs.ReceiptProof().Events[i]) if limit < int64(rmSize+size) { - return NewMessageProof(bls, bls.RxSeq+i, trp) + return newMessageProof(bls, bls.RxSeq+i, trp) } trp.Events = append(trp.Events, rs.ReceiptProof().Events[i]) rmSize += size } //last event - return NewMessageProof(bls, bls.RxSeq+int64(messageCnt), trp) + return newMessageProof(bls, bls.RxSeq+int64(messageCnt), trp) } @@ -233,7 +233,7 @@ func (b *bridge) Monitoring(bls *types.BMCLinkStatus) error { } func (b *bridge) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus, scb func(conn *websocket.Conn), errCb func(*websocket.Conn, error)) error { - offset, err := b.c.GetBTPLinkOffset(b.src, b.dst) + offset, err := b.c.GetBTPLinkOffset(b.src.GetAddress(), b.dst) if err != nil { return err } diff --git a/chain/icon/bridge/bridgefactory.go b/chain/icon/bridge/bridgefactory.go new file mode 100644 index 0000000..afe6b9e --- /dev/null +++ b/chain/icon/bridge/bridgefactory.go @@ -0,0 +1,91 @@ +package bridge + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/chain/icon" + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" + "github.com/icon-project/btp2/common/wallet" +) + +func RegisterIconBridge() { + link.RegisterFactory(&link.Factory{ + GetChainConfig: GetChainConfig, + CheckConfig: CheckConfig, + NewReceiver: NewReceiver, + NewSender: NewSender, + }) +} + +func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { + cfg := chain.BaseConfig{} + + jsonbody, err := json.Marshal(dict) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(jsonbody, &cfg); err != nil { + return nil, err + } + return cfg, nil +} + +func CheckConfig(cfg link.ChainConfig) bool { + baseCfg, ok := cfg.(chain.BaseConfig) + + if !ok { + return false + } + + if baseCfg.ChainId == "icon_bridge" { + return true + } + + return false +} + +func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l log.Logger) (link.Receiver, error) { + src := srcCfg.(chain.BaseConfig) + + return newBridge(src, dstCfg.GetAddress(), src.Endpoint, l) +} + +func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { + dst := dstCfg.(chain.BaseConfig) + + //TODO refactoring + w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) + if err != nil { + return nil, err + } + + return icon.NewSender(srcCfg.GetAddress(), dst, w, dst.Endpoint, dst.Options, l), nil +} + +func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) +} + +func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { + if keySecret != "" { + return os.ReadFile(keySecret) + } else { + if keyStorePass != "" { + return []byte(keyStorePass), nil + } else { + //TODO add error message + return nil, fmt.Errorf("") + } + } +} diff --git a/chain/icon/bridge/message.go b/chain/icon/bridge/message.go index acf63be..b1236ca 100644 --- a/chain/icon/bridge/message.go +++ b/chain/icon/bridge/message.go @@ -76,7 +76,7 @@ func (c *blockProof) ProofHeight() int64 { return c.ph } -func NewBlockUpdate(bs *types.BMCLinkStatus, targetHeight int64) *blockUpdate { +func newBlockUpdate(bs *types.BMCLinkStatus, targetHeight int64) *blockUpdate { nextBls := &types.BMCLinkStatus{} nextBls.Verifier.Height = targetHeight nextBls.TxSeq = bs.TxSeq @@ -108,7 +108,7 @@ func (m *MessageProof) LastSeqNum() int64 { return m.lastSeq } -func NewMessageProof(bs *types.BMCLinkStatus, ls int64, rp *ReceiptProof) (*MessageProof, error) { +func newMessageProof(bs *types.BMCLinkStatus, ls int64, rp *ReceiptProof) (*MessageProof, error) { //update bls nextBls := &types.BMCLinkStatus{} nextBls.Verifier.Height = bs.Verifier.Height diff --git a/chain/icon/btp2/btp2.go b/chain/icon/btp2/btp2.go index d7931ab..0bc1cf7 100644 --- a/chain/icon/btp2/btp2.go +++ b/chain/icon/btp2/btp2.go @@ -3,11 +3,16 @@ package btp2 import ( "encoding/base64" "fmt" + "math/big" + "path/filepath" + "time" "github.com/gorilla/websocket" "github.com/icon-project/btp2/chain/icon/client" "github.com/icon-project/btp2/common/codec" + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/db" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/intconv" "github.com/icon-project/btp2/common/link" @@ -16,6 +21,11 @@ import ( "github.com/icon-project/btp2/common/types" ) +const ( + DefaultDBType = db.GoLevelDBBackend + DefaultProgressInterval = 5 * time.Minute //5min +) + type receiveStatus struct { height int64 seq int64 @@ -38,19 +48,21 @@ func newReceiveStatus(height, seq int64) (*receiveStatus, error) { } type btp2 struct { - l log.Logger - src types.BtpAddress - dst types.BtpAddress - c *client.Client - nid int64 - rsc chan interface{} - rss []*receiveStatus - rs *receiveStatus - seq int64 - startHeight int64 + l log.Logger + src link.ChainConfig + dst types.BtpAddress + c *client.Client + receiveHeight int64 + bk db.Bucket + nid int64 + rsc chan interface{} + rss []*receiveStatus + rs *receiveStatus + seq int64 + startHeight int64 } -func NewBTP2(src, dst types.BtpAddress, endpoint string, l log.Logger) *btp2 { +func newBTP2(src link.ChainConfig, dst types.BtpAddress, endpoint string, fileCfg config.FileConfig, l log.Logger) (*btp2, error) { c := &btp2{ src: src, dst: dst, @@ -60,12 +72,53 @@ func NewBTP2(src, dst types.BtpAddress, endpoint string, l log.Logger) *btp2 { rs: &receiveStatus{}, } c.c = client.NewClient(endpoint, l) - return c + bk, err := c.prepareDatabase(fileCfg) + if err != nil { + return nil, err + } + c.bk = bk + return c, nil +} + +func (b *btp2) setHeightToDatabase() { + bytesArray := big.NewInt(b.receiveHeight).Bytes() + b.bk.Set([]byte("ReceiveHeight"), bytesArray) +} + +func (b *btp2) prepareDatabase(fileCfg config.FileConfig) (db.Bucket, error) { + b.l.Debugln("open database", filepath.Join(fileCfg.AbsBaseDir()+b.src.GetNetworkID(), b.dst.NetworkAddress())) + database, err := db.Open(fileCfg.AbsBaseDir()+b.src.GetNetworkID(), string(DefaultDBType), b.dst.NetworkAddress()) + if err != nil { + return nil, errors.Wrap(err, "fail to open database") + } + defer func() { + if err != nil { + database.Close() + } + }() + var bk db.Bucket + if bk, err = database.GetBucket("ReceiveHeight"); err != nil { + return nil, err + } + k := []byte("ReceiveHeight") + has, err := bk.Has(k) + if err != nil { + return nil, err + } + + if has { + h, err := bk.Get(k) + if err != nil { + return nil, err + } + b.receiveHeight = new(big.Int).SetBytes(h).Int64() + } + return bk, nil } func (b *btp2) getNetworkId() error { if b.nid == 0 { - nid, err := b.c.GetBTPLinkNetworkId(b.src, b.dst) + nid, err := b.c.GetBTPLinkNetworkId(b.src.GetAddress(), b.dst) if err != nil { return err } @@ -280,14 +333,23 @@ func (b *btp2) getMessage(height int64) (*mbt.MerkleBinaryTree, error) { } func (b *btp2) Monitoring(bls *types.BMCLinkStatus) error { + var height int64 + if bls.Verifier.Height < 1 { return fmt.Errorf("cannot catchup from zero height") } + if b.receiveHeight > bls.Verifier.Height { + height = b.receiveHeight + } else { + height = bls.Verifier.Height + } + req := &client.BTPRequest{ - Height: client.NewHexInt(bls.Verifier.Height + 1), - NetworkID: client.NewHexInt(b.nid), - ProofFlag: client.NewHexInt(0), + Height: client.NewHexInt(height + 1), + NetworkID: client.NewHexInt(b.nid), + ProofFlag: client.NewHexInt(0), + ProgressInterval: client.NewHexInt(int64(DefaultProgressInterval)), } onErr := func(conn *websocket.Conn, err error) { @@ -334,6 +396,12 @@ func (b *btp2) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus return err } + if v.Progress.Value != 0 { + b.receiveHeight = v.Progress.Value + b.setHeightToDatabase() + return nil + } + bh := &client.BTPBlockHeader{} if _, err = codec.RLP.UnmarshalFromBytes(h, bh); err != nil { return err diff --git a/chain/icon/btp2/btpblockfactory.go b/chain/icon/btp2/btpblockfactory.go new file mode 100644 index 0000000..556b2ad --- /dev/null +++ b/chain/icon/btp2/btpblockfactory.go @@ -0,0 +1,90 @@ +package btp2 + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/chain/icon" + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" + "github.com/icon-project/btp2/common/wallet" +) + +func RegisterIconBtp2() { + link.RegisterFactory(&link.Factory{ + GetChainConfig: GetChainConfig, + CheckConfig: CheckConfig, + NewReceiver: NewReceiver, + NewSender: NewSender, + }) +} + +func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { + cfg := chain.BaseConfig{} + + jsonbody, err := json.Marshal(dict) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(jsonbody, &cfg); err != nil { + return nil, err + } + return cfg, nil +} + +func CheckConfig(cfg link.ChainConfig) bool { + baseCfg, ok := cfg.(chain.BaseConfig) + if !ok { + return false + } + + if baseCfg.ChainId == "icon_btpBlock" { + return true + } + + return false +} + +func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l log.Logger) (link.Receiver, error) { + src := srcCfg.(chain.BaseConfig) + + return newBTP2(src, dstCfg.GetAddress(), src.Endpoint, fileCfg, l) +} + +func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { + dst := dstCfg.(chain.BaseConfig) + + //TODO refactoring + w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) + if err != nil { + return nil, err + } + + return icon.NewSender(srcCfg.GetAddress(), dst, w, dst.Endpoint, dst.Options, l), nil +} + +func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) +} + +func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { + if keySecret != "" { + return os.ReadFile(keySecret) + } else { + if keyStorePass != "" { + return []byte(keyStorePass), nil + } else { + //TODO add error message + return nil, fmt.Errorf("") + } + } +} diff --git a/chain/icon/client/type.go b/chain/icon/client/type.go index 7ac8243..59cee82 100644 --- a/chain/icon/client/type.go +++ b/chain/icon/client/type.go @@ -22,6 +22,7 @@ import ( "fmt" "math/big" + "github.com/icon-project/btp2/common" "github.com/icon-project/btp2/common/intconv" "github.com/icon-project/btp2/common/jsonrpc" "github.com/icon-project/btp2/common/types" @@ -278,6 +279,10 @@ type EventNotification struct { type WSEvent string +type ProgressNotification struct { + Progress common.HexInt64 `json:"progress"` +} + const ( WSEventInit WSEvent = "WSEventInit" ) @@ -425,14 +430,16 @@ type Block struct { } type BTPNotification struct { - Header string `json:"header"` - Proof string `json:"proof,omitempty"` + Header string `json:"header"` + Proof string `json:"proof,omitempty"` + Progress common.HexInt64 `json:"progress"` } type BTPRequest struct { - Height HexInt `json:"height"` - NetworkID HexInt `json:"networkID"` - ProofFlag HexInt `json:"proofFlag"` + Height HexInt `json:"height"` + NetworkID HexInt `json:"networkID"` + ProofFlag HexInt `json:"proofFlag"` + ProgressInterval HexInt `json:"progressInterval"` } type BTPNetworkInfo struct { @@ -466,6 +473,7 @@ type BTPBlockHeader struct { MessagesRoot []byte NextProofContext []byte } + type Dir int const ( diff --git a/chain/icon/factory.go b/chain/icon/factory.go deleted file mode 100644 index dd79290..0000000 --- a/chain/icon/factory.go +++ /dev/null @@ -1,65 +0,0 @@ -package icon - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/chain/icon/bridge" - "github.com/icon-project/btp2/chain/icon/btp2" - "github.com/icon-project/btp2/common/link" - "github.com/icon-project/btp2/common/log" - "github.com/icon-project/btp2/common/types" - "github.com/icon-project/btp2/common/wallet" -) - -const ( - BRIDGE = "bridge" - TRUSTLESS = "trustless" -) - -func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { - var receiver link.Receiver - - switch srcCfg.RelayMode { - case BRIDGE: - receiver = bridge.NewBridge(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) - case TRUSTLESS: - receiver = btp2.NewBTP2(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) - default: - l.Panicf("Not supported for relay mod:%s", srcCfg.RelayMode) - } - return receiver -} - -func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (types.Sender, error) { - //TODO refactoring - w, err := Wallet(cfg.KeyStorePass, cfg.KeySecret, cfg.KeyStoreData) - if err != nil { - return nil, err - } - - return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil -} - -func Wallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { - pw, err := resolvePassword(secret, passwd) - if err != nil { - return nil, err - } - return wallet.DecryptKeyStore(keyStore, pw) -} - -func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { - if keySecret != "" { - return os.ReadFile(keySecret) - } else { - if keyStorePass != "" { - return []byte(keyStorePass), nil - } else { - //TODO add error message - return nil, fmt.Errorf("") - } - } -} diff --git a/chain/icon/iconfactory.go b/chain/icon/iconfactory.go new file mode 100644 index 0000000..9c4edce --- /dev/null +++ b/chain/icon/iconfactory.go @@ -0,0 +1,70 @@ +package icon + +// +//import ( +// "encoding/json" +// "fmt" +// "os" +// +// "github.com/icon-project/btp2/chain" +// "github.com/icon-project/btp2/chain/icon/bridge" +// "github.com/icon-project/btp2/chain/icon/btp2" +// "github.com/icon-project/btp2/common/link" +// "github.com/icon-project/btp2/common/log" +// "github.com/icon-project/btp2/common/types" +// "github.com/icon-project/btp2/common/wallet" +//) +// +//const ( +// BRIDGE = "bridge" +// TRUSTLESS = "trustless" +//) +// +//// func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { +//func NewReceiver(srcCfg, dstCfg interface{}, l log.Logger) link.Receiver { +// src := srcCfg.(chain.BaseConfig) +// dst := dstCfg.(chain.BaseConfig) +// var receiver link.Receiver +// +// src.Name +// switch srcCfg.RelayMode { +// case BRIDGE: +// receiver = bridge.NewBridge(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) +// case TRUSTLESS: +// receiver = btp2.NewBTP2(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) +// default: +// l.Panicf("Not supported for relay mod:%s", srcCfg.RelayMode) +// } +// return receiver +//} +// +//func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (types.Sender, error) { +// //TODO refactoring +// w, err := Wallet(cfg.KeyStorePass, cfg.KeySecret, cfg.KeyStoreData) +// if err != nil { +// return nil, err +// } +// +// return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil +//} +// +//func Wallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { +// pw, err := resolvePassword(secret, passwd) +// if err != nil { +// return nil, err +// } +// return wallet.DecryptKeyStore(keyStore, pw) +//} +// +//func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { +// if keySecret != "" { +// return os.ReadFile(keySecret) +// } else { +// if keyStorePass != "" { +// return []byte(keyStorePass), nil +// } else { +// //TODO add error message +// return nil, fmt.Errorf("") +// } +// } +//} diff --git a/chain/icon/sender.go b/chain/icon/sender.go index 0d7ff10..eaa268d 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -25,9 +25,11 @@ import ( "strconv" "time" + "github.com/icon-project/btp2/chain" "github.com/icon-project/btp2/chain/icon/client" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/jsonrpc" + "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" ) @@ -89,12 +91,12 @@ func (q *Queue) len() int { } type sender struct { - c *client.Client - src types.BtpAddress - dst types.BtpAddress - w types.Wallet - l log.Logger - opt struct { + c *client.Client + srcAddr types.BtpAddress + dstCfg chain.BaseConfig + w types.Wallet + l log.Logger + opt struct { StepLimit int64 } rr chan *types.RelayResult @@ -102,14 +104,14 @@ type sender struct { queue *Queue } -func newSender(src, dst types.BtpAddress, w types.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) types.Sender { +func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, w types.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) types.Sender { s := &sender{ - src: src, - dst: dst, - w: w, - l: l, - rr: make(chan *types.RelayResult), - queue: NewQueue(), + srcAddr: srcAddr, + dstCfg: dstCfg.(chain.BaseConfig), + w: w, + l: l, + rr: make(chan *types.RelayResult), + queue: NewQueue(), } b, err := json.Marshal(opt) if err != nil { @@ -138,7 +140,7 @@ func (s *sender) Relay(rm types.RelayMessage) (string, error) { if MaxQueueSize <= s.queue.len() { return "", errors.InvalidStateError.New("pending queue full") } - s.l.Debugf("_relay src address:%s, rm id:%d, rm msg:%s", s.src.String(), rm.Id(), hex.EncodeToString(rm.Bytes()[:])) + s.l.Debugf("_relay src address:%s, rm id:%d, rm msg:%s", s.srcAddr.String(), rm.Id(), hex.EncodeToString(rm.Bytes()[:])) thp, err := s._relay(rm) if err != nil { @@ -156,17 +158,13 @@ func (s *sender) Relay(rm types.RelayMessage) (string, error) { return rm.Id(), nil } -func (s *sender) GetMarginForLimit() int64 { - return 0 -} - func (s *sender) _relay(rm types.RelayMessage) (*client.TransactionHashParam, error) { msg := rm.Bytes() idx := len(msg) / txSizeLimit if idx == 0 { rmp := &client.BMCRelayMethodParams{ - Prev: s.src.String(), + Prev: s.srcAddr.String(), Messages: base64.URLEncoding.EncodeToString(msg), } return s.sendTransaction(s.newTransactionParam(client.BMCRelayMethod, rmp)) @@ -213,19 +211,27 @@ func (s *sender) result(id string, txh *client.TransactionHashParam) { } } -func (s *sender) TxSizeLimit() int { - return txSizeLimit +// TODO config setting +func (s *sender) GetPreference() types.Preference { + p := types.Preference{ + TxSizeLimit: int64(txSizeLimit), + MarginForLimit: int64(0), + LatestResult: false, + FilledBlockUpdate: false, + } + + return p } func (s *sender) GetStatus() (*types.BMCLinkStatus, error) { p := &client.CallParam{ FromAddress: client.Address(s.w.Address()), - ToAddress: client.Address(s.dst.Account()), + ToAddress: client.Address(s.dstCfg.Address.Account()), DataType: "call", Data: client.CallData{ Method: client.BMCGetStatusMethod, Params: client.BMCStatusParams{ - Target: s.src.String(), + Target: s.srcAddr.String(), }, }, } @@ -254,8 +260,8 @@ func (s *sender) newTransactionParam(method string, params interface{}) *client. p := &client.TransactionParam{ Version: client.NewHexInt(client.JsonrpcApiVersion), FromAddress: client.Address(s.w.Address()), - ToAddress: client.Address(s.dst.Account()), - NetworkID: client.HexInt(s.dst.NetworkID()), + ToAddress: client.Address(s.dstCfg.Address.Account()), + NetworkID: client.HexInt(s.dstCfg.Address.NetworkID()), StepLimit: client.NewHexInt(s.opt.StepLimit), //TODO stepLimit estimate DataType: "call", Data: &client.CallData{ @@ -268,7 +274,7 @@ func (s *sender) newTransactionParam(method string, params interface{}) *client. func (s *sender) sendFragment(msg []byte, idx int) (*client.TransactionHashParam, error) { fmp := &client.BMCFragmentMethodParams{ - Prev: s.src.String(), + Prev: s.srcAddr.String(), Messages: base64.URLEncoding.EncodeToString(msg), Index: client.NewHexInt(int64(idx)), } diff --git a/cmd/relay/init.go b/cmd/relay/init.go new file mode 100644 index 0000000..1739c0b --- /dev/null +++ b/cmd/relay/init.go @@ -0,0 +1,13 @@ +package main + +import ( + "github.com/icon-project/btp2/chain/ethbr" + "github.com/icon-project/btp2/chain/icon/bridge" + "github.com/icon-project/btp2/chain/icon/btp2" +) + +func init() { + bridge.RegisterIconBridge() + btp2.RegisterIconBtp2() + ethbr.RegisterIconEthBr() +} diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 3c01374..8992d0e 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -25,8 +25,9 @@ import ( "github.com/spf13/cobra" "github.com/icon-project/btp2/common/cli" - "github.com/icon-project/btp2/common/linkfactory" + "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/relay" ) var ( @@ -47,7 +48,7 @@ var logoLines = []string{ func main() { rootCmd, rootVc := cli.NewCommand(nil, nil, "relay", "BTP Relay CLI") - cfg := &linkfactory.Config{} + cfg := &link.Config{} rootCmd.Long = "Command Line Interface of Relay for Blockchain Transmission Protocol" cli.SetEnvKeyReplacer(rootVc, strings.NewReplacer(".", "_")) //rootVc.Debug() @@ -88,55 +89,31 @@ func main() { return nil } rootPFlags := rootCmd.PersistentFlags() - rootPFlags.String("src.address", "", "BTP Address of source blockchain (PROTOCOL://NID.BLOCKCHAIN/BMC)") - rootPFlags.String("src.endpoint", "", "Endpoint of source blockchain") - rootPFlags.StringToString("src.options", nil, "Options, comma-separated 'key=value'") - rootPFlags.String("src.key_store", "", "Source keyStore") - rootPFlags.String("src.key_password", "", "Source password of keyStore") - rootPFlags.String("src.key_secret", "", "Source Secret(password) file for keyStore") - rootPFlags.String("src.relay_mode", "trustless", "Relay Mode") - rootPFlags.Bool("src.latest_result", false, "Sends relay messages regardless of final status reception.") - rootPFlags.Bool("src.filled_block_update", false, "Create relayMessage for all data received from the source network") - - rootPFlags.String("dst.address", "", "BTP Address of destination blockchain (PROTOCOL://NID.BLOCKCHAIN/BMC)") - rootPFlags.String("dst.endpoint", "", "Endpoint of destination blockchain") - rootPFlags.StringToString("dst.options", nil, "Options, comma-separated 'key=value'") - rootPFlags.String("dst.key_store", "", "Destination keyStore") - rootPFlags.String("dst.key_password", "", "Destination password of keyStore") - rootPFlags.String("dst.key_secret", "", "Destination Secret(password) file for keyStore") - rootPFlags.String("dst.relay_mode", "trustless", "Relay Mode") - rootPFlags.Bool("dst.latest_result", false, "Sends relay messages regardless of final status reception.") - rootPFlags.Bool("dst.filled_block_update", false, "Create relayMessage for all data received from the source network") - - rootPFlags.String("direction", "both", "relay network direction ( both, front, reverse)") - rootPFlags.Bool("maxSizeTx", false, "Send when the maximum transaction size is reached") - - rootPFlags.Int64("offset", 0, "Offset of MTA") - - // - rootPFlags.String("base_dir", "", "Base directory for data") + rootPFlags.StringP("config", "c", "", "Parsing configuration file") - // - rootPFlags.String("log_level", "debug", "Global log level (trace,debug,info,warn,error,fatal,panic)") - rootPFlags.String("console_level", "trace", "Console log level (trace,debug,info,warn,error,fatal,panic)") - // - rootPFlags.String("log_forwarder.vendor", "", "LogForwarder vendor (fluentd,logstash)") - rootPFlags.String("log_forwarder.address", "", "LogForwarder address") - rootPFlags.String("log_forwarder.level", "info", "LogForwarder level") - rootPFlags.String("log_forwarder.name", "", "LogForwarder name") - rootPFlags.StringToString("log_forwarder.options", nil, "LogForwarder options, comma-separated 'key=value'") - // - rootPFlags.String("log_writer.filename", "", "Log file name (rotated files resides in same directory)") - rootPFlags.Int("log_writer.maxsize", 100, "Maximum log file size in MiB") - rootPFlags.Int("log_writer.maxage", 0, "Maximum age of log file in day") - rootPFlags.Int("log_writer.maxbackups", 0, "Maximum number of backups") - rootPFlags.Bool("log_writer.localtime", false, "Use localtime on rotated log file instead of UTC") - rootPFlags.Bool("log_writer.compress", false, "Use gzip on rotated log file") + + //Chains Config + rootPFlags.StringToString("chains_config.src", nil, "Source chain config") + rootPFlags.StringToString("chains_config.dst", nil, "Destination chain config") + + //RelayConfig + rootPFlags.String("relay_config.direction", "both", "relay network direction ( both, front, reverse)") + rootPFlags.String("relay_config.base_dir", "", "Base directory for data") + rootPFlags.String("relay_config.log_level", "debug", "Global log level (trace,debug,info,warn,error,fatal,panic)") + rootPFlags.String("relay_config.console_level", "trace", "Console log level (trace,debug,info,warn,error,fatal,panic)") + rootPFlags.String("relay_config.log_forwarder.vendor", "", "LogForwarder vendor (fluentd,logstash)") + rootPFlags.String("relay_config.log_forwarder.address", "", "LogForwarder address") + rootPFlags.String("relay_config.log_forwarder.level", "info", "LogForwarder level") + rootPFlags.String("relay_config.log_forwarder.name", "", "LogForwarder name") + rootPFlags.StringToString("relay_config.log_forwarder.options", nil, "LogForwarder options, comma-separated 'key=value'") + rootPFlags.String("relay_config.log_writer.filename", "", "Log file name (rotated files resides in same directory)") + rootPFlags.Int("relay_config.log_writer.maxsize", 100, "Maximum log file size in MiB") + rootPFlags.Int("relay_config.log_writer.maxage", 0, "Maximum age of log file in day") + rootPFlags.Int("relay_config.log_writer.maxbackups", 0, "Maximum number of backups") + rootPFlags.Bool("relay_config.log_writer.localtime", false, "Use localtime on rotated log file instead of UTC") + rootPFlags.Bool("relay_config.log_writer.compress", false, "Use gzip on rotated log file") cli.BindPFlags(rootVc, rootPFlags) - err := cli.MarkAnnotationCustom(rootPFlags, "src.address", "dst.address", "src.endpoint", "dst.endpoint") - if err != nil { - return - } + saveCmd := &cobra.Command{ Use: "save [file]", Short: "Save configuration", @@ -154,17 +131,6 @@ func main() { return err } cmd.Println("Save configuration to", saveFilePath) - if saveSrcKeyStore, _ := cmd.Flags().GetString("save_src_key_store"); saveSrcKeyStore != "" { - if err := cli.JsonPrettySaveFile(saveSrcKeyStore, 0600, cfg.Src.KeyStoreData); err != nil { - return err - } - } - - if saveDstKeyStore, _ := cmd.Flags().GetString("save_dst_key_store"); saveDstKeyStore != "" { - if err := cli.JsonPrettySaveFile(saveDstKeyStore, 0600, cfg.Dst.KeyStoreData); err != nil { - return err - } - } return nil }, } @@ -186,12 +152,12 @@ func main() { modLevels, _ := cmd.Flags().GetStringToString("mod_level") - lf, err := linkfactory.NewLinkFactory(cfg, modLevels) + relay, err := relay.NewRelay(cfg, modLevels) if err != nil { return err } - - return lf.Start() + + return relay.Start() }, } rootCmd.AddCommand(startCmd) diff --git a/common/link/config.go b/common/link/config.go new file mode 100644 index 0000000..941d9af --- /dev/null +++ b/common/link/config.go @@ -0,0 +1,32 @@ +package link + +import ( + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" +) + +type RelayConfig struct { + Direction string `json:"direction"` + config.FileConfig `json:",squash"` //instead of `mapstructure:",squash"` + LogLevel string `json:"log_level"` + ConsoleLevel string `json:"console_level"` + LogForwarder *log.ForwarderConfig `json:"log_forwarder,omitempty"` + LogWriter *log.WriterConfig `json:"log_writer,omitempty"` +} + +type ChainConfig interface { + GetAddress() types.BtpAddress + GetChainId() string + GetNetworkID() string +} + +type ChainsConfigs struct { + Src map[string]interface{} `json:"src"` + Dst map[string]interface{} `json:"dst"` +} + +type Config struct { + RelayConfig `json:"relay_config"` + ChainsConfigs `json:"chains_config"` //instead of `mapstructure:",squash"` +} diff --git a/common/link/factory.go b/common/link/factory.go new file mode 100644 index 0000000..dd0b0e3 --- /dev/null +++ b/common/link/factory.go @@ -0,0 +1,155 @@ +package link + +import ( + "fmt" + stdlog "log" + + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/log" + "github.com/icon-project/btp2/common/types" +) + +type Factory struct { + CreateChainConfig func() map[string]interface{} + GetChainConfig func(dict map[string]interface{}) (ChainConfig, error) + CheckConfig func(cfg ChainConfig) bool + NewReceiver func(srcCfg, dstCfg ChainConfig, fileCfg config.FileConfig, l log.Logger) (Receiver, error) + NewSender func(srcCfg, dstCfg ChainConfig, l log.Logger) (types.Sender, error) +} + +var factories []*Factory + +func RegisterFactory(f *Factory) { + if f != nil { + factories = append(factories, f) + } +} + +// TODO rename / new go file?? +func NewLinkFactory(srcCfg, dstCfg map[string]interface{}, relayCfg RelayConfig, modLevels map[string]string) (types.Link, types.Sender, error) { + var err error + + var srcChainCfg ChainConfig + var dstChainCfg ChainConfig + + var srcFactory *Factory + var dstFactory *Factory + + //Receiver + for _, factory := range factories { + srcChainCfg, err = factory.GetChainConfig(srcCfg) + if err != nil { + return nil, nil, err + } + if factory.CheckConfig(srcChainCfg) { + srcFactory = factory + break + } + } + + if srcChainCfg == nil { + //TODO error message + return nil, nil, fmt.Errorf("") + } + + //Sender + for _, factory := range factories { + dstChainCfg, err = factory.GetChainConfig(dstCfg) + if err != nil { + return nil, nil, err + } + if factory.CheckConfig(dstChainCfg) { + dstFactory = factory + break + } + } + + if dstChainCfg == nil { + //TODO error message + return nil, nil, fmt.Errorf("") + } + + logger := setLogger(srcChainCfg, relayCfg, modLevels) + logger.Debugln(relayCfg.FileConfig.FilePath, relayCfg.FileConfig.BaseDir) + + //new receiver + r, err := srcFactory.NewReceiver(srcChainCfg, dstChainCfg, relayCfg.FileConfig, logger) + if err != nil { + return nil, nil, err + } + + //new sender + s, err := dstFactory.NewSender(srcChainCfg, dstChainCfg, logger) + if err != nil { + return nil, nil, err + } + + l := NewLink(srcChainCfg, dstChainCfg, r, logger) + return l, s, nil +} + +func Start(link types.Link, sender types.Sender, errCh chan error) error { + go func() { + err := link.Start(sender) + select { + case errCh <- err: + default: + } + }() + + return nil +} + +func setLogger(srcCfg ChainConfig, lc RelayConfig, modLevels map[string]string) log.Logger { + l := log.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", srcCfg.GetNetworkID())}) + log.SetGlobalLogger(l) + stdlog.SetOutput(l.WriterLevel(log.WarnLevel)) + if lc.LogWriter != nil { + if lc.LogWriter.Filename == "" { + log.Debugln("LogWriterConfig filename is empty string, will be ignore") + } else { + var lwCfg log.WriterConfig + lwCfg = *lc.LogWriter + lwCfg.Filename = lc.ResolveAbsolute(lwCfg.Filename) + w, err := log.NewWriter(&lwCfg) + if err != nil { + log.Panicf("Fail to make writer err=%+v", err) + } + err = l.SetFileWriter(w) + if err != nil { + log.Panicf("Fail to set file l err=%+v", err) + } + } + } + + if lv, err := log.ParseLevel(lc.LogLevel); err != nil { + log.Panicf("Invalid log_level=%s", lc.LogLevel) + } else { + l.SetLevel(lv) + } + if lv, err := log.ParseLevel(lc.ConsoleLevel); err != nil { + log.Panicf("Invalid console_level=%s", lc.ConsoleLevel) + } else { + l.SetConsoleLevel(lv) + } + + for mod, lvStr := range modLevels { + if lv, err := log.ParseLevel(lvStr); err != nil { + log.Panicf("Invalid mod_level mod=%s level=%s", mod, lvStr) + } else { + l.SetModuleLevel(mod, lv) + } + } + + if lc.LogForwarder != nil { + if lc.LogForwarder.Vendor == "" && lc.LogForwarder.Address == "" { + log.Debugln("LogForwarderConfig vendor and address is empty string, will be ignore") + } else { + if err := log.AddForwarder(lc.LogForwarder); err != nil { + log.Fatalf("Invalid log_forwarder err:%+v", err) + } + } + } + + return l +} diff --git a/common/link/link.go b/common/link/link.go index 4b105fc..131cb7e 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -4,7 +4,6 @@ import ( "strconv" "sync" - "github.com/icon-project/btp2/chain" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" @@ -20,7 +19,6 @@ const ( type relayMessage struct { id string bls *types.BMCLinkStatus - bpHeight int64 message []byte rmis []RelayMessageItem sendingStatus bool @@ -42,10 +40,6 @@ func (r *relayMessage) BMCLinkStatus() *types.BMCLinkStatus { return r.bls } -func (r *relayMessage) BpHeight() int64 { - return r.bpHeight -} - func (r *relayMessage) RelayMessageItems() []RelayMessageItem { return r.rmis } @@ -65,14 +59,15 @@ type Link struct { rss []ReceiveStatus rmi *relayMessageItem limitSize int64 - srcCfg chain.BaseConfig - dstCfg chain.BaseConfig + srcCfg ChainConfig + dstCfg ChainConfig bls *types.BMCLinkStatus blsChannel chan *types.BMCLinkStatus relayState RelayState + p types.Preference } -func NewLink(srcCfg, dstCfg chain.BaseConfig, r Receiver, l log.Logger) types.Link { +func NewLink(srcCfg, dstCfg ChainConfig, r Receiver, l log.Logger) types.Link { link := &Link{ l: l, srcCfg: srcCfg, @@ -93,6 +88,8 @@ func NewLink(srcCfg, dstCfg chain.BaseConfig, r Receiver, l log.Logger) types.Li func (l *Link) Start(sender types.Sender) error { l.s = sender + l.p = sender.GetPreference() + errCh := make(chan error) if err := l.senderChannel(errCh); err != nil { return err @@ -172,7 +169,7 @@ func (l *Link) receiverChannel(errCh chan error) error { } func (l *Link) senderChannel(errCh chan error) error { - l.limitSize = int64(l.s.TxSizeLimit()) - l.s.GetMarginForLimit() + l.limitSize = l.p.TxSizeLimit - l.p.MarginForLimit rcc, err := l.s.Start() if err != nil { return err @@ -218,7 +215,7 @@ func (l *Link) buildRelayMessage() error { } if mpLen == 0 { - if l.srcCfg.FilledBlockUpdate == true { + if l.p.FilledBlockUpdate == true { if l.isOverLimit(l.rmi.size) { if err = l.appendRelayMessage(); err != nil { return err @@ -268,11 +265,10 @@ func (l *Link) appendRelayMessage() error { } rm := &relayMessage{ - id: l.srcCfg.Address.NetworkID() + "_" + strconv.FormatInt(l.bls.Verifier.Height, 16) + "_" + strconv.FormatInt(l.bls.RxSeq, 16), - bls: &types.BMCLinkStatus{}, - bpHeight: l.r.GetHeightForSeq(l.bls.RxSeq), - message: m, - rmis: rmi, + id: l.srcCfg.GetNetworkID() + "_" + strconv.FormatInt(l.bls.Verifier.Height, 16) + "_" + strconv.FormatInt(l.bls.RxSeq, 16), + bls: &types.BMCLinkStatus{}, + message: m, + rmis: rmi, } rm.bls.TxSeq = l.bls.TxSeq @@ -492,7 +488,7 @@ func (l *Link) updateBlockProof(id string) error { } func (l *Link) isOverLimit(size int64) bool { - if int64(l.s.TxSizeLimit()) < size { + if l.p.TxSizeLimit < size { return true } return false @@ -531,7 +527,7 @@ func (l *Link) result(rr *types.RelayResult) error { if rm != nil { switch rr.Err { case errors.SUCCESS: - if l.dstCfg.LatestResult == true { + if l.p.LatestResult == true { l.successRelayMessage(rr.Id) } else { if rr.Finalized == true { diff --git a/common/linkfactory/config.go b/common/linkfactory/config.go deleted file mode 100644 index 2fc3f46..0000000 --- a/common/linkfactory/config.go +++ /dev/null @@ -1,26 +0,0 @@ -package linkfactory - -import ( - "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/common/config" - "github.com/icon-project/btp2/common/log" -) - -type LinkConfig struct { - config.FileConfig `json:",squash"` //instead of `mapstructure:",squash"` - Src chain.BaseConfig `json:"src"` - Dst chain.BaseConfig `json:"dst"` - Direction string `json:"direction"` //front, reverse, both -} - -type LogConfig struct { - LogLevel string `json:"log_level"` - ConsoleLevel string `json:"console_level"` - LogForwarder *log.ForwarderConfig `json:"log_forwarder,omitempty"` - LogWriter *log.WriterConfig `json:"log_writer,omitempty"` -} - -type Config struct { - LinkConfig `json:",squash"` //instead of `mapstructure:",squash"` - LogConfig `json:",squash"` //instead of `mapstructure:",squash"` -} diff --git a/common/linkfactory/linkfactory.go b/common/linkfactory/linkfactory.go deleted file mode 100644 index cf46b88..0000000 --- a/common/linkfactory/linkfactory.go +++ /dev/null @@ -1,283 +0,0 @@ -package linkfactory - -import ( - "fmt" - stdlog "log" - "path" - - "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/chain/ethbr" - "github.com/icon-project/btp2/chain/icon" - "github.com/icon-project/btp2/common/config" - "github.com/icon-project/btp2/common/link" - "github.com/icon-project/btp2/common/log" - "github.com/icon-project/btp2/common/types" -) - -const ( - BothDirection = "both" - FrontDirection = "front" - ReverseDirection = "reverse" - - ICON = "icon" - ETH = "eth" - ETH2 = "eth2" - BSC = "bsc" - HARDHAT = "hardhat" -) - -type LinkInfo struct { - link types.Link - l log.Logger -} - -func (l *LinkInfo) GetLogger() log.Logger { - return l.l -} - -func (l *LinkInfo) Start(sender types.Sender, errCh chan error) error { - go func() { - err := l.link.Start(sender) - select { - case errCh <- err: - default: - } - }() - - return nil -} - -func (l *LinkInfo) Stop() { - l.link.Stop() -} - -func NewLinkInfo(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) (*LinkInfo, error) { - var lk types.Link - l := setLogger(srcCfg, lc, fc, modLevels) - l.Debugln(fc.FilePath, fc.BaseDir) - if fc.BaseDir == "" { - fc.BaseDir = path.Join(".", ".relay", srcCfg.Address.NetworkAddress()) - } - - r := newReceiver(srcCfg, dstCfg, l) - lk = link.NewLink(srcCfg, dstCfg, r, l) - linkInfo := &LinkInfo{ - link: lk, - l: l, - } - return linkInfo, nil -} - -//func (l *LinkFactory) Start(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig) error { -// linkErrCh := make(chan error) -// go func() { -// s, err := NewSender(srcCfg, dstCfg, l.l) -// if err != nil { -// linkErrCh <- err -// } -// -// err = l.link.Start(s) -// if err != nil { -// linkErrCh <- err -// } -// select { -// case linkErrCh <- err: -// default: -// } -// }() -// -// return nil -//} - -type LinkFactory struct { - linkInfos []*LinkInfo - senders []types.Sender -} - -func (l *LinkFactory) Start() error { - linkErrCh := make(chan error) - - for i, linkInfo := range l.linkInfos { - if err := linkInfo.Start(l.senders[i], linkErrCh); err != nil { - return err - } - } - - for { - select { - case err := <-linkErrCh: - if err != nil { - return err - } - } - } -} - -func (l *LinkFactory) Stop() { - for i, linkInfo := range l.linkInfos { - linkInfo.Stop() - l.senders[i].Stop() - } -} - -func NewLinkFactory(cfg *Config, modLevels map[string]string) (*LinkFactory, error) { - lf := &LinkFactory{ - linkInfos: make([]*LinkInfo, 0), - senders: make([]types.Sender, 0), - } - - switch cfg.Direction { - case FrontDirection: - linkInfo, err := NewLinkInfo(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) - if err != nil { - return nil, err - } - sender, err := NewSender(cfg.Src, cfg.Dst, linkInfo.GetLogger()) - if err != nil { - return nil, err - } - lf.linkInfos = append(lf.linkInfos, linkInfo) - lf.senders = append(lf.senders, sender) - case ReverseDirection: - linkInfo, err := NewLinkInfo(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) - if err != nil { - return nil, err - } - sender, err := NewSender(cfg.Dst, cfg.Src, linkInfo.GetLogger()) - if err != nil { - return nil, err - } - lf.linkInfos = append(lf.linkInfos, linkInfo) - lf.senders = append(lf.senders, sender) - - case BothDirection: - srcLinkInfo, err := NewLinkInfo(cfg.Src, cfg.Dst, cfg.LogConfig, cfg.FileConfig, modLevels) - if err != nil { - return nil, err - } - srcSender, err := NewSender(cfg.Src, cfg.Dst, srcLinkInfo.GetLogger()) - if err != nil { - return nil, err - } - lf.linkInfos = append(lf.linkInfos, srcLinkInfo) - lf.senders = append(lf.senders, srcSender) - - dstLinkInfo, err := NewLinkInfo(cfg.Dst, cfg.Src, cfg.LogConfig, cfg.FileConfig, modLevels) - if err != nil { - return nil, err - } - dstSender, err := NewSender(cfg.Dst, cfg.Src, dstLinkInfo.GetLogger()) - if err != nil { - return nil, err - } - lf.linkInfos = append(lf.linkInfos, dstLinkInfo) - lf.senders = append(lf.senders, dstSender) - - default: - return nil, fmt.Errorf("Not supported direction:%s", cfg.Direction) - } - - return lf, nil -} - -func newReceiver(srcCfg chain.BaseConfig, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { - var receiver link.Receiver - - switch srcCfg.Address.BlockChain() { - case ICON: - receiver = icon.NewReceiver(srcCfg, dstCfg, l) - case ETH: - fallthrough - case ETH2: - fallthrough - case BSC: - fallthrough - case HARDHAT: - receiver = ethbr.NewReceiver(srcCfg, dstCfg, l) - default: - l.Fatalf("Not supported for chain:%s", srcCfg.Address.BlockChain()) - return nil - } - return receiver -} - -func NewSender(srcCfg, dstCfg chain.BaseConfig, l log.Logger) (types.Sender, error) { - var sender types.Sender - var err error - switch dstCfg.Address.BlockChain() { - case ICON: - sender, err = icon.NewSender(srcCfg.Address, dstCfg, l) - if err != nil { - return nil, err - } - case ETH: - fallthrough - case ETH2: - fallthrough - case BSC: - fallthrough - case HARDHAT: - sender, err = ethbr.NewSender(srcCfg.Address, dstCfg, l) - if err != nil { - return nil, err - } - default: - l.Fatalf("Not supported for chain:%s", srcCfg.Address.BlockChain()) - } - - return sender, nil -} - -func setLogger(srcCfg chain.BaseConfig, lc LogConfig, fc config.FileConfig, modLevels map[string]string) log.Logger { - l := log.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", srcCfg.Address.NetworkID())}) - log.SetGlobalLogger(l) - stdlog.SetOutput(l.WriterLevel(log.WarnLevel)) - if lc.LogWriter != nil { - if lc.LogWriter.Filename == "" { - log.Debugln("LogWriterConfig filename is empty string, will be ignore") - } else { - var lwCfg log.WriterConfig - lwCfg = *lc.LogWriter - lwCfg.Filename = fc.ResolveAbsolute(lwCfg.Filename) - w, err := log.NewWriter(&lwCfg) - if err != nil { - log.Panicf("Fail to make writer err=%+v", err) - } - err = l.SetFileWriter(w) - if err != nil { - log.Panicf("Fail to set file l err=%+v", err) - } - } - } - - if lv, err := log.ParseLevel(lc.LogLevel); err != nil { - log.Panicf("Invalid log_level=%s", lc.LogLevel) - } else { - l.SetLevel(lv) - } - if lv, err := log.ParseLevel(lc.ConsoleLevel); err != nil { - log.Panicf("Invalid console_level=%s", lc.ConsoleLevel) - } else { - l.SetConsoleLevel(lv) - } - - for mod, lvStr := range modLevels { - if lv, err := log.ParseLevel(lvStr); err != nil { - log.Panicf("Invalid mod_level mod=%s level=%s", mod, lvStr) - } else { - l.SetModuleLevel(mod, lv) - } - } - - if lc.LogForwarder != nil { - if lc.LogForwarder.Vendor == "" && lc.LogForwarder.Address == "" { - log.Debugln("LogForwarderConfig vendor and address is empty string, will be ignore") - } else { - if err := log.AddForwarder(lc.LogForwarder); err != nil { - log.Fatalf("Invalid log_forwarder err:%+v", err) - } - } - } - - return l -} diff --git a/common/relay/relay.go b/common/relay/relay.go new file mode 100644 index 0000000..fadb62c --- /dev/null +++ b/common/relay/relay.go @@ -0,0 +1,75 @@ +package relay + +import ( + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/types" +) + +const ( + BothDirection = "both" + FrontDirection = "front" + ReverseDirection = "reverse" +) + +type linkFactory struct { + link types.Link + sender types.Sender +} +type Relay struct { + lfs []linkFactory +} + +// TODO rename / new go file?? +func NewRelay(cfg *link.Config, modLevels map[string]string) (*Relay, error) { + + r := &Relay{ + lfs: make([]linkFactory, 0), + } + switch cfg.Direction { + case FrontDirection: + l, s, err := link.NewLinkFactory(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) + if err != nil { + return nil, err + } + r.lfs = append(r.lfs, linkFactory{link: l, sender: s}) + case ReverseDirection: + l, s, err := link.NewLinkFactory(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) + if err != nil { + return nil, err + } + r.lfs = append(r.lfs, linkFactory{link: l, sender: s}) + case BothDirection: + frontL, frontS, err := link.NewLinkFactory(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) + if err != nil { + return nil, err + } + r.lfs = append(r.lfs, linkFactory{link: frontL, sender: frontS}) + + reverseL, reverseS, err := link.NewLinkFactory(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) + if err != nil { + return nil, err + } + r.lfs = append(r.lfs, linkFactory{link: reverseL, sender: reverseS}) + } + + return r, nil +} + +func (r *Relay) Start() error { + linkErrCh := make(chan error) + + for _, lf := range r.lfs { + if err := link.Start(lf.link, lf.sender, linkErrCh); err != nil { + return err + } + } + + for { + select { + case err := <-linkErrCh: + if err != nil { + return err + } + } + } +} diff --git a/common/types/type.go b/common/types/type.go index 8997536..a23fe96 100644 --- a/common/types/type.go +++ b/common/types/type.go @@ -56,11 +56,18 @@ type RelayResult struct { Finalized bool } +type Preference struct { + TxSizeLimit int64 + MarginForLimit int64 + LatestResult bool + FilledBlockUpdate bool + Other map[string]interface{} +} + type Sender interface { Start() (<-chan *RelayResult, error) Stop() GetStatus() (*BMCLinkStatus, error) Relay(rm RelayMessage) (string, error) - GetMarginForLimit() int64 - TxSizeLimit() int + GetPreference() Preference } From 3c4571b5d5d9231ff838e3218ffe70df5399b150 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Tue, 18 Jul 2023 14:38:04 +0900 Subject: [PATCH 04/22] Refactor eth bridge sender --- chain/ethbr/sender.go | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/chain/ethbr/sender.go b/chain/ethbr/sender.go index 3c08696..6d0f9f8 100644 --- a/chain/ethbr/sender.go +++ b/chain/ethbr/sender.go @@ -26,6 +26,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" + "github.com/icon-project/btp2/chain" + "github.com/icon-project/btp2/common/link" btpTypes "github.com/icon-project/btp2/common/types" "github.com/icon-project/btp2/chain/ethbr/binding" @@ -43,7 +45,7 @@ const ( ) var ( - txSizeLimit = int(math.Ceil(txMaxDataSize / (1 + txOverheadScale))) + txSizeLimit = int(math.Ceil(txMaxDataSize / (1 + txOverheadScale))) //TODO xcall의 2k 사이즈에 맞게 다시 설정한다. ) type Queue struct { @@ -90,12 +92,12 @@ func (q *Queue) len() int { } type sender struct { - c *client.Client - src btpTypes.BtpAddress - dst btpTypes.BtpAddress - w btpTypes.Wallet - l log.Logger - opt struct { + c *client.Client + srcAddr btpTypes.BtpAddress + dstCfg chain.BaseConfig + w btpTypes.Wallet + l log.Logger + opt struct { } bmc *binding.BMC rr chan *btpTypes.RelayResult @@ -103,14 +105,14 @@ type sender struct { queue *Queue } -func newSender(src, dst btpTypes.BtpAddress, w btpTypes.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) btpTypes.Sender { +func newSender(srcAddr btpTypes.BtpAddress, dstCfg link.ChainConfig, w btpTypes.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) btpTypes.Sender { s := &sender{ - src: src, - dst: dst, - w: w, - l: l, - rr: make(chan *btpTypes.RelayResult), - queue: NewQueue(), + srcAddr: srcAddr, + dstCfg: dstCfg.(chain.BaseConfig), + w: w, + l: l, + rr: make(chan *btpTypes.RelayResult), + queue: NewQueue(), } b, err := json.Marshal(opt) @@ -123,7 +125,7 @@ func newSender(src, dst btpTypes.BtpAddress, w btpTypes.Wallet, endpoint string, s.c = client.NewClient(endpoint, l) - s.bmc, _ = binding.NewBMC(client.HexToAddress(s.dst.ContractAddress()), s.c.GetEthClient()) + s.bmc, _ = binding.NewBMC(client.HexToAddress(s.dstCfg.Address.ContractAddress()), s.c.GetEthClient()) return s } @@ -137,7 +139,7 @@ func (s *sender) Stop() { } func (s *sender) GetStatus() (*btpTypes.BMCLinkStatus, error) { var status binding.TypesLinkStatus - status, err := s.bmc.GetStatus(nil, s.src.String()) + status, err := s.bmc.GetStatus(nil, s.srcAddr.String()) if err != nil { s.l.Errorf("Error retrieving relay status from BMC") return nil, err @@ -152,10 +154,6 @@ func (s *sender) GetStatus() (*btpTypes.BMCLinkStatus, error) { return ls, nil } -func (s *sender) GetMarginForLimit() int64 { - return 0 -} - func (s *sender) Relay(rm btpTypes.RelayMessage) (string, error) { //check send queue if MaxQueueSize <= s.queue.len() { @@ -234,8 +232,16 @@ func (s *sender) GetResult(txh *client.TransactionHashParam) (*types.Receipt, er } } -func (s *sender) TxSizeLimit() int { - return txSizeLimit +// TODO config setting +func (s *sender) GetPreference() btpTypes.Preference { + p := btpTypes.Preference{ + TxSizeLimit: int64(txSizeLimit), + MarginForLimit: int64(0), + LatestResult: false, + FilledBlockUpdate: false, + } + + return p } func (s *sender) _relay(rm btpTypes.RelayMessage) (*client.TransactionHashParam, error) { @@ -247,7 +253,7 @@ func (s *sender) _relay(rm btpTypes.RelayMessage) (*client.TransactionHashParam, var tx *types.Transaction - tx, err = s.bmc.HandleRelayMessage(t, s.src.String(), rm.Bytes()[:]) + tx, err = s.bmc.HandleRelayMessage(t, s.srcAddr.String(), rm.Bytes()[:]) if err != nil { s.l.Errorf("handleRelayMessage error: %s, rm id:%s ", err.Error(), rm.Id()) return nil, err From 6a05a98eb892f0c98c7cb53c9e57c84e128d9ec9 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Tue, 18 Jul 2023 17:08:47 +0900 Subject: [PATCH 05/22] Cleanup relay code --- chain/ethbr/ethbrfactory.go | 3 -- chain/ethbr/message.go | 4 -- chain/ethbr/sender.go | 1 - chain/icon/bridge/bridgefactory.go | 5 --- chain/icon/btp2/btp2.go | 2 +- chain/icon/btp2/btpblockfactory.go | 5 --- chain/icon/iconfactory.go | 70 ------------------------------ chain/icon/sender.go | 1 - common/link/factory.go | 18 +++----- common/relay/relay.go | 9 ++-- 10 files changed, 12 insertions(+), 106 deletions(-) delete mode 100644 chain/icon/iconfactory.go diff --git a/chain/ethbr/ethbrfactory.go b/chain/ethbr/ethbrfactory.go index a4bd833..96fb780 100644 --- a/chain/ethbr/ethbrfactory.go +++ b/chain/ethbr/ethbrfactory.go @@ -57,8 +57,6 @@ func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l l func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) - - //TODO refactoring w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) if err != nil { return nil, err @@ -82,7 +80,6 @@ func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { if keyStorePass != "" { return []byte(keyStorePass), nil } else { - //TODO return nil, fmt.Errorf("") } } diff --git a/chain/ethbr/message.go b/chain/ethbr/message.go index 010b368..f05051b 100644 --- a/chain/ethbr/message.go +++ b/chain/ethbr/message.go @@ -110,10 +110,6 @@ func NewMessageProof(bs *types.BMCLinkStatus, startSeq, lastSeq int64, rps []*cl continue } numOfEvents += len(rp.Events) - //if b, err = codec.RLP.MarshalToBytes(rp.Events); err != nil { - // return nil, err - //} - //TODO refactoring if b, err = rlp.EncodeToBytes(rp.Events); err != nil { return nil, err } diff --git a/chain/ethbr/sender.go b/chain/ethbr/sender.go index 6d0f9f8..dcdf838 100644 --- a/chain/ethbr/sender.go +++ b/chain/ethbr/sender.go @@ -232,7 +232,6 @@ func (s *sender) GetResult(txh *client.TransactionHashParam) (*types.Receipt, er } } -// TODO config setting func (s *sender) GetPreference() btpTypes.Preference { p := btpTypes.Preference{ TxSizeLimit: int64(txSizeLimit), diff --git a/chain/icon/bridge/bridgefactory.go b/chain/icon/bridge/bridgefactory.go index afe6b9e..d486828 100644 --- a/chain/icon/bridge/bridgefactory.go +++ b/chain/icon/bridge/bridgefactory.go @@ -2,7 +2,6 @@ package bridge import ( "encoding/json" - "fmt" "os" "github.com/icon-project/btp2/chain" @@ -60,7 +59,6 @@ func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l l func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) - //TODO refactoring w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) if err != nil { return nil, err @@ -83,9 +81,6 @@ func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { } else { if keyStorePass != "" { return []byte(keyStorePass), nil - } else { - //TODO add error message - return nil, fmt.Errorf("") } } } diff --git a/chain/icon/btp2/btp2.go b/chain/icon/btp2/btp2.go index 0bc1cf7..0b1a775 100644 --- a/chain/icon/btp2/btp2.go +++ b/chain/icon/btp2/btp2.go @@ -430,7 +430,7 @@ func (b *btp2) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus func (b *btp2) GetReceiveStatusForSequence(seq int64) *receiveStatus { for _, rs := range b.rss { - if rs.Seq() <= seq && seq <= rs.Seq() { //TODO + if rs.Seq() <= seq && seq <= rs.Seq() { return rs } } diff --git a/chain/icon/btp2/btpblockfactory.go b/chain/icon/btp2/btpblockfactory.go index 556b2ad..0b86f76 100644 --- a/chain/icon/btp2/btpblockfactory.go +++ b/chain/icon/btp2/btpblockfactory.go @@ -2,7 +2,6 @@ package btp2 import ( "encoding/json" - "fmt" "os" "github.com/icon-project/btp2/chain" @@ -59,7 +58,6 @@ func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l l func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) - //TODO refactoring w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) if err != nil { return nil, err @@ -82,9 +80,6 @@ func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { } else { if keyStorePass != "" { return []byte(keyStorePass), nil - } else { - //TODO add error message - return nil, fmt.Errorf("") } } } diff --git a/chain/icon/iconfactory.go b/chain/icon/iconfactory.go deleted file mode 100644 index 9c4edce..0000000 --- a/chain/icon/iconfactory.go +++ /dev/null @@ -1,70 +0,0 @@ -package icon - -// -//import ( -// "encoding/json" -// "fmt" -// "os" -// -// "github.com/icon-project/btp2/chain" -// "github.com/icon-project/btp2/chain/icon/bridge" -// "github.com/icon-project/btp2/chain/icon/btp2" -// "github.com/icon-project/btp2/common/link" -// "github.com/icon-project/btp2/common/log" -// "github.com/icon-project/btp2/common/types" -// "github.com/icon-project/btp2/common/wallet" -//) -// -//const ( -// BRIDGE = "bridge" -// TRUSTLESS = "trustless" -//) -// -//// func NewReceiver(srcCfg, dstCfg chain.BaseConfig, l log.Logger) link.Receiver { -//func NewReceiver(srcCfg, dstCfg interface{}, l log.Logger) link.Receiver { -// src := srcCfg.(chain.BaseConfig) -// dst := dstCfg.(chain.BaseConfig) -// var receiver link.Receiver -// -// src.Name -// switch srcCfg.RelayMode { -// case BRIDGE: -// receiver = bridge.NewBridge(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) -// case TRUSTLESS: -// receiver = btp2.NewBTP2(srcCfg.Address, dstCfg.Address, srcCfg.Endpoint, l) -// default: -// l.Panicf("Not supported for relay mod:%s", srcCfg.RelayMode) -// } -// return receiver -//} -// -//func NewSender(srcAddr types.BtpAddress, cfg chain.BaseConfig, l log.Logger) (types.Sender, error) { -// //TODO refactoring -// w, err := Wallet(cfg.KeyStorePass, cfg.KeySecret, cfg.KeyStoreData) -// if err != nil { -// return nil, err -// } -// -// return newSender(srcAddr, cfg.Address, w, cfg.Endpoint, cfg.Options, l), nil -//} -// -//func Wallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { -// pw, err := resolvePassword(secret, passwd) -// if err != nil { -// return nil, err -// } -// return wallet.DecryptKeyStore(keyStore, pw) -//} -// -//func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { -// if keySecret != "" { -// return os.ReadFile(keySecret) -// } else { -// if keyStorePass != "" { -// return []byte(keyStorePass), nil -// } else { -// //TODO add error message -// return nil, fmt.Errorf("") -// } -// } -//} diff --git a/chain/icon/sender.go b/chain/icon/sender.go index eaa268d..6087d11 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -211,7 +211,6 @@ func (s *sender) result(id string, txh *client.TransactionHashParam) { } } -// TODO config setting func (s *sender) GetPreference() types.Preference { p := types.Preference{ TxSizeLimit: int64(txSizeLimit), diff --git a/common/link/factory.go b/common/link/factory.go index dd0b0e3..0fb84d6 100644 --- a/common/link/factory.go +++ b/common/link/factory.go @@ -10,11 +10,10 @@ import ( ) type Factory struct { - CreateChainConfig func() map[string]interface{} - GetChainConfig func(dict map[string]interface{}) (ChainConfig, error) - CheckConfig func(cfg ChainConfig) bool - NewReceiver func(srcCfg, dstCfg ChainConfig, fileCfg config.FileConfig, l log.Logger) (Receiver, error) - NewSender func(srcCfg, dstCfg ChainConfig, l log.Logger) (types.Sender, error) + GetChainConfig func(dict map[string]interface{}) (ChainConfig, error) + CheckConfig func(cfg ChainConfig) bool + NewReceiver func(srcCfg, dstCfg ChainConfig, fileCfg config.FileConfig, l log.Logger) (Receiver, error) + NewSender func(srcCfg, dstCfg ChainConfig, l log.Logger) (types.Sender, error) } var factories []*Factory @@ -25,8 +24,7 @@ func RegisterFactory(f *Factory) { } } -// TODO rename / new go file?? -func NewLinkFactory(srcCfg, dstCfg map[string]interface{}, relayCfg RelayConfig, modLevels map[string]string) (types.Link, types.Sender, error) { +func ComposeLink(srcCfg, dstCfg map[string]interface{}, relayCfg RelayConfig, modLevels map[string]string) (types.Link, types.Sender, error) { var err error var srcChainCfg ChainConfig @@ -48,8 +46,7 @@ func NewLinkFactory(srcCfg, dstCfg map[string]interface{}, relayCfg RelayConfig, } if srcChainCfg == nil { - //TODO error message - return nil, nil, fmt.Errorf("") + return nil, nil, fmt.Errorf("not supported source chain") } //Sender @@ -65,8 +62,7 @@ func NewLinkFactory(srcCfg, dstCfg map[string]interface{}, relayCfg RelayConfig, } if dstChainCfg == nil { - //TODO error message - return nil, nil, fmt.Errorf("") + return nil, nil, fmt.Errorf("not supported destination chain") } logger := setLogger(srcChainCfg, relayCfg, modLevels) diff --git a/common/relay/relay.go b/common/relay/relay.go index fadb62c..7b60cf1 100644 --- a/common/relay/relay.go +++ b/common/relay/relay.go @@ -19,7 +19,6 @@ type Relay struct { lfs []linkFactory } -// TODO rename / new go file?? func NewRelay(cfg *link.Config, modLevels map[string]string) (*Relay, error) { r := &Relay{ @@ -27,25 +26,25 @@ func NewRelay(cfg *link.Config, modLevels map[string]string) (*Relay, error) { } switch cfg.Direction { case FrontDirection: - l, s, err := link.NewLinkFactory(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) + l, s, err := link.ComposeLink(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) if err != nil { return nil, err } r.lfs = append(r.lfs, linkFactory{link: l, sender: s}) case ReverseDirection: - l, s, err := link.NewLinkFactory(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) + l, s, err := link.ComposeLink(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) if err != nil { return nil, err } r.lfs = append(r.lfs, linkFactory{link: l, sender: s}) case BothDirection: - frontL, frontS, err := link.NewLinkFactory(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) + frontL, frontS, err := link.ComposeLink(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) if err != nil { return nil, err } r.lfs = append(r.lfs, linkFactory{link: frontL, sender: frontS}) - reverseL, reverseS, err := link.NewLinkFactory(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) + reverseL, reverseS, err := link.ComposeLink(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) if err != nil { return nil, err } From a9a85f8406bf5a6dbbd36602745bfc2b6ec8414c Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Tue, 18 Jul 2023 17:16:25 +0900 Subject: [PATCH 06/22] Fix bug in resolvePassword --- chain/icon/bridge/bridgefactory.go | 1 + chain/icon/btp2/btpblockfactory.go | 1 + 2 files changed, 2 insertions(+) diff --git a/chain/icon/bridge/bridgefactory.go b/chain/icon/bridge/bridgefactory.go index d486828..9678bfb 100644 --- a/chain/icon/bridge/bridgefactory.go +++ b/chain/icon/bridge/bridgefactory.go @@ -83,4 +83,5 @@ func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { return []byte(keyStorePass), nil } } + return nil, nil } diff --git a/chain/icon/btp2/btpblockfactory.go b/chain/icon/btp2/btpblockfactory.go index 0b86f76..67be6c6 100644 --- a/chain/icon/btp2/btpblockfactory.go +++ b/chain/icon/btp2/btpblockfactory.go @@ -82,4 +82,5 @@ func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { return []byte(keyStorePass), nil } } + return nil, nil } From 9248fa2b42d282f7852f518195c556c59b750fe4 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Wed, 19 Jul 2023 09:12:51 +0900 Subject: [PATCH 07/22] Add limit on number of retries in icon tx resut --- chain/icon/sender.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/chain/icon/sender.go b/chain/icon/sender.go index 6087d11..c1111c5 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -41,6 +41,7 @@ const ( DefaultRelayReSendInterval = time.Second DefaultStepLimit = 0x9502f900 //maxStepLimit(invoke), refer https://www.icondev.io/docs/step-estimation MaxQueueSize = 100 + TransactionResultRetryLimit = 5 ) var ( @@ -320,13 +321,20 @@ SignLoop: } func (s *sender) GetResult(txh *client.TransactionHashParam) (*client.TransactionResult, error) { + var retry = TransactionResultRetryLimit for { txr, err := s.c.GetTransactionResult(txh) if err != nil { if je, ok := err.(*jsonrpc.Error); ok { switch je.Code { - //TODO add notFound timeout - case client.JsonrpcErrorCodePending, client.JsonrpcErrorCodeExecuting, client.JsonrpcErrorCodeNotFound: + case client.JsonrpcErrorCodePending, client.JsonrpcErrorCodeExecuting: + <-time.After(DefaultGetRelayResultInterval) + continue + case client.JsonrpcErrorCodeNotFound: + if retry == 0 { + return nil, fmt.Errorf("not found transaction result ( TxHash : %v)", txh.Hash) + } + retry-- <-time.After(DefaultGetRelayResultInterval) continue } From 378f38359b9aaebf9842c97368bdb77c1460f49d Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Wed, 19 Jul 2023 11:11:27 +0900 Subject: [PATCH 08/22] Add relay mode and support chain to relay configuration --- chain/config.go | 6 +++--- chain/ethbr/ethbrfactory.go | 31 ++++++++++++++++++++++------- chain/icon/bridge/bridgefactory.go | 32 ++++++++++++++++++++++-------- chain/icon/btp2/btpblockfactory.go | 31 ++++++++++++++++++++++------- common/link/config.go | 2 +- common/link/factory.go | 25 +++++++++++++++++++++++ 6 files changed, 101 insertions(+), 26 deletions(-) diff --git a/chain/config.go b/chain/config.go index 99191e9..ca63dea 100644 --- a/chain/config.go +++ b/chain/config.go @@ -26,7 +26,7 @@ type BaseConfig struct { Address types.BtpAddress `json:"address"` Endpoint string `json:"endpoint"` KeyStoreData json.RawMessage `json:"key_store"` - ChainId string `json:"chain_id"` + Mode string `json:"mode"` KeyStorePass string `json:"key_password,omitempty"` KeySecret string `json:"key_secret,omitempty"` @@ -37,8 +37,8 @@ func (b BaseConfig) GetAddress() types.BtpAddress { return b.Address } -func (b BaseConfig) GetChainId() string { - return b.ChainId +func (b BaseConfig) GetMode() string { + return b.Mode } func (b BaseConfig) GetNetworkID() string { diff --git a/chain/ethbr/ethbrfactory.go b/chain/ethbr/ethbrfactory.go index 96fb780..d70655d 100644 --- a/chain/ethbr/ethbrfactory.go +++ b/chain/ethbr/ethbrfactory.go @@ -13,15 +13,29 @@ import ( "github.com/icon-project/btp2/common/wallet" ) +const MODE = "bridge" + +var supportBlockChain = []string{"hardhat", "eth", "eth2", "bsc"} + func RegisterIconEthBr() { link.RegisterFactory(&link.Factory{ - GetChainConfig: GetChainConfig, - CheckConfig: CheckConfig, - NewReceiver: NewReceiver, - NewSender: NewSender, + GetSupportChain: GetSupportChain, + GetMode: GetMode, + GetChainConfig: GetChainConfig, + CheckConfig: CheckConfig, + NewReceiver: NewReceiver, + NewSender: NewSender, }) } +func GetSupportChain() []string { + return supportBlockChain +} + +func GetMode() string { + return MODE +} + func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { cfg := chain.BaseConfig{} @@ -42,10 +56,13 @@ func CheckConfig(cfg link.ChainConfig) bool { return false } - if baseCfg.ChainId == "eth_bridge" { - return true + for _, c := range supportBlockChain { + if c == baseCfg.Address.BlockChain() { + if baseCfg.Mode == MODE { + return true + } + } } - return false } diff --git a/chain/icon/bridge/bridgefactory.go b/chain/icon/bridge/bridgefactory.go index 9678bfb..0b1a45c 100644 --- a/chain/icon/bridge/bridgefactory.go +++ b/chain/icon/bridge/bridgefactory.go @@ -13,15 +13,29 @@ import ( "github.com/icon-project/btp2/common/wallet" ) +const MODE = "bridge" + +var supportBlockChain = []string{"icon", "havah"} + func RegisterIconBridge() { link.RegisterFactory(&link.Factory{ - GetChainConfig: GetChainConfig, - CheckConfig: CheckConfig, - NewReceiver: NewReceiver, - NewSender: NewSender, + GetSupportChain: GetSupportChain, + GetMode: GetMode, + GetChainConfig: GetChainConfig, + CheckConfig: CheckConfig, + NewReceiver: NewReceiver, + NewSender: NewSender, }) } +func GetSupportChain() []string { + return supportBlockChain +} + +func GetMode() string { + return MODE +} + func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { cfg := chain.BaseConfig{} @@ -38,15 +52,17 @@ func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { func CheckConfig(cfg link.ChainConfig) bool { baseCfg, ok := cfg.(chain.BaseConfig) - if !ok { return false } - if baseCfg.ChainId == "icon_bridge" { - return true + for _, c := range supportBlockChain { + if c == baseCfg.Address.BlockChain() { + if baseCfg.Mode == MODE { + return true + } + } } - return false } diff --git a/chain/icon/btp2/btpblockfactory.go b/chain/icon/btp2/btpblockfactory.go index 67be6c6..4f97a39 100644 --- a/chain/icon/btp2/btpblockfactory.go +++ b/chain/icon/btp2/btpblockfactory.go @@ -13,15 +13,29 @@ import ( "github.com/icon-project/btp2/common/wallet" ) +const MODE = "btpBlock" + +var supportBlockChain = []string{"icon", "havah"} + func RegisterIconBtp2() { link.RegisterFactory(&link.Factory{ - GetChainConfig: GetChainConfig, - CheckConfig: CheckConfig, - NewReceiver: NewReceiver, - NewSender: NewSender, + GetSupportChain: GetSupportChain, + GetMode: GetMode, + GetChainConfig: GetChainConfig, + CheckConfig: CheckConfig, + NewReceiver: NewReceiver, + NewSender: NewSender, }) } +func GetSupportChain() []string { + return supportBlockChain +} + +func GetMode() string { + return MODE +} + func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { cfg := chain.BaseConfig{} @@ -42,10 +56,13 @@ func CheckConfig(cfg link.ChainConfig) bool { return false } - if baseCfg.ChainId == "icon_btpBlock" { - return true + for _, c := range supportBlockChain { + if c == baseCfg.Address.BlockChain() { + if baseCfg.Mode == MODE { + return true + } + } } - return false } diff --git a/common/link/config.go b/common/link/config.go index 941d9af..d70e26e 100644 --- a/common/link/config.go +++ b/common/link/config.go @@ -17,7 +17,7 @@ type RelayConfig struct { type ChainConfig interface { GetAddress() types.BtpAddress - GetChainId() string + GetMode() string GetNetworkID() string } diff --git a/common/link/factory.go b/common/link/factory.go index 0fb84d6..5c300ee 100644 --- a/common/link/factory.go +++ b/common/link/factory.go @@ -3,6 +3,7 @@ package link import ( "fmt" stdlog "log" + "sort" "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/log" @@ -10,6 +11,9 @@ import ( ) type Factory struct { + GetSupportChain func() []string + GetMode func() string + GetChainConfig func(dict map[string]interface{}) (ChainConfig, error) CheckConfig func(cfg ChainConfig) bool NewReceiver func(srcCfg, dstCfg ChainConfig, fileCfg config.FileConfig, l log.Logger) (Receiver, error) @@ -20,10 +24,31 @@ var factories []*Factory func RegisterFactory(f *Factory) { if f != nil { + if checkDuplicates(f) { + return + } factories = append(factories, f) } } +func checkDuplicates(f *Factory) bool { + for _, cf := range factories { + for _, cfChain := range cf.GetSupportChain() { + if contains(f.GetSupportChain(), cfChain) { + if cf.GetMode() == f.GetMode() { + return true + } + } + } + } + return false +} + +func contains(s []string, e string) bool { + i := sort.SearchStrings(s, e) + return i < len(s) && s[i] == e +} + func ComposeLink(srcCfg, dstCfg map[string]interface{}, relayCfg RelayConfig, modLevels map[string]string) (types.Link, types.Sender, error) { var err error From 488fd0a888ee1f418669d5b89a650d0fb71e6d5c Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Fri, 21 Jul 2023 10:46:51 +0900 Subject: [PATCH 09/22] Refactor config in relay --- chain/config.go | 10 +- chain/ethbr/ethbrfactory.go | 68 +++++------ chain/ethbr/receiver.go | 11 +- chain/ethbr/sender.go | 2 +- chain/icon/bridge/bridge.go | 2 +- chain/icon/bridge/bridgefactory.go | 64 +++++------ chain/icon/btp2/btp2.go | 11 +- chain/icon/btp2/btpblockfactory.go | 64 +++++------ cmd/relay/main.go | 7 +- common/link/config.go | 36 +++--- common/link/factory.go | 176 ++++++++--------------------- common/link/link.go | 26 ++--- common/relay/config.go | 21 ++++ common/relay/relay.go | 124 ++++++++++++++++++-- 14 files changed, 309 insertions(+), 313 deletions(-) create mode 100644 common/relay/config.go diff --git a/chain/config.go b/chain/config.go index ca63dea..7c35283 100644 --- a/chain/config.go +++ b/chain/config.go @@ -26,7 +26,7 @@ type BaseConfig struct { Address types.BtpAddress `json:"address"` Endpoint string `json:"endpoint"` KeyStoreData json.RawMessage `json:"key_store"` - Mode string `json:"mode"` + Type string `json:"type"` KeyStorePass string `json:"key_password,omitempty"` KeySecret string `json:"key_secret,omitempty"` @@ -37,10 +37,6 @@ func (b BaseConfig) GetAddress() types.BtpAddress { return b.Address } -func (b BaseConfig) GetMode() string { - return b.Mode -} - -func (b BaseConfig) GetNetworkID() string { - return b.Address.NetworkID() +func (b BaseConfig) GetType() string { + return b.Type } diff --git a/chain/ethbr/ethbrfactory.go b/chain/ethbr/ethbrfactory.go index d70655d..8d0601e 100644 --- a/chain/ethbr/ethbrfactory.go +++ b/chain/ethbr/ethbrfactory.go @@ -2,44 +2,31 @@ package ethbr import ( "encoding/json" - "fmt" "os" "github.com/icon-project/btp2/chain" - "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" "github.com/icon-project/btp2/common/wallet" ) -const MODE = "bridge" - -var supportBlockChain = []string{"hardhat", "eth", "eth2", "bsc"} +const TYPE = "bsc-bridge-solidity" func RegisterIconEthBr() { link.RegisterFactory(&link.Factory{ - GetSupportChain: GetSupportChain, - GetMode: GetMode, - GetChainConfig: GetChainConfig, - CheckConfig: CheckConfig, - NewReceiver: NewReceiver, - NewSender: NewSender, + Type: TYPE, + ParseChainConfig: ParseChainConfig, + NewLink: NewLink, + NewReceiver: NewReceiver, + NewSender: NewSender, }) } -func GetSupportChain() []string { - return supportBlockChain -} - -func GetMode() string { - return MODE -} - -func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { +func ParseChainConfig(raw json.RawMessage) (link.ChainConfig, error) { cfg := chain.BaseConfig{} - jsonbody, err := json.Marshal(dict) + jsonbody, err := json.Marshal(raw) if err != nil { return nil, err } @@ -47,39 +34,41 @@ func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { if err := json.Unmarshal(jsonbody, &cfg); err != nil { return nil, err } - return cfg, nil -} -func CheckConfig(cfg link.ChainConfig) bool { - baseCfg, ok := cfg.(chain.BaseConfig) - if !ok { - return false + //TODO add check + if cfg.Type == TYPE { + return cfg, nil } - for _, c := range supportBlockChain { - if c == baseCfg.Address.BlockChain() { - if baseCfg.Mode == MODE { - return true - } - } + return nil, nil +} + +func NewLink(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (types.Link, error) { + src := srcCfg.(chain.BaseConfig) + + r, err := newEthBridge(srcCfg, dstAddr, src.Endpoint, l, baseDir, src.Options) + if err != nil { + return nil, err } - return false + + link := link.NewLink(srcCfg, r, l) + return link, nil } -func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l log.Logger) (link.Receiver, error) { +func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (link.Receiver, error) { src := srcCfg.(chain.BaseConfig) - return newEthBridge(srcCfg, dstCfg.GetAddress(), src.Endpoint, l, fileCfg, src.Options) + return newEthBridge(srcCfg, dstAddr, src.Endpoint, l, baseDir, src.Options) } -func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { +func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) if err != nil { return nil, err } - return newSender(srcCfg.GetAddress(), dst, w, dst.Endpoint, dst.Options, l), nil + return newSender(srcAddr, dst, w, dst.Endpoint, dst.Options, l), nil } func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { @@ -96,8 +85,7 @@ func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { } else { if keyStorePass != "" { return []byte(keyStorePass), nil - } else { - return nil, fmt.Errorf("") } } + return nil, nil } diff --git a/chain/ethbr/receiver.go b/chain/ethbr/receiver.go index a5f8207..b4d3d7b 100644 --- a/chain/ethbr/receiver.go +++ b/chain/ethbr/receiver.go @@ -20,7 +20,6 @@ import ( "github.com/icon-project/btp2/chain/ethbr/binding" "github.com/icon-project/btp2/chain/ethbr/client" "github.com/icon-project/btp2/common/codec" - "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/db" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/link" @@ -88,7 +87,7 @@ type ethbr struct { } func newEthBridge(src link.ChainConfig, dst btpTypes.BtpAddress, endpoint string, - l log.Logger, fileCfg config.FileConfig, opt map[string]interface{}) (*ethbr, error) { + l log.Logger, baseDir string, opt map[string]interface{}) (*ethbr, error) { c := ðbr{ src: src, dst: dst, @@ -107,7 +106,7 @@ func newEthBridge(src link.ChainConfig, dst btpTypes.BtpAddress, endpoint string l.Panicf("fail to unmarshal opt:%#v err:%+v", opt, err) } - bk, err := c.prepareDatabase(fileCfg) + bk, err := c.prepareDatabase(baseDir) if err != nil { return nil, err } @@ -120,9 +119,9 @@ func (e *ethbr) setHeightToDatabase() { e.bk.Set([]byte("ReceiveHeight"), bytesArray) } -func (e *ethbr) prepareDatabase(fileCfg config.FileConfig) (db.Bucket, error) { - e.l.Debugln("open database", filepath.Join(fileCfg.AbsBaseDir()+e.src.GetNetworkID(), e.dst.NetworkAddress())) - database, err := db.Open(fileCfg.AbsBaseDir()+e.src.GetNetworkID(), string(DefaultDBType), e.dst.NetworkAddress()) +func (e *ethbr) prepareDatabase(baseDir string) (db.Bucket, error) { + e.l.Debugln("open database", filepath.Join(baseDir+e.src.GetAddress().NetworkID(), e.dst.NetworkAddress())) + database, err := db.Open(baseDir+e.src.GetAddress().NetworkID(), string(DefaultDBType), e.dst.NetworkAddress()) if err != nil { return nil, errors.Wrap(err, "fail to open database") } diff --git a/chain/ethbr/sender.go b/chain/ethbr/sender.go index dcdf838..6b618ba 100644 --- a/chain/ethbr/sender.go +++ b/chain/ethbr/sender.go @@ -45,7 +45,7 @@ const ( ) var ( - txSizeLimit = int(math.Ceil(txMaxDataSize / (1 + txOverheadScale))) //TODO xcall의 2k 사이즈에 맞게 다시 설정한다. + txSizeLimit = int(math.Ceil(txMaxDataSize / (1 + txOverheadScale))) ) type Queue struct { diff --git a/chain/icon/bridge/bridge.go b/chain/icon/bridge/bridge.go index ace1428..764bb4c 100644 --- a/chain/icon/bridge/bridge.go +++ b/chain/icon/bridge/bridge.go @@ -73,7 +73,7 @@ func newReceiveStatus(height, rxSeq int64, sn int64, msgs []string, next types.B }, nil } -func newBridge(src link.ChainConfig, dst types.BtpAddress, endpoint string, l log.Logger) (*bridge, error) { +func newBridge(src link.ChainConfig, dst types.BtpAddress, endpoint string, baseDir string, l log.Logger) (*bridge, error) { c := &bridge{ src: src, dst: dst, diff --git a/chain/icon/bridge/bridgefactory.go b/chain/icon/bridge/bridgefactory.go index 0b1a45c..fc099ef 100644 --- a/chain/icon/bridge/bridgefactory.go +++ b/chain/icon/bridge/bridgefactory.go @@ -6,40 +6,28 @@ import ( "github.com/icon-project/btp2/chain" "github.com/icon-project/btp2/chain/icon" - "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" "github.com/icon-project/btp2/common/wallet" ) -const MODE = "bridge" - -var supportBlockChain = []string{"icon", "havah"} +const TYPE = "icon-bridge-java" func RegisterIconBridge() { link.RegisterFactory(&link.Factory{ - GetSupportChain: GetSupportChain, - GetMode: GetMode, - GetChainConfig: GetChainConfig, - CheckConfig: CheckConfig, - NewReceiver: NewReceiver, - NewSender: NewSender, + Type: TYPE, + ParseChainConfig: ParseChainConfig, + NewLink: NewLink, + NewReceiver: NewReceiver, + NewSender: NewSender, }) } -func GetSupportChain() []string { - return supportBlockChain -} - -func GetMode() string { - return MODE -} - -func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { +func ParseChainConfig(raw json.RawMessage) (link.ChainConfig, error) { cfg := chain.BaseConfig{} - jsonbody, err := json.Marshal(dict) + jsonbody, err := json.Marshal(raw) if err != nil { return nil, err } @@ -47,32 +35,34 @@ func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { if err := json.Unmarshal(jsonbody, &cfg); err != nil { return nil, err } - return cfg, nil -} -func CheckConfig(cfg link.ChainConfig) bool { - baseCfg, ok := cfg.(chain.BaseConfig) - if !ok { - return false + //TODO add check + if cfg.Type == TYPE { + return cfg, nil } - for _, c := range supportBlockChain { - if c == baseCfg.Address.BlockChain() { - if baseCfg.Mode == MODE { - return true - } - } + return nil, nil +} + +func NewLink(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (types.Link, error) { + src := srcCfg.(chain.BaseConfig) + + r, err := newBridge(src, dstAddr, src.Endpoint, baseDir, l) + if err != nil { + return nil, err } - return false + + link := link.NewLink(srcCfg, r, l) + return link, nil } -func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l log.Logger) (link.Receiver, error) { +func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (link.Receiver, error) { src := srcCfg.(chain.BaseConfig) - return newBridge(src, dstCfg.GetAddress(), src.Endpoint, l) + return newBridge(src, dstAddr, src.Endpoint, baseDir, l) } -func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { +func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) @@ -80,7 +70,7 @@ func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, err return nil, err } - return icon.NewSender(srcCfg.GetAddress(), dst, w, dst.Endpoint, dst.Options, l), nil + return icon.NewSender(srcAddr, dst, w, dst.Endpoint, dst.Options, l), nil } func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { diff --git a/chain/icon/btp2/btp2.go b/chain/icon/btp2/btp2.go index 0b1a775..08efd58 100644 --- a/chain/icon/btp2/btp2.go +++ b/chain/icon/btp2/btp2.go @@ -11,7 +11,6 @@ import ( "github.com/icon-project/btp2/chain/icon/client" "github.com/icon-project/btp2/common/codec" - "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/db" "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/intconv" @@ -62,7 +61,7 @@ type btp2 struct { startHeight int64 } -func newBTP2(src link.ChainConfig, dst types.BtpAddress, endpoint string, fileCfg config.FileConfig, l log.Logger) (*btp2, error) { +func newBTP2(src link.ChainConfig, dst types.BtpAddress, endpoint string, baseDir string, l log.Logger) (*btp2, error) { c := &btp2{ src: src, dst: dst, @@ -72,7 +71,7 @@ func newBTP2(src link.ChainConfig, dst types.BtpAddress, endpoint string, fileCf rs: &receiveStatus{}, } c.c = client.NewClient(endpoint, l) - bk, err := c.prepareDatabase(fileCfg) + bk, err := c.prepareDatabase(baseDir) if err != nil { return nil, err } @@ -85,9 +84,9 @@ func (b *btp2) setHeightToDatabase() { b.bk.Set([]byte("ReceiveHeight"), bytesArray) } -func (b *btp2) prepareDatabase(fileCfg config.FileConfig) (db.Bucket, error) { - b.l.Debugln("open database", filepath.Join(fileCfg.AbsBaseDir()+b.src.GetNetworkID(), b.dst.NetworkAddress())) - database, err := db.Open(fileCfg.AbsBaseDir()+b.src.GetNetworkID(), string(DefaultDBType), b.dst.NetworkAddress()) +func (b *btp2) prepareDatabase(baseDir string) (db.Bucket, error) { + b.l.Debugln("open database", filepath.Join(baseDir+b.src.GetAddress().NetworkID(), b.dst.NetworkAddress())) + database, err := db.Open(baseDir+b.src.GetAddress().NetworkID(), string(DefaultDBType), b.dst.NetworkAddress()) if err != nil { return nil, errors.Wrap(err, "fail to open database") } diff --git a/chain/icon/btp2/btpblockfactory.go b/chain/icon/btp2/btpblockfactory.go index 4f97a39..7abcf31 100644 --- a/chain/icon/btp2/btpblockfactory.go +++ b/chain/icon/btp2/btpblockfactory.go @@ -6,40 +6,28 @@ import ( "github.com/icon-project/btp2/chain" "github.com/icon-project/btp2/chain/icon" - "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" "github.com/icon-project/btp2/common/wallet" ) -const MODE = "btpBlock" - -var supportBlockChain = []string{"icon", "havah"} +const TYPE = "icon-btpblock-java" func RegisterIconBtp2() { link.RegisterFactory(&link.Factory{ - GetSupportChain: GetSupportChain, - GetMode: GetMode, - GetChainConfig: GetChainConfig, - CheckConfig: CheckConfig, - NewReceiver: NewReceiver, - NewSender: NewSender, + Type: TYPE, + ParseChainConfig: ParseChainConfig, + NewLink: NewLink, + NewReceiver: NewReceiver, + NewSender: NewSender, }) } -func GetSupportChain() []string { - return supportBlockChain -} - -func GetMode() string { - return MODE -} - -func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { +func ParseChainConfig(raw json.RawMessage) (link.ChainConfig, error) { cfg := chain.BaseConfig{} - jsonbody, err := json.Marshal(dict) + jsonbody, err := json.Marshal(raw) if err != nil { return nil, err } @@ -47,32 +35,34 @@ func GetChainConfig(dict map[string]interface{}) (link.ChainConfig, error) { if err := json.Unmarshal(jsonbody, &cfg); err != nil { return nil, err } - return cfg, nil -} -func CheckConfig(cfg link.ChainConfig) bool { - baseCfg, ok := cfg.(chain.BaseConfig) - if !ok { - return false + //TODO add check + if cfg.Type == TYPE { + return cfg, nil } - for _, c := range supportBlockChain { - if c == baseCfg.Address.BlockChain() { - if baseCfg.Mode == MODE { - return true - } - } + return nil, nil +} + +func NewLink(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (types.Link, error) { + src := srcCfg.(chain.BaseConfig) + + r, err := newBTP2(src, dstAddr, src.Endpoint, baseDir, l) + if err != nil { + return nil, err } - return false + + link := link.NewLink(srcCfg, r, l) + return link, nil } -func NewReceiver(srcCfg, dstCfg link.ChainConfig, fileCfg config.FileConfig, l log.Logger) (link.Receiver, error) { +func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (link.Receiver, error) { src := srcCfg.(chain.BaseConfig) - return newBTP2(src, dstCfg.GetAddress(), src.Endpoint, fileCfg, l) + return newBTP2(src, dstAddr, src.Endpoint, baseDir, l) } -func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { +func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) @@ -80,7 +70,7 @@ func NewSender(srcCfg, dstCfg link.ChainConfig, l log.Logger) (types.Sender, err return nil, err } - return icon.NewSender(srcCfg.GetAddress(), dst, w, dst.Endpoint, dst.Options, l), nil + return icon.NewSender(srcAddr, dst, w, dst.Endpoint, dst.Options, l), nil } func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 8992d0e..a4a990b 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -25,7 +25,6 @@ import ( "github.com/spf13/cobra" "github.com/icon-project/btp2/common/cli" - "github.com/icon-project/btp2/common/link" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/relay" ) @@ -48,7 +47,7 @@ var logoLines = []string{ func main() { rootCmd, rootVc := cli.NewCommand(nil, nil, "relay", "BTP Relay CLI") - cfg := &link.Config{} + cfg := &relay.Config{} rootCmd.Long = "Command Line Interface of Relay for Blockchain Transmission Protocol" cli.SetEnvKeyReplacer(rootVc, strings.NewReplacer(".", "_")) //rootVc.Debug() @@ -93,8 +92,8 @@ func main() { rootPFlags.StringP("config", "c", "", "Parsing configuration file") //Chains Config - rootPFlags.StringToString("chains_config.src", nil, "Source chain config") - rootPFlags.StringToString("chains_config.dst", nil, "Destination chain config") + rootPFlags.String("chains_config.src", "", "Source chain config") + rootPFlags.String("chains_config.dst", "", "Destination chain config") //RelayConfig rootPFlags.String("relay_config.direction", "both", "relay network direction ( both, front, reverse)") diff --git a/common/link/config.go b/common/link/config.go index d70e26e..c686936 100644 --- a/common/link/config.go +++ b/common/link/config.go @@ -1,32 +1,30 @@ package link import ( - "github.com/icon-project/btp2/common/config" - "github.com/icon-project/btp2/common/log" + "encoding/json" + "github.com/icon-project/btp2/common/types" ) -type RelayConfig struct { - Direction string `json:"direction"` - config.FileConfig `json:",squash"` //instead of `mapstructure:",squash"` - LogLevel string `json:"log_level"` - ConsoleLevel string `json:"console_level"` - LogForwarder *log.ForwarderConfig `json:"log_forwarder,omitempty"` - LogWriter *log.WriterConfig `json:"log_writer,omitempty"` -} - type ChainConfig interface { GetAddress() types.BtpAddress - GetMode() string - GetNetworkID() string + GetType() string } -type ChainsConfigs struct { - Src map[string]interface{} `json:"src"` - Dst map[string]interface{} `json:"dst"` +type ChainConfigCommon struct { + Type string `json:"type"` + Address types.BtpAddress `json:"address"` } -type Config struct { - RelayConfig `json:"relay_config"` - ChainsConfigs `json:"chains_config"` //instead of `mapstructure:",squash"` +func (c *ChainConfigCommon) GetAddress() types.BtpAddress { + return c.Address +} + +func (c *ChainConfigCommon) GetType() string { + return c.Type +} + +type ChainsConfigs struct { + Src json.RawMessage `json:"src"` + Dst json.RawMessage `json:"dst"` } diff --git a/common/link/factory.go b/common/link/factory.go index 5c300ee..c2f7af2 100644 --- a/common/link/factory.go +++ b/common/link/factory.go @@ -1,23 +1,18 @@ package link import ( - "fmt" - stdlog "log" - "sort" + "encoding/json" - "github.com/icon-project/btp2/common/config" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" ) type Factory struct { - GetSupportChain func() []string - GetMode func() string - - GetChainConfig func(dict map[string]interface{}) (ChainConfig, error) - CheckConfig func(cfg ChainConfig) bool - NewReceiver func(srcCfg, dstCfg ChainConfig, fileCfg config.FileConfig, l log.Logger) (Receiver, error) - NewSender func(srcCfg, dstCfg ChainConfig, l log.Logger) (types.Sender, error) + Type string + ParseChainConfig func(raw json.RawMessage) (ChainConfig, error) + NewReceiver func(srcCfg ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (Receiver, error) + NewLink func(srcCfg ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (types.Link, error) + NewSender func(srcAddr types.BtpAddress, dstCfg ChainConfig, l log.Logger) (types.Sender, error) } var factories []*Factory @@ -25,7 +20,7 @@ var factories []*Factory func RegisterFactory(f *Factory) { if f != nil { if checkDuplicates(f) { - return + return //TODO err?? } factories = append(factories, f) } @@ -33,144 +28,67 @@ func RegisterFactory(f *Factory) { func checkDuplicates(f *Factory) bool { for _, cf := range factories { - for _, cfChain := range cf.GetSupportChain() { - if contains(f.GetSupportChain(), cfChain) { - if cf.GetMode() == f.GetMode() { - return true - } - } + if cf.Type == f.Type { + return true } } return false } -func contains(s []string, e string) bool { - i := sort.SearchStrings(s, e) - return i < len(s) && s[i] == e -} - -func ComposeLink(srcCfg, dstCfg map[string]interface{}, relayCfg RelayConfig, modLevels map[string]string) (types.Link, types.Sender, error) { - var err error - - var srcChainCfg ChainConfig - var dstChainCfg ChainConfig - - var srcFactory *Factory - var dstFactory *Factory - - //Receiver - for _, factory := range factories { - srcChainCfg, err = factory.GetChainConfig(srcCfg) - if err != nil { - return nil, nil, err - } - if factory.CheckConfig(srcChainCfg) { - srcFactory = factory - break - } - } - - if srcChainCfg == nil { - return nil, nil, fmt.Errorf("not supported source chain") - } +func CreateLink(srcRaw, dstRaw json.RawMessage, l log.Logger, baseDir string) (types.Link, error) { //Sender - for _, factory := range factories { - dstChainCfg, err = factory.GetChainConfig(dstCfg) - if err != nil { - return nil, nil, err - } - if factory.CheckConfig(dstChainCfg) { - dstFactory = factory - break - } - } - - if dstChainCfg == nil { - return nil, nil, fmt.Errorf("not supported destination chain") - } - - logger := setLogger(srcChainCfg, relayCfg, modLevels) - logger.Debugln(relayCfg.FileConfig.FilePath, relayCfg.FileConfig.BaseDir) - - //new receiver - r, err := srcFactory.NewReceiver(srcChainCfg, dstChainCfg, relayCfg.FileConfig, logger) - if err != nil { - return nil, nil, err - } - - //new sender - s, err := dstFactory.NewSender(srcChainCfg, dstChainCfg, logger) - if err != nil { - return nil, nil, err + var dstCfgCommon ChainConfigCommon + if err := json.Unmarshal(dstRaw, &dstCfgCommon); err != nil { + return nil, err } - l := NewLink(srcChainCfg, dstChainCfg, r, logger) - return l, s, nil -} - -func Start(link types.Link, sender types.Sender, errCh chan error) error { - go func() { - err := link.Start(sender) - select { - case errCh <- err: - default: + for _, f := range factories { + srcCfg, err := f.ParseChainConfig(srcRaw) + if err != nil { + return nil, err } - }() - - return nil -} - -func setLogger(srcCfg ChainConfig, lc RelayConfig, modLevels map[string]string) log.Logger { - l := log.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", srcCfg.GetNetworkID())}) - log.SetGlobalLogger(l) - stdlog.SetOutput(l.WriterLevel(log.WarnLevel)) - if lc.LogWriter != nil { - if lc.LogWriter.Filename == "" { - log.Debugln("LogWriterConfig filename is empty string, will be ignore") - } else { - var lwCfg log.WriterConfig - lwCfg = *lc.LogWriter - lwCfg.Filename = lc.ResolveAbsolute(lwCfg.Filename) - w, err := log.NewWriter(&lwCfg) + if srcCfg != nil { + link, err := f.NewLink(srcCfg, dstCfgCommon.GetAddress(), baseDir, l) if err != nil { - log.Panicf("Fail to make writer err=%+v", err) + return nil, err } - err = l.SetFileWriter(w) - if err != nil { - log.Panicf("Fail to set file l err=%+v", err) + + if link == nil { + receiver, err := f.NewReceiver(srcCfg, dstCfgCommon.GetAddress(), baseDir, l) + if err != nil { + return nil, err + } + + link = NewLink(srcCfg, receiver, l) } + return link, nil } } - if lv, err := log.ParseLevel(lc.LogLevel); err != nil { - log.Panicf("Invalid log_level=%s", lc.LogLevel) - } else { - l.SetLevel(lv) - } - if lv, err := log.ParseLevel(lc.ConsoleLevel); err != nil { - log.Panicf("Invalid console_level=%s", lc.ConsoleLevel) - } else { - l.SetConsoleLevel(lv) - } + return nil, nil +} - for mod, lvStr := range modLevels { - if lv, err := log.ParseLevel(lvStr); err != nil { - log.Panicf("Invalid mod_level mod=%s level=%s", mod, lvStr) - } else { - l.SetModuleLevel(mod, lv) - } +func CreateSender(srcRaw, dstRaw json.RawMessage, l log.Logger) (types.Sender, error) { + //Sender + var srcCfgCommon ChainConfigCommon + if err := json.Unmarshal(srcRaw, &srcCfgCommon); err != nil { + return nil, err } - if lc.LogForwarder != nil { - if lc.LogForwarder.Vendor == "" && lc.LogForwarder.Address == "" { - log.Debugln("LogForwarderConfig vendor and address is empty string, will be ignore") - } else { - if err := log.AddForwarder(lc.LogForwarder); err != nil { - log.Fatalf("Invalid log_forwarder err:%+v", err) + for _, f := range factories { + dstCfg, err := f.ParseChainConfig(dstRaw) + if err != nil { + return nil, err + } + if dstCfg != nil { + s, err := f.NewSender(srcCfgCommon.GetAddress(), dstCfg, l) + if err != nil { + return nil, err } + return s, nil } } - return l + return nil, nil } diff --git a/common/link/link.go b/common/link/link.go index 131cb7e..2180ce6 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -60,18 +60,16 @@ type Link struct { rmi *relayMessageItem limitSize int64 srcCfg ChainConfig - dstCfg ChainConfig bls *types.BMCLinkStatus blsChannel chan *types.BMCLinkStatus relayState RelayState p types.Preference } -func NewLink(srcCfg, dstCfg ChainConfig, r Receiver, l log.Logger) types.Link { +func NewLink(srcCfg ChainConfig, r Receiver, l log.Logger) types.Link { link := &Link{ l: l, srcCfg: srcCfg, - dstCfg: dstCfg, r: r, rms: make([]*relayMessage, 0), rss: make([]ReceiveStatus, 0), @@ -91,7 +89,7 @@ func (l *Link) Start(sender types.Sender) error { l.p = sender.GetPreference() errCh := make(chan error) - if err := l.senderChannel(errCh); err != nil { + if err := l.startSenderChannel(errCh); err != nil { return err } @@ -102,7 +100,7 @@ func (l *Link) Start(sender types.Sender) error { l.bls = bls - if err := l.receiverChannel(errCh); err != nil { + if err := l.startReceiverChannel(errCh); err != nil { return err } @@ -124,7 +122,7 @@ func (l *Link) Stop() { l.r.Stop() } -func (l *Link) receiverChannel(errCh chan error) error { +func (l *Link) startReceiverChannel(errCh chan error) error { once := new(sync.Once) rc, err := l.r.Start(l.bls) if err != nil { @@ -143,14 +141,14 @@ func (l *Link) receiverChannel(errCh chan error) error { errCh <- err } - if err = l.HandleRelayMessage(); err != nil { + if err = l.handleRelayMessage(); err != nil { errCh <- err } l.relayState = PENDING }) if l.bls.Verifier.Height < rs.Height() { - if err = l.HandleRelayMessage(); err != nil { + if err = l.handleRelayMessage(); err != nil { errCh <- err } } @@ -168,7 +166,7 @@ func (l *Link) receiverChannel(errCh chan error) error { return nil } -func (l *Link) senderChannel(errCh chan error) error { +func (l *Link) startSenderChannel(errCh chan error) error { l.limitSize = l.p.TxSizeLimit - l.p.MarginForLimit rcc, err := l.s.Start() if err != nil { @@ -265,7 +263,7 @@ func (l *Link) appendRelayMessage() error { } rm := &relayMessage{ - id: l.srcCfg.GetNetworkID() + "_" + strconv.FormatInt(l.bls.Verifier.Height, 16) + "_" + strconv.FormatInt(l.bls.RxSeq, 16), + id: l.srcCfg.GetAddress().NetworkID() + "_" + strconv.FormatInt(l.bls.Verifier.Height, 16) + "_" + strconv.FormatInt(l.bls.RxSeq, 16), bls: &types.BMCLinkStatus{}, message: m, rmis: rmi, @@ -286,7 +284,7 @@ func (l *Link) appendRelayMessage() error { return nil } -func (l *Link) HandleRelayMessage() error { +func (l *Link) handleRelayMessage() error { l.rmsMtx.Lock() defer l.rmsMtx.Unlock() if l.relayState == RUNNING { @@ -506,7 +504,7 @@ func (l *Link) successRelayMessage(id string) error { l.relayState = RUNNING - if err := l.HandleRelayMessage(); err != nil { + if err := l.handleRelayMessage(); err != nil { return err } l.blsChannel <- rm.BMCLinkStatus() @@ -543,7 +541,7 @@ func (l *Link) result(rr *types.RelayResult) error { l.updateBMCLinkStatus() l.removeAllRelayMessage() l.relayState = RUNNING - l.HandleRelayMessage() + l.handleRelayMessage() } case errors.BMVAlreadyVerified: if rr.Finalized != true { @@ -556,7 +554,7 @@ func (l *Link) result(rr *types.RelayResult) error { l.removeAllRelayMessage() } else { if l.rms[index].sendingStatus == false { - if err := l.HandleRelayMessage(); err != nil { + if err := l.handleRelayMessage(); err != nil { return err } } diff --git a/common/relay/config.go b/common/relay/config.go new file mode 100644 index 0000000..5bfc37f --- /dev/null +++ b/common/relay/config.go @@ -0,0 +1,21 @@ +package relay + +import ( + "github.com/icon-project/btp2/common/config" + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/log" +) + +type RelayConfig struct { + Direction string `json:"direction"` + config.FileConfig `json:",squash"` //instead of `mapstructure:",squash"` + LogLevel string `json:"log_level"` + ConsoleLevel string `json:"console_level"` + LogForwarder *log.ForwarderConfig `json:"log_forwarder,omitempty"` + LogWriter *log.WriterConfig `json:"log_writer,omitempty"` +} + +type Config struct { + RelayConfig `json:"relay_config"` + link.ChainsConfigs `json:"chains_config"` //instead of `mapstructure:",squash"` +} diff --git a/common/relay/relay.go b/common/relay/relay.go index 7b60cf1..a1eb582 100644 --- a/common/relay/relay.go +++ b/common/relay/relay.go @@ -1,7 +1,12 @@ package relay import ( + "encoding/json" + "fmt" + stdlog "log" + "github.com/icon-project/btp2/common/link" + "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" ) @@ -16,49 +21,73 @@ type linkFactory struct { sender types.Sender } type Relay struct { - lfs []linkFactory + lfs []*linkFactory } -func NewRelay(cfg *link.Config, modLevels map[string]string) (*Relay, error) { +func NewRelay(cfg *Config, modLevels map[string]string) (*Relay, error) { r := &Relay{ - lfs: make([]linkFactory, 0), + lfs: make([]*linkFactory, 0), } switch cfg.Direction { case FrontDirection: - l, s, err := link.ComposeLink(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) + lf, err := newLinkFactory(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) if err != nil { return nil, err } - r.lfs = append(r.lfs, linkFactory{link: l, sender: s}) + + r.lfs = append(r.lfs, lf) case ReverseDirection: - l, s, err := link.ComposeLink(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) + lf, err := newLinkFactory(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) if err != nil { return nil, err } - r.lfs = append(r.lfs, linkFactory{link: l, sender: s}) + + r.lfs = append(r.lfs, lf) + case BothDirection: - frontL, frontS, err := link.ComposeLink(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) + frontLf, err := newLinkFactory(cfg.Src, cfg.Dst, cfg.RelayConfig, modLevels) if err != nil { return nil, err } - r.lfs = append(r.lfs, linkFactory{link: frontL, sender: frontS}) - reverseL, reverseS, err := link.ComposeLink(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) + r.lfs = append(r.lfs, frontLf) + + reverseLf, err := newLinkFactory(cfg.Dst, cfg.Src, cfg.RelayConfig, modLevels) if err != nil { return nil, err } - r.lfs = append(r.lfs, linkFactory{link: reverseL, sender: reverseS}) + + r.lfs = append(r.lfs, reverseLf) } return r, nil } +func newLinkFactory(srcRaw, dstRaw json.RawMessage, relayCfg RelayConfig, modLevels map[string]string) (*linkFactory, error) { + logger, err := setLogger(srcRaw, relayCfg, modLevels) + if err != nil { + return nil, err + } + + l, err := link.CreateLink(srcRaw, dstRaw, logger, relayCfg.BaseDir) + if err != nil { + return nil, err + } + + s, err := link.CreateSender(srcRaw, dstRaw, logger) + if err != nil { + return nil, err + } + + return &linkFactory{link: l, sender: s}, nil +} + func (r *Relay) Start() error { linkErrCh := make(chan error) for _, lf := range r.lfs { - if err := link.Start(lf.link, lf.sender, linkErrCh); err != nil { + if err := start(lf.link, lf.sender, linkErrCh); err != nil { return err } } @@ -72,3 +101,74 @@ func (r *Relay) Start() error { } } } + +func start(link types.Link, sender types.Sender, errCh chan error) error { + err := link.Start(sender) + go func() { + select { + case errCh <- err: + default: + } + }() + + return nil +} + +func setLogger(srcRaw json.RawMessage, lc RelayConfig, modLevels map[string]string) (log.Logger, error) { + var srcCfgCommon link.ChainConfigCommon + if err := json.Unmarshal(srcRaw, &srcCfgCommon); err != nil { + return nil, err + } + + l := log.WithFields(log.Fields{log.FieldKeyChain: fmt.Sprintf("%s", srcCfgCommon.GetAddress().NetworkID())}) + log.SetGlobalLogger(l) + stdlog.SetOutput(l.WriterLevel(log.WarnLevel)) + if lc.LogWriter != nil { + if lc.LogWriter.Filename == "" { + log.Debugln("LogWriterConfig filename is empty string, will be ignore") + } else { + var lwCfg log.WriterConfig + lwCfg = *lc.LogWriter + lwCfg.Filename = lc.ResolveAbsolute(lwCfg.Filename) + w, err := log.NewWriter(&lwCfg) + if err != nil { + log.Panicf("Fail to make writer err=%+v", err) + } + err = l.SetFileWriter(w) + if err != nil { + log.Panicf("Fail to set file l err=%+v", err) + } + } + } + + if lv, err := log.ParseLevel(lc.LogLevel); err != nil { + log.Panicf("Invalid log_level=%s", lc.LogLevel) + } else { + l.SetLevel(lv) + } + if lv, err := log.ParseLevel(lc.ConsoleLevel); err != nil { + log.Panicf("Invalid console_level=%s", lc.ConsoleLevel) + } else { + l.SetConsoleLevel(lv) + } + + for mod, lvStr := range modLevels { + if lv, err := log.ParseLevel(lvStr); err != nil { + log.Panicf("Invalid mod_level mod=%s level=%s", mod, lvStr) + } else { + l.SetModuleLevel(mod, lv) + } + } + + if lc.LogForwarder != nil { + if lc.LogForwarder.Vendor == "" && lc.LogForwarder.Address == "" { + log.Debugln("LogForwarderConfig vendor and address is empty string, will be ignore") + } else { + if err := log.AddForwarder(lc.LogForwarder); err != nil { + log.Fatalf("Invalid log_forwarder err:%+v", err) + } + } + } + + return l, nil +} From 2d9ce46c97defa3a6c65a6a8f3346eb25cddc022 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Tue, 25 Jul 2023 10:35:13 +0900 Subject: [PATCH 10/22] Fix bug in relay --- common/relay/relay.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/relay/relay.go b/common/relay/relay.go index a1eb582..80c5215 100644 --- a/common/relay/relay.go +++ b/common/relay/relay.go @@ -103,8 +103,8 @@ func (r *Relay) Start() error { } func start(link types.Link, sender types.Sender, errCh chan error) error { - err := link.Start(sender) go func() { + err := link.Start(sender) select { case errCh <- err: default: From 146bb5f80bd22982b3b09d6254abd23362d51f06 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Tue, 25 Jul 2023 11:30:32 +0900 Subject: [PATCH 11/22] Change factory type in eth bridge --- chain/ethbr/ethbrfactory.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/ethbr/ethbrfactory.go b/chain/ethbr/ethbrfactory.go index 8d0601e..d6548b6 100644 --- a/chain/ethbr/ethbrfactory.go +++ b/chain/ethbr/ethbrfactory.go @@ -11,9 +11,9 @@ import ( "github.com/icon-project/btp2/common/wallet" ) -const TYPE = "bsc-bridge-solidity" +const TYPE = "eth-bridge-solidity" -func RegisterIconEthBr() { +func RegisterEthBridge() { link.RegisterFactory(&link.Factory{ Type: TYPE, ParseChainConfig: ParseChainConfig, From 1a923453bdbbb6a92eb4ae65b5187e1a2bdf5135 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Thu, 27 Jul 2023 09:27:52 +0900 Subject: [PATCH 12/22] Delete init.go --- cmd/relay/init.go | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 cmd/relay/init.go diff --git a/cmd/relay/init.go b/cmd/relay/init.go deleted file mode 100644 index 1739c0b..0000000 --- a/cmd/relay/init.go +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "github.com/icon-project/btp2/chain/ethbr" - "github.com/icon-project/btp2/chain/icon/bridge" - "github.com/icon-project/btp2/chain/icon/btp2" -) - -func init() { - bridge.RegisterIconBridge() - btp2.RegisterIconBtp2() - ethbr.RegisterIconEthBr() -} From a3d7660433c70c1b02a8353de8c5681511cf3d39 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Thu, 27 Jul 2023 10:03:14 +0900 Subject: [PATCH 13/22] Add factory init in relay --- cmd/relay/main.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/relay/main.go b/cmd/relay/main.go index a4a990b..63294cd 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -24,6 +24,9 @@ import ( "github.com/spf13/cobra" + "github.com/icon-project/btp2/chain/ethbr" + "github.com/icon-project/btp2/chain/icon/bridge" + "github.com/icon-project/btp2/chain/icon/btp2" "github.com/icon-project/btp2/common/cli" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/relay" @@ -45,6 +48,12 @@ var logoLines = []string{ " |___/ ", } +func init() { + bridge.RegisterIconBridge() + btp2.RegisterIconBtp2() + ethbr.RegisterEthBridge() +} + func main() { rootCmd, rootVc := cli.NewCommand(nil, nil, "relay", "BTP Relay CLI") cfg := &relay.Config{} From 65e1eec5185268f0e3294fdb6df2492e84e2c33b Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Thu, 27 Jul 2023 10:29:48 +0900 Subject: [PATCH 14/22] Update error channel in relay --- common/link/link.go | 26 +++----------------------- common/relay/relay.go | 11 +++-------- common/types/type.go | 2 +- 3 files changed, 7 insertions(+), 32 deletions(-) diff --git a/common/link/link.go b/common/link/link.go index 2180ce6..eac998b 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -84,12 +84,11 @@ func NewLink(srcCfg ChainConfig, r Receiver, l log.Logger) types.Link { return link } -func (l *Link) Start(sender types.Sender) error { +func (l *Link) Start(sender types.Sender, errChan chan error) error { l.s = sender l.p = sender.GetPreference() - errCh := make(chan error) - if err := l.startSenderChannel(errCh); err != nil { + if err := l.startSenderChannel(errChan); err != nil { return err } @@ -100,20 +99,11 @@ func (l *Link) Start(sender types.Sender) error { l.bls = bls - if err := l.startReceiverChannel(errCh); err != nil { + if err := l.startReceiverChannel(errChan); err != nil { return err } - l.r.FinalizedStatus(l.blsChannel) - for { - select { - case err := <-errCh: - if err != nil { - return err - } - } - } return nil } @@ -157,11 +147,6 @@ func (l *Link) startReceiverChannel(errCh chan error) error { } } } - - select { - case errCh <- err: - default: - } }() return nil } @@ -180,11 +165,6 @@ func (l *Link) startSenderChannel(errCh chan error) error { errCh <- err } } - - select { - case errCh <- err: - default: - } }() return nil } diff --git a/common/relay/relay.go b/common/relay/relay.go index 80c5215..53521bc 100644 --- a/common/relay/relay.go +++ b/common/relay/relay.go @@ -103,14 +103,9 @@ func (r *Relay) Start() error { } func start(link types.Link, sender types.Sender, errCh chan error) error { - go func() { - err := link.Start(sender) - select { - case errCh <- err: - default: - } - }() - + if err := link.Start(sender, errCh); err != nil { + return err + } return nil } diff --git a/common/types/type.go b/common/types/type.go index a23fe96..99d3a4d 100644 --- a/common/types/type.go +++ b/common/types/type.go @@ -37,7 +37,7 @@ type Wallet interface { } type Link interface { - Start(sender Sender) error + Start(sender Sender, errChan chan error) error Stop() } From 8998818ff0b2dfd4ccc0846001dac013fe4dac09 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Thu, 27 Jul 2023 10:58:25 +0900 Subject: [PATCH 15/22] Add log in relay --- chain/ethbr/receiver.go | 3 +++ chain/ethbr/sender.go | 2 +- chain/icon/bridge/bridge.go | 4 +++- chain/icon/btp2/btp2.go | 4 ++++ chain/icon/sender.go | 4 ++-- common/link/link.go | 11 ++++++++++- common/link/type.go | 4 ++-- 7 files changed, 25 insertions(+), 7 deletions(-) diff --git a/chain/ethbr/receiver.go b/chain/ethbr/receiver.go index b4d3d7b..d16698b 100644 --- a/chain/ethbr/receiver.go +++ b/chain/ethbr/receiver.go @@ -146,6 +146,7 @@ func (e *ethbr) prepareDatabase(baseDir string) (db.Bucket, error) { return nil, err } e.receiveHeight = new(big.Int).SetBytes(h).Int64() + e.l.Debugf("Database has height data (height:%d)", e.receiveHeight) } return bk, nil } @@ -169,6 +170,7 @@ func (e *ethbr) GetStatus() (link.ReceiveStatus, error) { } func (e *ethbr) BuildBlockUpdate(bls *btpTypes.BMCLinkStatus, limit int64) ([]link.BlockUpdate, error) { + e.l.Debugf("Build BlockUpdate (height=%d, rxSeq=%d)", bls.Verifier.Height, bls.RxSeq) bus := make([]link.BlockUpdate, 0) rs := e.nextReceiveStatus(bls) if rs == nil { @@ -185,6 +187,7 @@ func (e *ethbr) BuildBlockProof(bls *btpTypes.BMCLinkStatus, height int64) (link } func (e *ethbr) BuildMessageProof(bls *btpTypes.BMCLinkStatus, limit int64) (link.MessageProof, error) { + e.l.Debugf("Build BuildMessageProof (height=%d, rxSeq=%d)", bls.Verifier.Height, bls.RxSeq) var rmSize int seq := bls.RxSeq + 1 rps := make([]*client.ReceiptProof, 0) diff --git a/chain/ethbr/sender.go b/chain/ethbr/sender.go index 6b618ba..a70ed0d 100644 --- a/chain/ethbr/sender.go +++ b/chain/ethbr/sender.go @@ -175,7 +175,7 @@ func (s *sender) result(id string, txh *client.TransactionHashParam) { s.queue.dequeue(id) if err != nil { - s.l.Debugf("result fail rm id : %d , txHash : %v", id, txh.Hash) + s.l.Debugf("result fail rm id : %s , txHash : %v", id, txh.Hash) if ec, ok := errors.CoderOf(err); ok { s.rr <- &btpTypes.RelayResult{ diff --git a/chain/icon/bridge/bridge.go b/chain/icon/bridge/bridge.go index 764bb4c..5578923 100644 --- a/chain/icon/bridge/bridge.go +++ b/chain/icon/bridge/bridge.go @@ -134,6 +134,7 @@ func (b *bridge) GetHeightForSeq(seq int64) int64 { } func (b *bridge) BuildBlockUpdate(bls *types.BMCLinkStatus, limit int64) ([]link.BlockUpdate, error) { + b.l.Debugf("Build BlockUpdate (height=%d, rxSeq=%d)", bls.Verifier.Height, bls.RxSeq) bus := make([]link.BlockUpdate, 0) rs := b.nextReceiveStatus(bls) bu := newBlockUpdate(bls, rs.Height()) @@ -146,6 +147,7 @@ func (b *bridge) BuildBlockProof(bls *types.BMCLinkStatus, height int64) (link.B } func (b *bridge) BuildMessageProof(bls *types.BMCLinkStatus, limit int64) (link.MessageProof, error) { + b.l.Debugf("Build BuildMessageProof (height=%d, rxSeq=%d)", bls.Verifier.Height, bls.RxSeq) var rmSize int rs := b.GetReceiveStatusForSequence(bls.RxSeq + 1) if rs == nil { @@ -179,7 +181,7 @@ func (b *bridge) BuildRelayMessage(rmis []link.RelayMessageItem) ([]byte, error) for _, rmi := range rmis { if rmi.Type() == link.TypeMessageProof { mp := rmi.(*MessageProof) - b.l.Debugf("BuildRelayMessage height:%d data:%s ", mp.nextBls.Verifier.Height, + b.l.Debugf("BuildRelayMessage (height:%d, data:%s ", mp.nextBls.Verifier.Height, base64.URLEncoding.EncodeToString(mp.Bytes())) return mp.Bytes(), nil diff --git a/chain/icon/btp2/btp2.go b/chain/icon/btp2/btp2.go index 08efd58..addda23 100644 --- a/chain/icon/btp2/btp2.go +++ b/chain/icon/btp2/btp2.go @@ -111,6 +111,7 @@ func (b *btp2) prepareDatabase(baseDir string) (db.Bucket, error) { return nil, err } b.receiveHeight = new(big.Int).SetBytes(h).Int64() + b.l.Debugf("Database has height data (height:%d)", b.receiveHeight) } return bk, nil } @@ -187,6 +188,7 @@ func (b *btp2) GetHeightForSeq(seq int64) int64 { } func (b *btp2) BuildBlockUpdate(bls *types.BMCLinkStatus, limit int64) ([]link.BlockUpdate, error) { + b.l.Debugf("Build BlockUpdate (height:%d, rxSeq:%d)", bls.Verifier.Height, bls.RxSeq) bus := make([]link.BlockUpdate, 0) rs := b.nextReceiveStatus(bls) if rs == nil { @@ -217,6 +219,7 @@ func (b *btp2) BuildBlockProof(bls *types.BMCLinkStatus, height int64) (link.Blo } func (b *btp2) BuildMessageProof(bls *types.BMCLinkStatus, limit int64) (link.MessageProof, error) { + b.l.Debugf("Build BuildMessageProof (height:%d, rxSeq:%d)", bls.Verifier.Height, bls.RxSeq) rs := b.GetReceiveStatusForHeight(bls.Verifier.Height) if rs == nil { @@ -266,6 +269,7 @@ func (b *btp2) BuildRelayMessage(rmis []link.RelayMessageItem) ([]byte, error) { return nil, err } + b.l.Debugf("BuildRelayMessage (type:%d, len:%d)", rmi.Type(), rmi.Len()) bm.Messages = append(bm.Messages, tpm) } diff --git a/chain/icon/sender.go b/chain/icon/sender.go index c1111c5..d7c5218 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -141,7 +141,7 @@ func (s *sender) Relay(rm types.RelayMessage) (string, error) { if MaxQueueSize <= s.queue.len() { return "", errors.InvalidStateError.New("pending queue full") } - s.l.Debugf("_relay src address:%s, rm id:%d, rm msg:%s", s.srcAddr.String(), rm.Id(), hex.EncodeToString(rm.Bytes()[:])) + s.l.Debugf("_relay src address:%s, rm id:%s, rm msg:%s", s.srcAddr.String(), rm.Id(), hex.EncodeToString(rm.Bytes()[:])) thp, err := s._relay(rm) if err != nil { @@ -193,7 +193,7 @@ func (s *sender) result(id string, txh *client.TransactionHashParam) { s.queue.dequeue(id) if err != nil { - s.l.Debugf("result fail rm id : %d , txHash : %v", id, txh.Hash) + s.l.Debugf("result fail rm id : %s , txHash : %v", id, txh.Hash) if ec, ok := errors.CoderOf(err); ok { s.rr <- &types.RelayResult{ diff --git a/common/link/link.go b/common/link/link.go index eac998b..84e5bb3 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -126,6 +126,7 @@ func (l *Link) startReceiverChannel(errCh chan error) error { case ReceiveStatus: rs := t.(ReceiveStatus) l.rss = append(l.rss, t) + l.l.Debugf("ReceiveStatus (height:%d, seq:%d)", rs.Height(), rs.Seq()) once.Do(func() { if err = l.handleUndeliveredRelayMessage(); err != nil { errCh <- err @@ -170,6 +171,7 @@ func (l *Link) startSenderChannel(errCh chan error) error { } func (l *Link) buildRelayMessage() error { + l.l.Debugf("BuildRelayMessage (bls height:%d, bls rx seq:%d)", l.bls.Verifier.Height, l.bls.RxSeq) if len(l.rmi.rmis) == 0 { l.resetRelayMessageItem() } @@ -219,6 +221,8 @@ func (l *Link) buildRelayMessage() error { func (l *Link) sendRelayMessage() error { for _, rm := range l.rms { if rm.sendingStatus == false { + l.l.Debugf("SendRelayMessage (bls height:%d, bls txSeq:%d, bls rxSeq:%d)", + rm.bls.Verifier.Height, rm.bls.TxSeq, rm.bls.RxSeq) _, err := l.s.Relay(rm) if err != nil { if errors.InvalidStateError.Equals(err) { @@ -256,6 +260,8 @@ func (l *Link) appendRelayMessage() error { rm.sendingStatus = false l.rms = append(l.rms, rm) + l.l.Debugf("AppendRelayMessage (bls height:%d, bls txSeq:%d, bls rxSeq:%d)", + rm.bls.Verifier.Height, rm.bls.TxSeq, rm.bls.RxSeq) } l.rmi.rmis = l.rmi.rmis[:0] @@ -279,6 +285,7 @@ func (l *Link) handleRelayMessage() error { l.buildRelayMessage() l.sendRelayMessage() } else { + l.l.Debugf("Relay status : %d, ReceiveStatus size: %d", l.relayState, len(l.rss)) break } } @@ -287,6 +294,7 @@ func (l *Link) handleRelayMessage() error { } func (l *Link) buildBlockUpdates(bs *types.BMCLinkStatus) ([]BlockUpdate, error) { + l.l.Debugf("BuildBlockUpdates (bls height:%d, bls rxSeq:%d)", l.bls.Verifier.Height, l.bls.RxSeq) for { bus, err := l.r.BuildBlockUpdate(bs, l.limitSize-l.rmi.size) if err != nil { @@ -304,7 +312,7 @@ func (l *Link) handleUndeliveredRelayMessage() error { return nil } for l.bls.RxSeq < rs.Seq() { - l.l.Debugf("handleUndeliveredRelayMessage ReceiveStatus(height : %d, seq : %s), BMCLinkStatus(height : %d, seq : %s)", + l.l.Debugf("HandleUndeliveredRelayMessage ReceiveStatus(height : %d, seq : %s), BMCLinkStatus(height : %d, seq : %s)", rs.Height(), rs.Seq(), l.bls.Verifier.Height, l.bls.RxSeq) _, err := l.buildProof(nil) if err != nil { @@ -319,6 +327,7 @@ func (l *Link) handleUndeliveredRelayMessage() error { } func (l *Link) buildProof(bu BlockUpdate) (int64, error) { + l.l.Debugf("BuildProof (bls height:%d, bls rx seq:%d)", l.bls.Verifier.Height, l.bls.RxSeq) var mpLen int64 rs := l.getReceiveStatusForHeight(l.bls.Verifier.Height) if rs == nil { diff --git a/common/link/type.go b/common/link/type.go index cbc3136..4eb8a05 100644 --- a/common/link/type.go +++ b/common/link/type.go @@ -52,8 +52,8 @@ type BlockProof interface { type MessageProof interface { RelayMessageItem - StartSeqNum() int64 //TODO change - LastSeqNum() int64 //TODO change + StartSeqNum() int64 + LastSeqNum() int64 } type Receiver interface { From da68ac12bbaec8b9ffb5860bce308de8792534f8 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Thu, 27 Jul 2023 11:11:03 +0900 Subject: [PATCH 16/22] Add error handling in link --- common/link/link.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/common/link/link.go b/common/link/link.go index aed5a49..6c04f97 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -283,8 +283,14 @@ func (l *Link) handleRelayMessage() error { if l.relayState == RUNNING && len(l.rss) != 0 && l.bls.Verifier.Height < l.rss[len(l.rss)-1].Height() { - l.buildRelayMessage() - l.sendRelayMessage() + if err := l.buildRelayMessage(); err != nil { + return err + } + + if err := l.sendRelayMessage(); err != nil { + return err + } + } else { l.l.Debugf("Relay status : %d, ReceiveStatus size: %d", l.relayState, len(l.rss)) break @@ -516,10 +522,14 @@ func (l *Link) result(rr *types.RelayResult) error { switch rr.Err { case errors.SUCCESS: if l.p.LatestResult == true { - l.successRelayMessage(rr.Id) + if err := l.successRelayMessage(rr.Id); err != nil { + return err + } } else { if rr.Finalized == true { - l.successRelayMessage(rr.Id) + if err := l.successRelayMessage(rr.Id); err != nil { + return err + } } } case errors.BMVUnknown: @@ -531,7 +541,9 @@ func (l *Link) result(rr *types.RelayResult) error { l.updateBMCLinkStatus() l.removeAllRelayMessage() l.relayState = RUNNING - l.handleRelayMessage() + if err := l.handleRelayMessage(); err != nil { + return err + } } case errors.BMVAlreadyVerified: if rr.Finalized != true { From c4a9fce160a71e57831acd2f4d5e4b45c3fef5dc Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Thu, 27 Jul 2023 11:57:32 +0900 Subject: [PATCH 17/22] Clean up code in relay --- chain/ethbr/receiver.go | 22 +++++++++------------- chain/icon/bridge/bridge.go | 12 ++++++------ chain/icon/btp2/btp2.go | 19 +++++++++++-------- chain/icon/sender.go | 2 +- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/chain/ethbr/receiver.go b/chain/ethbr/receiver.go index d16698b..ecd303c 100644 --- a/chain/ethbr/receiver.go +++ b/chain/ethbr/receiver.go @@ -60,12 +60,8 @@ func newReceiveStatus(height, startSeq, lastSeq int64, rps []*client.ReceiptProo } const ( - DefaultDBType = db.GoLevelDBBackend - EPOCH = 200 - EventSignature = "Message(string,uint256,bytes)" - EventIndexSignature = 0 - EventIndexNext = 1 - EventIndexSequence = 2 + DefaultDBType = db.GoLevelDBBackend + EventSignature = "Message(string,uint256,bytes)" ) type ethbr struct { @@ -153,7 +149,7 @@ func (e *ethbr) prepareDatabase(baseDir string) (db.Bucket, error) { func (e *ethbr) Start(bls *btpTypes.BMCLinkStatus) (<-chan interface{}, error) { go func() { - err := e.Monitoring(bls) + err := e.monitoring(bls) e.l.Debugf("Unknown monitoring error occurred (err : %v)", err) e.rsc <- err }() @@ -191,7 +187,7 @@ func (e *ethbr) BuildMessageProof(bls *btpTypes.BMCLinkStatus, limit int64) (lin var rmSize int seq := bls.RxSeq + 1 rps := make([]*client.ReceiptProof, 0) - rs := e.GetReceiveStatusForSequence(seq) + rs := e.getReceiveStatusForSequence(seq) if rs == nil { return nil, nil } @@ -238,7 +234,7 @@ func (e *ethbr) BuildMessageProof(bls *btpTypes.BMCLinkStatus, limit int64) (lin } func (e *ethbr) GetHeightForSeq(seq int64) int64 { - rs := e.GetReceiveStatusForSequence(seq) + rs := e.getReceiveStatusForSequence(seq) if rs != nil { return rs.height } else { @@ -292,7 +288,7 @@ func (e *ethbr) clearReceiveStatus(bls *btpTypes.BMCLinkStatus) { } } -func (e *ethbr) Monitoring(bls *btpTypes.BMCLinkStatus) error { +func (e *ethbr) monitoring(bls *btpTypes.BMCLinkStatus) error { var height int64 fq := ðereum.FilterQuery{ Addresses: []common.Address{common.HexToAddress(e.src.GetAddress().ContractAddress())}, @@ -326,7 +322,7 @@ func (e *ethbr) Monitoring(bls *btpTypes.BMCLinkStatus) error { ls.RxSeq = e.seq ls.Verifier.Height = height e.l.Debugf("Restart Monitoring") - e.Monitoring(ls) + e.monitoring(ls) } return e.c.MonitorBlock(br, @@ -432,7 +428,7 @@ func (e *ethbr) newBlockUpdate(v *client.BlockNotification) (*client.BlockUpdate return bu, nil } -func (e *ethbr) GetReceiveStatusForSequence(seq int64) *receiveStatus { +func (e *ethbr) getReceiveStatusForSequence(seq int64) *receiveStatus { for _, rs := range e.rss { if rs.startSeq <= seq && seq <= rs.lastSeq { return rs @@ -441,7 +437,7 @@ func (e *ethbr) GetReceiveStatusForSequence(seq int64) *receiveStatus { return nil } -func (e *ethbr) GetReceiveStatusForHeight(height int64) *receiveStatus { +func (e *ethbr) getReceiveStatusForHeight(height int64) *receiveStatus { for _, rs := range e.rss { if rs.Height() == height { return rs diff --git a/chain/icon/bridge/bridge.go b/chain/icon/bridge/bridge.go index 5578923..c17cd65 100644 --- a/chain/icon/bridge/bridge.go +++ b/chain/icon/bridge/bridge.go @@ -108,7 +108,7 @@ func (b *bridge) Start(bls *types.BMCLinkStatus) (<-chan interface{}, error) { } go func() { - err := b.Monitoring(bls) + err := b.monitoring(bls) b.l.Debugf("Unknown monitoring error occurred (err : %v)", err) b.rsc <- err }() @@ -125,7 +125,7 @@ func (b *bridge) GetStatus() (link.ReceiveStatus, error) { } func (b *bridge) GetHeightForSeq(seq int64) int64 { - rs := b.GetReceiveStatusForSequence(seq) + rs := b.getReceiveStatusForSequence(seq) if rs != nil { return rs.height } else { @@ -149,7 +149,7 @@ func (b *bridge) BuildBlockProof(bls *types.BMCLinkStatus, height int64) (link.B func (b *bridge) BuildMessageProof(bls *types.BMCLinkStatus, limit int64) (link.MessageProof, error) { b.l.Debugf("Build BuildMessageProof (height=%d, rxSeq=%d)", bls.Verifier.Height, bls.RxSeq) var rmSize int - rs := b.GetReceiveStatusForSequence(bls.RxSeq + 1) + rs := b.getReceiveStatusForSequence(bls.RxSeq + 1) if rs == nil { return nil, nil } @@ -201,7 +201,7 @@ func (b *bridge) FinalizedStatus(blsc <-chan *types.BMCLinkStatus) { }() } -func (b *bridge) Monitoring(bls *types.BMCLinkStatus) error { +func (b *bridge) monitoring(bls *types.BMCLinkStatus) error { if bls.Verifier.Height < 1 { return fmt.Errorf("cannot catchup from zero height") } @@ -220,7 +220,7 @@ func (b *bridge) Monitoring(bls *types.BMCLinkStatus) error { ls.RxSeq = b.rs.Seq() ls.Verifier.Height = b.rs.Height() b.l.Debugf("Restart Monitoring") - b.Monitoring(ls) + b.monitoring(ls) } onConn := func(conn *websocket.Conn) { b.l.Debugf("ReceiveLoop monitorBTP2Block height:%d seq:%d networkId:%d connected %s", @@ -301,7 +301,7 @@ func (b *bridge) clearReceiveStatus(bls *types.BMCLinkStatus) { } } -func (b *bridge) GetReceiveStatusForSequence(seq int64) *receiveStatus { +func (b *bridge) getReceiveStatusForSequence(seq int64) *receiveStatus { for _, rs := range b.rss { if rs.Seq() <= seq && seq <= rs.Seq() { return rs diff --git a/chain/icon/btp2/btp2.go b/chain/icon/btp2/btp2.go index addda23..3debcaf 100644 --- a/chain/icon/btp2/btp2.go +++ b/chain/icon/btp2/btp2.go @@ -162,7 +162,7 @@ func (b *btp2) Start(bls *types.BMCLinkStatus) (<-chan interface{}, error) { } go func() { - err := b.Monitoring(bls) + err := b.monitoring(bls) b.l.Debugf("Unknown monitoring error occurred (err : %v)", err) b.rsc <- err }() @@ -179,7 +179,7 @@ func (b *btp2) GetStatus() (link.ReceiveStatus, error) { } func (b *btp2) GetHeightForSeq(seq int64) int64 { - rs := b.GetReceiveStatusForSequence(seq) + rs := b.getReceiveStatusForSequence(seq) if rs != nil { return rs.height } else { @@ -220,7 +220,7 @@ func (b *btp2) BuildBlockProof(bls *types.BMCLinkStatus, height int64) (link.Blo func (b *btp2) BuildMessageProof(bls *types.BMCLinkStatus, limit int64) (link.MessageProof, error) { b.l.Debugf("Build BuildMessageProof (height:%d, rxSeq:%d)", bls.Verifier.Height, bls.RxSeq) - rs := b.GetReceiveStatusForHeight(bls.Verifier.Height) + rs := b.getReceiveStatusForHeight(bls.Verifier.Height) if rs == nil { return nil, nil @@ -335,7 +335,7 @@ func (b *btp2) getMessage(height int64) (*mbt.MerkleBinaryTree, error) { return mt, nil } -func (b *btp2) Monitoring(bls *types.BMCLinkStatus) error { +func (b *btp2) monitoring(bls *types.BMCLinkStatus) error { var height int64 if bls.Verifier.Height < 1 { @@ -363,11 +363,11 @@ func (b *btp2) Monitoring(bls *types.BMCLinkStatus) error { ls.RxSeq = b.rs.Seq() ls.Verifier.Height = b.rs.Height() b.l.Debugf("Restart Monitoring") - b.Monitoring(ls) + b.monitoring(ls) } onConn := func(conn *websocket.Conn) { b.l.Debugf("ReceiveLoop monitorBTP2Block height:%d seq:%d networkId:%d connected %s", - bls.Verifier.Height, bls.RxSeq, b.nid, conn.LocalAddr().String()) + height, bls.RxSeq, b.nid, conn.LocalAddr().String()) } err := b.monitorBTP2Block(req, bls, onConn, onErr) @@ -402,6 +402,9 @@ func (b *btp2) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus if v.Progress.Value != 0 { b.receiveHeight = v.Progress.Value b.setHeightToDatabase() + } + + if len(v.Header) == 0 { return nil } @@ -431,7 +434,7 @@ func (b *btp2) monitorBTP2Block(req *client.BTPRequest, bls *types.BMCLinkStatus }, scb, errCb) } -func (b *btp2) GetReceiveStatusForSequence(seq int64) *receiveStatus { +func (b *btp2) getReceiveStatusForSequence(seq int64) *receiveStatus { for _, rs := range b.rss { if rs.Seq() <= seq && seq <= rs.Seq() { return rs @@ -440,7 +443,7 @@ func (b *btp2) GetReceiveStatusForSequence(seq int64) *receiveStatus { return nil } -func (b *btp2) GetReceiveStatusForHeight(height int64) *receiveStatus { +func (b *btp2) getReceiveStatusForHeight(height int64) *receiveStatus { for _, rs := range b.rss { if rs.Height() == height { return rs diff --git a/chain/icon/sender.go b/chain/icon/sender.go index d7c5218..fb9b615 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -262,7 +262,7 @@ func (s *sender) newTransactionParam(method string, params interface{}) *client. FromAddress: client.Address(s.w.Address()), ToAddress: client.Address(s.dstCfg.Address.Account()), NetworkID: client.HexInt(s.dstCfg.Address.NetworkID()), - StepLimit: client.NewHexInt(s.opt.StepLimit), //TODO stepLimit estimate + StepLimit: client.NewHexInt(s.opt.StepLimit), DataType: "call", Data: &client.CallData{ Method: method, From e303f98df8615d86c46b5e239530f59414a0db58 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Mon, 31 Jul 2023 10:48:15 +0900 Subject: [PATCH 18/22] Update chain factory --- chain/config.go | 4 +-- chain/ethbr/ethbrfactory.go | 49 ++++++++++------------------- chain/icon/bridge/bridgefactory.go | 50 ++++++++++-------------------- chain/icon/btp2/btpblockfactory.go | 50 ++++++++++-------------------- 4 files changed, 49 insertions(+), 104 deletions(-) diff --git a/chain/config.go b/chain/config.go index 7c35283..416a94b 100644 --- a/chain/config.go +++ b/chain/config.go @@ -17,15 +17,13 @@ package chain import ( - "encoding/json" - "github.com/icon-project/btp2/common/types" ) type BaseConfig struct { Address types.BtpAddress `json:"address"` Endpoint string `json:"endpoint"` - KeyStoreData json.RawMessage `json:"key_store"` + KeyStore string `json:"key_store"` Type string `json:"type"` KeyStorePass string `json:"key_password,omitempty"` KeySecret string `json:"key_secret,omitempty"` diff --git a/chain/ethbr/ethbrfactory.go b/chain/ethbr/ethbrfactory.go index d6548b6..bf63922 100644 --- a/chain/ethbr/ethbrfactory.go +++ b/chain/ethbr/ethbrfactory.go @@ -2,6 +2,7 @@ package ethbr import ( "encoding/json" + "fmt" "os" "github.com/icon-project/btp2/chain" @@ -11,13 +12,12 @@ import ( "github.com/icon-project/btp2/common/wallet" ) -const TYPE = "eth-bridge-solidity" +const TYPE = "eth-bridge" func RegisterEthBridge() { link.RegisterFactory(&link.Factory{ Type: TYPE, ParseChainConfig: ParseChainConfig, - NewLink: NewLink, NewReceiver: NewReceiver, NewSender: NewSender, }) @@ -25,34 +25,13 @@ func RegisterEthBridge() { func ParseChainConfig(raw json.RawMessage) (link.ChainConfig, error) { cfg := chain.BaseConfig{} - - jsonbody, err := json.Marshal(raw) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(jsonbody, &cfg); err != nil { + if err := json.Unmarshal(raw, &cfg); err != nil { return nil, err } - - //TODO add check - if cfg.Type == TYPE { - return cfg, nil - } - - return nil, nil -} - -func NewLink(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (types.Link, error) { - src := srcCfg.(chain.BaseConfig) - - r, err := newEthBridge(srcCfg, dstAddr, src.Endpoint, l, baseDir, src.Options) - if err != nil { - return nil, err + if cfg.Type != TYPE { + return nil, fmt.Errorf("invalid type (type:%s)", cfg.Type) } - - link := link.NewLink(srcCfg, r, l) - return link, nil + return cfg, nil } func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (link.Receiver, error) { @@ -63,7 +42,7 @@ func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir stri func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) - w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) + w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStore) if err != nil { return nil, err } @@ -71,12 +50,16 @@ func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) return newSender(srcAddr, dst, w, dst.Endpoint, dst.Options, l), nil } -func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { - pw, err := resolvePassword(secret, passwd) - if err != nil { - return nil, err +func newWallet(passwd, secret string, keyStorePath string) (types.Wallet, error) { + if keyStore, err := os.ReadFile(keyStorePath); err != nil { + return nil, fmt.Errorf("fail to open KeyStore file path=%s", keyStorePath) + } else { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) } - return wallet.DecryptKeyStore(keyStore, pw) } func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { diff --git a/chain/icon/bridge/bridgefactory.go b/chain/icon/bridge/bridgefactory.go index fc099ef..12bd1c3 100644 --- a/chain/icon/bridge/bridgefactory.go +++ b/chain/icon/bridge/bridgefactory.go @@ -2,6 +2,7 @@ package bridge import ( "encoding/json" + "fmt" "os" "github.com/icon-project/btp2/chain" @@ -12,13 +13,12 @@ import ( "github.com/icon-project/btp2/common/wallet" ) -const TYPE = "icon-bridge-java" +const TYPE = "icon-bridge" func RegisterIconBridge() { link.RegisterFactory(&link.Factory{ Type: TYPE, ParseChainConfig: ParseChainConfig, - NewLink: NewLink, NewReceiver: NewReceiver, NewSender: NewSender, }) @@ -26,34 +26,13 @@ func RegisterIconBridge() { func ParseChainConfig(raw json.RawMessage) (link.ChainConfig, error) { cfg := chain.BaseConfig{} - - jsonbody, err := json.Marshal(raw) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(jsonbody, &cfg); err != nil { + if err := json.Unmarshal(raw, &cfg); err != nil { return nil, err } - - //TODO add check - if cfg.Type == TYPE { - return cfg, nil + if cfg.Type != TYPE { + return nil, fmt.Errorf("invalid type (type:%s)", cfg.Type) } - - return nil, nil -} - -func NewLink(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (types.Link, error) { - src := srcCfg.(chain.BaseConfig) - - r, err := newBridge(src, dstAddr, src.Endpoint, baseDir, l) - if err != nil { - return nil, err - } - - link := link.NewLink(srcCfg, r, l) - return link, nil + return cfg, nil } func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (link.Receiver, error) { @@ -64,8 +43,7 @@ func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir stri func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) - - w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) + w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStore) if err != nil { return nil, err } @@ -73,12 +51,16 @@ func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) return icon.NewSender(srcAddr, dst, w, dst.Endpoint, dst.Options, l), nil } -func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { - pw, err := resolvePassword(secret, passwd) - if err != nil { - return nil, err +func newWallet(passwd, secret string, keyStorePath string) (types.Wallet, error) { + if keyStore, err := os.ReadFile(keyStorePath); err != nil { + return nil, fmt.Errorf("fail to open KeyStore file path=%s", keyStorePath) + } else { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) } - return wallet.DecryptKeyStore(keyStore, pw) } func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { diff --git a/chain/icon/btp2/btpblockfactory.go b/chain/icon/btp2/btpblockfactory.go index 7abcf31..ff5a5e2 100644 --- a/chain/icon/btp2/btpblockfactory.go +++ b/chain/icon/btp2/btpblockfactory.go @@ -2,6 +2,7 @@ package btp2 import ( "encoding/json" + "fmt" "os" "github.com/icon-project/btp2/chain" @@ -12,13 +13,12 @@ import ( "github.com/icon-project/btp2/common/wallet" ) -const TYPE = "icon-btpblock-java" +const TYPE = "icon-btpblock" func RegisterIconBtp2() { link.RegisterFactory(&link.Factory{ Type: TYPE, ParseChainConfig: ParseChainConfig, - NewLink: NewLink, NewReceiver: NewReceiver, NewSender: NewSender, }) @@ -26,34 +26,13 @@ func RegisterIconBtp2() { func ParseChainConfig(raw json.RawMessage) (link.ChainConfig, error) { cfg := chain.BaseConfig{} - - jsonbody, err := json.Marshal(raw) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(jsonbody, &cfg); err != nil { + if err := json.Unmarshal(raw, &cfg); err != nil { return nil, err } - - //TODO add check - if cfg.Type == TYPE { - return cfg, nil + if cfg.Type != TYPE { + return nil, fmt.Errorf("invalid type (type:%s)", cfg.Type) } - - return nil, nil -} - -func NewLink(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (types.Link, error) { - src := srcCfg.(chain.BaseConfig) - - r, err := newBTP2(src, dstAddr, src.Endpoint, baseDir, l) - if err != nil { - return nil, err - } - - link := link.NewLink(srcCfg, r, l) - return link, nil + return cfg, nil } func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir string, l log.Logger) (link.Receiver, error) { @@ -64,8 +43,7 @@ func NewReceiver(srcCfg link.ChainConfig, dstAddr types.BtpAddress, baseDir stri func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) (types.Sender, error) { dst := dstCfg.(chain.BaseConfig) - - w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStoreData) + w, err := newWallet(dst.KeyStorePass, dst.KeySecret, dst.KeyStore) if err != nil { return nil, err } @@ -73,12 +51,16 @@ func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, l log.Logger) return icon.NewSender(srcAddr, dst, w, dst.Endpoint, dst.Options, l), nil } -func newWallet(passwd, secret string, keyStore json.RawMessage) (types.Wallet, error) { - pw, err := resolvePassword(secret, passwd) - if err != nil { - return nil, err +func newWallet(passwd, secret string, keyStorePath string) (types.Wallet, error) { + if keyStore, err := os.ReadFile(keyStorePath); err != nil { + return nil, fmt.Errorf("fail to open KeyStore file path=%s", keyStorePath) + } else { + pw, err := resolvePassword(secret, passwd) + if err != nil { + return nil, err + } + return wallet.DecryptKeyStore(keyStore, pw) } - return wallet.DecryptKeyStore(keyStore, pw) } func resolvePassword(keySecret, keyStorePass string) ([]byte, error) { From 010dd2b3a98be9648ba8ea550b26e09c821e511c Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Mon, 31 Jul 2023 11:43:04 +0900 Subject: [PATCH 19/22] Update flag to configuration file --- cmd/relay/main.go | 64 ++++++++++++++++++++++++++++++-------------- common/cli/helper.go | 19 ++++++++++++- e2edemo/relay.sh | 20 +++++++------- 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 63294cd..a01e58d 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -72,6 +72,7 @@ func main() { rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { baseDir := rootVc.GetString("base_dir") logfile := rootVc.GetString("log_writer.filename") + cfg.FilePath = rootVc.GetString("config") if cfg.FilePath != "" { f, err := os.Open(cfg.FilePath) @@ -84,10 +85,33 @@ func main() { return fmt.Errorf("fail to read config file=%s err=%+v", cfg.FilePath, err) } cfg.FilePath, _ = filepath.Abs(cfg.FilePath) + if err := rootVc.Unmarshal(&cfg, cli.ViperDecodeOptJson); err != nil { + return fmt.Errorf("fail to unmarshall config from env err=%+v", err) + } + } else { + relayCfg := &relay.RelayConfig{} + if err := rootVc.Unmarshal(&relayCfg, cli.ViperDecodeOptJson); err != nil { + return fmt.Errorf("fail to unmarshall config from env err=%+v", err) + } + cfg.RelayConfig = *relayCfg + + if pp, err := cmd.Flags().GetString("src_config"); err == nil && len(pp) > 0 { + if parsed, err := cli.ReadJSONObject(pp); err != nil { + return err + } else if parsed != nil { + cfg.Src = parsed + } + } + + if pp, err := cmd.Flags().GetString("dst_config"); err == nil && len(pp) > 0 { + if parsed, err := cli.ReadJSONObject(pp); err != nil { + return err + } else if parsed != nil { + cfg.Dst = parsed + } + } } - if err := rootVc.Unmarshal(&cfg, cli.ViperDecodeOptJson); err != nil { - return fmt.Errorf("fail to unmarshall config from env err=%+v", err) - } + if baseDir != "" { cfg.BaseDir = cfg.ResolveRelative(baseDir) } @@ -101,25 +125,25 @@ func main() { rootPFlags.StringP("config", "c", "", "Parsing configuration file") //Chains Config - rootPFlags.String("chains_config.src", "", "Source chain config") - rootPFlags.String("chains_config.dst", "", "Destination chain config") + rootPFlags.String("src_config", "", "raw json string or '@' for stdin for parameter JSON") + rootPFlags.String("dst_config", "", "raw json string or '@'for stdin for parameter JSON") //RelayConfig - rootPFlags.String("relay_config.direction", "both", "relay network direction ( both, front, reverse)") - rootPFlags.String("relay_config.base_dir", "", "Base directory for data") - rootPFlags.String("relay_config.log_level", "debug", "Global log level (trace,debug,info,warn,error,fatal,panic)") - rootPFlags.String("relay_config.console_level", "trace", "Console log level (trace,debug,info,warn,error,fatal,panic)") - rootPFlags.String("relay_config.log_forwarder.vendor", "", "LogForwarder vendor (fluentd,logstash)") - rootPFlags.String("relay_config.log_forwarder.address", "", "LogForwarder address") - rootPFlags.String("relay_config.log_forwarder.level", "info", "LogForwarder level") - rootPFlags.String("relay_config.log_forwarder.name", "", "LogForwarder name") - rootPFlags.StringToString("relay_config.log_forwarder.options", nil, "LogForwarder options, comma-separated 'key=value'") - rootPFlags.String("relay_config.log_writer.filename", "", "Log file name (rotated files resides in same directory)") - rootPFlags.Int("relay_config.log_writer.maxsize", 100, "Maximum log file size in MiB") - rootPFlags.Int("relay_config.log_writer.maxage", 0, "Maximum age of log file in day") - rootPFlags.Int("relay_config.log_writer.maxbackups", 0, "Maximum number of backups") - rootPFlags.Bool("relay_config.log_writer.localtime", false, "Use localtime on rotated log file instead of UTC") - rootPFlags.Bool("relay_config.log_writer.compress", false, "Use gzip on rotated log file") + rootPFlags.String("direction", "reverse", "relay network direction (both,front,reverse)") + rootPFlags.String("base_dir", "", "Base directory for data") + rootPFlags.String("log_level", "debug", "Global log level (trace,debug,info,warn,error,fatal,panic)") + rootPFlags.String("console_level", "trace", "Console log level (trace,debug,info,warn,error,fatal,panic)") + rootPFlags.String("log_forwarder.vendor", "", "LogForwarder vendor (fluentd,logstash)") + rootPFlags.String("log_forwarder.address", "", "LogForwarder address") + rootPFlags.String("log_forwarder.level", "info", "LogForwarder level") + rootPFlags.String("log_forwarder.name", "", "LogForwarder name") + rootPFlags.StringToString("log_forwarder.options", nil, "LogForwarder options, comma-separated 'key=value'") + rootPFlags.String("log_writer.filename", "", "Log file name (rotated files resides in same directory)") + rootPFlags.Int("log_writer.maxsize", 100, "Maximum log file size in MiB") + rootPFlags.Int("log_writer.maxage", 0, "Maximum age of log file in day") + rootPFlags.Int("log_writer.maxbackups", 0, "Maximum number of backups") + rootPFlags.Bool("log_writer.localtime", false, "Use localtime on rotated log file instead of UTC") + rootPFlags.Bool("log_writer.compress", false, "Use gzip on rotated log file") cli.BindPFlags(rootVc, rootPFlags) saveCmd := &cobra.Command{ diff --git a/common/cli/helper.go b/common/cli/helper.go index 44e3f2b..2b877d2 100644 --- a/common/cli/helper.go +++ b/common/cli/helper.go @@ -275,7 +275,7 @@ func ViperDecodeOptJson(c *mapstructure.DecoderConfig) { return json.Marshal(input) } else if inputValType.Kind() == reflect.String { if input != "" { - return ioutil.ReadFile(input.(string)) + return os.ReadFile(input.(string)) } else { return json.RawMessage(nil), nil } @@ -781,3 +781,20 @@ func OnInterrupt(cb func()) { cb() }() } + +func ReadJSONObject(s string) ([]byte, error) { + if len(s) == 0 { + return nil, nil + } + var bs []byte + var err error + if strings.HasPrefix(s, "@") { + bs, err = os.ReadFile(s[1:]) + } else { + bs = []byte(s) + } + if err != nil { + return nil, err + } + return bs, nil +} diff --git a/e2edemo/relay.sh b/e2edemo/relay.sh index 47f2b62..a8a0ecf 100755 --- a/e2edemo/relay.sh +++ b/e2edemo/relay.sh @@ -40,20 +40,18 @@ fi if [ "x$BMV_BRIDGE" = xtrue ]; then echo "Using Bridge mode" + SRC_TYPE="icon-bridge" else echo "Using BTPBlock mode" - BMV_BRIDGE=false + SRC_TYPE="icon-btpblock" fi +DST_TYPE="eth-bridge" + +SRC_CONFIG='{"address":"'"$SRC_ADDRESS"'","endpoint":"'"$SRC_ENDPOINT"'","key_store":"'"$SRC_KEY_STORE"'","key_password":"'"$SRC_KEY_PASSWORD"'","type":"'"$SRC_TYPE"'"}' +DST_CONFIG='{"address":"'"$DST_ADDRESS"'","endpoint":"'"$DST_ENDPOINT"'","key_store":"'"$DST_KEY_STORE"'","key_password":"'"$DST_KEY_PASSWORD"'","type":"'"$DST_TYPE"'"}' ${RELAY_BIN} \ --direction both \ - --src.address ${SRC_ADDRESS} \ - --src.endpoint ${SRC_ENDPOINT} \ - --src.key_store ${SRC_KEY_STORE} \ - --src.key_password ${SRC_KEY_PASSWORD} \ - --src.bridge_mode=${BMV_BRIDGE} \ - --dst.address ${DST_ADDRESS} \ - --dst.endpoint ${DST_ENDPOINT} \ - --dst.key_store ${DST_KEY_STORE} \ - --dst.key_password ${DST_KEY_PASSWORD} \ - start + --src_config ${SRC_CONFIG} \ + --dst_config ${DST_CONFIG} \ + start \ No newline at end of file From f20e315d661d3f0ca7a5751390dd6c81c70b7080 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Mon, 31 Jul 2023 11:46:47 +0900 Subject: [PATCH 20/22] Update factory in link --- common/link/factory.go | 79 +++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/common/link/factory.go b/common/link/factory.go index c2f7af2..e947af8 100644 --- a/common/link/factory.go +++ b/common/link/factory.go @@ -2,7 +2,9 @@ package link import ( "encoding/json" + "fmt" + "github.com/icon-project/btp2/common/errors" "github.com/icon-project/btp2/common/log" "github.com/icon-project/btp2/common/types" ) @@ -15,80 +17,77 @@ type Factory struct { NewSender func(srcAddr types.BtpAddress, dstCfg ChainConfig, l log.Logger) (types.Sender, error) } -var factories []*Factory +var factories = map[string]*Factory{} func RegisterFactory(f *Factory) { - if f != nil { - if checkDuplicates(f) { - return //TODO err?? - } - factories = append(factories, f) + if f.NewLink == nil && f.NewReceiver == nil { + panic("NewLink and NewReader are empty") } -} - -func checkDuplicates(f *Factory) bool { - for _, cf := range factories { - if cf.Type == f.Type { - return true - } + if _, ok := factories[f.Type]; ok { + panic(fmt.Sprintf("Duplicate factory registration for %s", f.Type)) } - return false + factories[f.Type] = f } func CreateLink(srcRaw, dstRaw json.RawMessage, l log.Logger, baseDir string) (types.Link, error) { + var srcCfgCommon ChainConfigCommon + if err := json.Unmarshal(srcRaw, &srcCfgCommon); err != nil { + return nil, err + } + srcType := srcCfgCommon.GetType() + if len(srcType) == 0 { + return nil, errors.IllegalArgumentError.New("empty type in source config") + + } //Sender var dstCfgCommon ChainConfigCommon if err := json.Unmarshal(dstRaw, &dstCfgCommon); err != nil { return nil, err } - for _, f := range factories { + if f, ok := factories[srcType]; ok { srcCfg, err := f.ParseChainConfig(srcRaw) if err != nil { return nil, err } - if srcCfg != nil { - link, err := f.NewLink(srcCfg, dstCfgCommon.GetAddress(), baseDir, l) + if f.NewLink != nil { + return f.NewLink(srcCfg, dstCfgCommon.GetAddress(), baseDir, l) + } else { + receiver, err := f.NewReceiver(srcCfg, dstCfgCommon.GetAddress(), baseDir, l) if err != nil { return nil, err } - - if link == nil { - receiver, err := f.NewReceiver(srcCfg, dstCfgCommon.GetAddress(), baseDir, l) - if err != nil { - return nil, err - } - - link = NewLink(srcCfg, receiver, l) - } - return link, nil + return NewLink(srcCfg, receiver, l), nil } - } - return nil, nil + } else { + return nil, errors.NotFoundError.Errorf("UnknownSourceType(type=%s)", srcType) + } } func CreateSender(srcRaw, dstRaw json.RawMessage, l log.Logger) (types.Sender, error) { - //Sender var srcCfgCommon ChainConfigCommon if err := json.Unmarshal(srcRaw, &srcCfgCommon); err != nil { return nil, err } + var dstCfgCommon ChainConfigCommon + if err := json.Unmarshal(dstRaw, &dstCfgCommon); err != nil { + return nil, err + } + dstType := dstCfgCommon.GetType() + if len(dstType) == 0 { + return nil, errors.IllegalArgumentError.New("empty type in dst config") + } - for _, f := range factories { + if f, ok := factories[dstType]; ok { dstCfg, err := f.ParseChainConfig(dstRaw) if err != nil { return nil, err } - if dstCfg != nil { - s, err := f.NewSender(srcCfgCommon.GetAddress(), dstCfg, l) - if err != nil { - return nil, err - } - return s, nil - } - } - return nil, nil + return f.NewSender(srcCfgCommon.GetAddress(), dstCfg, l) + } else { + return nil, errors.NotFoundError.Errorf("UnknownSourceType(type=%s)", dstType) + } } From 0eba41b9edd604d4b23f884f99ced620e3b70b40 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Mon, 31 Jul 2023 11:48:35 +0900 Subject: [PATCH 21/22] Clean up code in relay --- chain/ethbr/sender.go | 18 +++++++++--------- chain/icon/sender.go | 18 +++++++++--------- common/link/link.go | 12 +++++++----- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/chain/ethbr/sender.go b/chain/ethbr/sender.go index a70ed0d..d983ff9 100644 --- a/chain/ethbr/sender.go +++ b/chain/ethbr/sender.go @@ -48,7 +48,7 @@ var ( txSizeLimit = int(math.Ceil(txMaxDataSize / (1 + txOverheadScale))) ) -type Queue struct { +type queue struct { values []*relayMessageTx } @@ -57,12 +57,12 @@ type relayMessageTx struct { txHash []byte } -func NewQueue() *Queue { - queue := &Queue{} +func newQueue() *queue { + queue := &queue{} return queue } -func (q *Queue) enqueue(id string, txHash []byte) error { +func (q *queue) enqueue(id string, txHash []byte) error { if MaxQueueSize <= len(q.values) { return fmt.Errorf("queue full") } @@ -74,7 +74,7 @@ func (q *Queue) enqueue(id string, txHash []byte) error { return nil } -func (q *Queue) dequeue(id string) { +func (q *queue) dequeue(id string) { for i, rm := range q.values { if rm.id == id { q.values = q.values[i+1:] @@ -83,11 +83,11 @@ func (q *Queue) dequeue(id string) { } } -func (q *Queue) isEmpty() bool { +func (q *queue) isEmpty() bool { return len(q.values) == 0 } -func (q *Queue) len() int { +func (q *queue) len() int { return len(q.values) } @@ -102,7 +102,7 @@ type sender struct { bmc *binding.BMC rr chan *btpTypes.RelayResult isFoundOffsetBySeq bool - queue *Queue + queue *queue } func newSender(srcAddr btpTypes.BtpAddress, dstCfg link.ChainConfig, w btpTypes.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) btpTypes.Sender { @@ -112,7 +112,7 @@ func newSender(srcAddr btpTypes.BtpAddress, dstCfg link.ChainConfig, w btpTypes. w: w, l: l, rr: make(chan *btpTypes.RelayResult), - queue: NewQueue(), + queue: newQueue(), } b, err := json.Marshal(opt) diff --git a/chain/icon/sender.go b/chain/icon/sender.go index fb9b615..a5ce6d1 100644 --- a/chain/icon/sender.go +++ b/chain/icon/sender.go @@ -48,7 +48,7 @@ var ( txSizeLimit = int(math.Ceil(txMaxDataSize / (1 + txOverheadScale))) ) -type Queue struct { +type queue struct { values []*relayMessageTx } @@ -57,12 +57,12 @@ type relayMessageTx struct { txHash []byte } -func NewQueue() *Queue { - queue := &Queue{} +func newQueue() *queue { + queue := &queue{} return queue } -func (q *Queue) enqueue(id string, txHash []byte) error { +func (q *queue) enqueue(id string, txHash []byte) error { if MaxQueueSize <= len(q.values) { return fmt.Errorf("queue full") } @@ -74,7 +74,7 @@ func (q *Queue) enqueue(id string, txHash []byte) error { return nil } -func (q *Queue) dequeue(id string) { +func (q *queue) dequeue(id string) { for i, rm := range q.values { if rm.id == id { q.values = q.values[i+1:] @@ -83,11 +83,11 @@ func (q *Queue) dequeue(id string) { } } -func (q *Queue) isEmpty() bool { +func (q *queue) isEmpty() bool { return len(q.values) == 0 } -func (q *Queue) len() int { +func (q *queue) len() int { return len(q.values) } @@ -102,7 +102,7 @@ type sender struct { } rr chan *types.RelayResult isFoundOffsetBySeq bool - queue *Queue + queue *queue } func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, w types.Wallet, endpoint string, opt map[string]interface{}, l log.Logger) types.Sender { @@ -112,7 +112,7 @@ func NewSender(srcAddr types.BtpAddress, dstCfg link.ChainConfig, w types.Wallet w: w, l: l, rr: make(chan *types.RelayResult), - queue: NewQueue(), + queue: newQueue(), } b, err := json.Marshal(opt) if err != nil { diff --git a/common/link/link.go b/common/link/link.go index 6c04f97..94e384a 100644 --- a/common/link/link.go +++ b/common/link/link.go @@ -221,8 +221,8 @@ func (l *Link) buildRelayMessage() error { func (l *Link) sendRelayMessage() error { for _, rm := range l.rms { if rm.sendingStatus == false { - l.l.Debugf("SendRelayMessage (bls height:%d, bls txSeq:%d, bls rxSeq:%d)", - rm.bls.Verifier.Height, rm.bls.TxSeq, rm.bls.RxSeq) + l.l.Debugf("SendRelayMessage (bls height:%d, bls rxSeq:%d)", + rm.bls.Verifier.Height, rm.bls.RxSeq) _, err := l.s.Relay(rm) if err != nil { if errors.InvalidStateError.Equals(err) { @@ -261,8 +261,8 @@ func (l *Link) appendRelayMessage() error { rm.sendingStatus = false l.rms = append(l.rms, rm) - l.l.Debugf("AppendRelayMessage (bls height:%d, bls txSeq:%d, bls rxSeq:%d)", - rm.bls.Verifier.Height, rm.bls.TxSeq, rm.bls.RxSeq) + l.l.Debugf("AppendRelayMessage (bls height:%d, bls rxSeq:%d)", + rm.bls.Verifier.Height, rm.bls.RxSeq) } l.rmi.rmis = l.rmi.rmis[:0] @@ -564,7 +564,9 @@ func (l *Link) result(rr *types.RelayResult) error { } case errors.BMVRevertInvalidBlockWitnessOld: //TODO Error handling required on Finalized - l.updateBlockProof(rr.Id) + if err := l.updateBlockProof(rr.Id); err != nil { + return err + } default: l.l.Panicf("fail to GetResult RelayMessage ID:%v ErrorCoder:%+v", rr.Id, rr.Err) From 6227ddbec5060a0c1151021e354cd446e98ceac8 Mon Sep 17 00:00:00 2001 From: ByoungGul Kwon Date: Mon, 31 Jul 2023 14:13:07 +0900 Subject: [PATCH 22/22] Update error handling in icon client --- chain/icon/client/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/chain/icon/client/client.go b/chain/icon/client/client.go index f508916..d22bdb3 100644 --- a/chain/icon/client/client.go +++ b/chain/icon/client/client.go @@ -378,6 +378,7 @@ func (c *Client) MonitorBTP(p *BTPRequest, cb func(conn *websocket.Conn, v *BTPN case *BTPNotification: if err := cb(conn, t); err != nil { c.l.Debugf("MonitorBTP callback return err:%+v", err) + errCb(conn, err) } case WSEvent: c.l.Debugf("MonitorBTP WSEvent %s %+v", conn.LocalAddr().String(), t)