Skip to content

Commit

Permalink
Merge branch 'main' into fix/unexecuted-proposals-lost
Browse files Browse the repository at this point in the history
  • Loading branch information
mpetrun5 authored Jul 10, 2024
2 parents 9d877ae + 49a0777 commit 0a859da
Show file tree
Hide file tree
Showing 36 changed files with 481 additions and 154 deletions.
6 changes: 3 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ func Run() error {
eventHandlers = append(eventHandlers, hubEventHandlers.NewDepositEventHandler(depositListener, depositHandler, bridgeAddress, *config.GeneralChainConfig.Id, msgChan))
eventHandlers = append(eventHandlers, hubEventHandlers.NewKeygenEventHandler(l, tssListener, coordinator, host, communication, keyshareStore, bridgeAddress, networkTopology.Threshold))
eventHandlers = append(eventHandlers, hubEventHandlers.NewFrostKeygenEventHandler(l, tssListener, coordinator, host, communication, frostKeyshareStore, frostAddress, networkTopology.Threshold))
eventHandlers = append(eventHandlers, hubEventHandlers.NewRefreshEventHandler(l, topologyProvider, topologyStore, tssListener, coordinator, host, communication, connectionGate, keyshareStore, bridgeAddress))
eventHandlers = append(eventHandlers, hubEventHandlers.NewRetryEventHandler(l, tssListener, depositHandler, propStore, bridgeAddress, *config.GeneralChainConfig.Id, config.BlockConfirmations, msgChan))
eventHandlers = append(eventHandlers, hubEventHandlers.NewRefreshEventHandler(l, topologyProvider, topologyStore, tssListener, coordinator, host, communication, connectionGate, keyshareStore, frostKeyshareStore, bridgeAddress))
eventHandlers = append(eventHandlers, hubEventHandlers.NewRetryEventHandler(l, tssListener, depositHandler, bridgeAddress, *config.GeneralChainConfig.Id, config.BlockConfirmations, msgChan))

Check failure on line 228 in app/app.go

View workflow job for this annotation

GitHub Actions / linter-check

not enough arguments in call to hubEventHandlers.NewRetryEventHandler

Check failure on line 228 in app/app.go

View workflow job for this annotation

GitHub Actions / linter-check

not enough arguments in call to hubEventHandlers.NewRetryEventHandler

Check failure on line 228 in app/app.go

View workflow job for this annotation

GitHub Actions / test (1.19.x, ubuntu-latest)

not enough arguments in call to hubEventHandlers.NewRetryEventHandler
evmListener := listener.NewEVMListener(client, eventHandlers, blockstore, sygmaMetrics, *config.GeneralChainConfig.Id, config.BlockRetryInterval, config.BlockConfirmations, config.BlockInterval)
executor := executor.NewExecutor(host, communication, coordinator, bridgeContract, keyshareStore, exitLock, config.GasLimit.Uint64())

Expand Down Expand Up @@ -325,7 +325,7 @@ func Run() error {
resources := make(map[[32]byte]btcConfig.Resource)
for _, resource := range config.Resources {
resources[resource.ResourceID] = resource
eventHandlers = append(eventHandlers, btcListener.NewFungibleTransferEventHandler(l, *config.GeneralChainConfig.Id, depositHandler, msgChan, conn, resource))
eventHandlers = append(eventHandlers, btcListener.NewFungibleTransferEventHandler(l, *config.GeneralChainConfig.Id, depositHandler, msgChan, conn, resource, config.FeeAddress))
}
listener := btcListener.NewBtcListener(conn, eventHandlers, config, blockstore)

Expand Down
18 changes: 16 additions & 2 deletions chains/btc/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import (
type RawResource struct {
Address string
ResourceID string
FeeAmount string
Tweak string
Script string
}

type Resource struct {
Address btcutil.Address
FeeAmount *big.Int
ResourceID [32]byte
Tweak string
Script []byte
Expand All @@ -34,6 +36,7 @@ type RawBtcConfig struct {
chain.GeneralChainConfig `mapstructure:",squash"`
Resources []RawResource `mapstrcture:"resources"`
StartBlock int64 `mapstructure:"startBlock"`
FeeAddress string `mapstructure:"feeAddress"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
BlockInterval int64 `mapstructure:"blockInterval" default:"5"`
Expand All @@ -48,7 +51,7 @@ func (c *RawBtcConfig) Validate() error {
return err
}

if c.BlockConfirmations != 0 && c.BlockConfirmations < 1 {
if c.BlockConfirmations < 1 {
return fmt.Errorf("blockConfirmations has to be >=1")
}

Expand All @@ -65,6 +68,7 @@ func (c *RawBtcConfig) Validate() error {
type BtcConfig struct {
GeneralChainConfig chain.GeneralChainConfig
Resources []Resource
FeeAddress btcutil.Address
Username string
Password string
StartBlock *big.Int
Expand Down Expand Up @@ -100,14 +104,22 @@ func NewBtcConfig(chainConfig map[string]interface{}) (*BtcConfig, error) {
if err != nil {
return nil, err
}

feeAddress, err := btcutil.DecodeAddress(c.FeeAddress, &networkParams)
if err != nil {
return nil, err
}
resources := make([]Resource, len(c.Resources))
for i, r := range c.Resources {
scriptBytes, err := hex.DecodeString(r.Script)
if err != nil {
return nil, err
}

feeAmount, success := new(big.Int).SetString(r.FeeAmount, 10)
if !success {
return nil, fmt.Errorf("error: could not convert string to *big.Int")
}

address, err := btcutil.DecodeAddress(r.Address, &networkParams)
if err != nil {
return nil, err
Expand All @@ -123,6 +135,7 @@ func NewBtcConfig(chainConfig map[string]interface{}) (*BtcConfig, error) {
ResourceID: resource32Bytes,
Script: scriptBytes,
Tweak: r.Tweak,
FeeAmount: feeAmount,
}
}

Expand All @@ -137,6 +150,7 @@ func NewBtcConfig(chainConfig map[string]interface{}) (*BtcConfig, error) {
Password: c.Password,
Network: networkParams,
MempoolUrl: c.MempoolUrl,
FeeAddress: feeAddress,
Resources: resources,
}
return config, nil
Expand Down
17 changes: 11 additions & 6 deletions chains/btc/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,21 @@ func (s *NewBtcConfigTestSuite) Test_InvalidPassword() {
func (s *NewBtcConfigTestSuite) Test_ValidConfig() {
expectedResource := listener.SliceTo32Bytes(common.LeftPadBytes([]byte{3}, 31))
expectedAddress, _ := btcutil.DecodeAddress("tb1qln69zuhdunc9stwfh6t7adexxrcr04ppy6thgm", &chaincfg.TestNet3Params)
feeAddress, _ := btcutil.DecodeAddress("mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt", &chaincfg.TestNet3Params)
expectedScript, _ := hex.DecodeString("51206a698882348433b57d549d6344f74500fcd13ad8d2200cdf89f8e39e5cafa7d5")

rawConfig := map[string]interface{}{
"id": 1,
"endpoint": "ws://domain.com",
"name": "btc1",
"username": "username",
"password": "pass123",
"network": "testnet",
"id": 1,
"endpoint": "ws://domain.com",
"name": "btc1",
"username": "username",
"password": "pass123",
"network": "testnet",
"feeAddress": "mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt",
"resources": []interface{}{
config.RawResource{
Address: "tb1qln69zuhdunc9stwfh6t7adexxrcr04ppy6thgm",
FeeAmount: "10000000",
ResourceID: "0x0000000000000000000000000000000000000000000000000000000000000300",
Script: "51206a698882348433b57d549d6344f74500fcd13ad8d2200cdf89f8e39e5cafa7d5",
Tweak: "tweak",
Expand All @@ -130,12 +133,14 @@ func (s *NewBtcConfigTestSuite) Test_ValidConfig() {
BlockInterval: big.NewInt(5),
BlockRetryInterval: time.Duration(5) * time.Second,
Network: chaincfg.TestNet3Params,
FeeAddress: feeAddress,
Resources: []config.Resource{
{
Address: expectedAddress,
ResourceID: expectedResource,
Script: expectedScript,
Tweak: "tweak",
FeeAmount: big.NewInt(10000000),
},
},
})
Expand Down
36 changes: 32 additions & 4 deletions chains/btc/executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,32 @@ func (e *Executor) Execute(proposals []*proposal.Proposal) error {
if len(props) == 0 {
return nil
}
resource, ok := e.resources[props[0].Data.ResourceId]
if !ok {
return fmt.Errorf("no address for resource")

propsPerResource := make(map[[32]byte][]*BtcTransferProposal)
for _, prop := range props {
propsPerResource[prop.Data.ResourceId] = append(propsPerResource[prop.Data.ResourceId], prop)
}

p := pool.New().WithErrors()
for resourceID, props := range propsPerResource {
resourceID := resourceID
props := props

p.Go(func() error {
resource, ok := e.resources[resourceID]
if !ok {
return fmt.Errorf("no resource for ID %s", hex.EncodeToString(resourceID[:]))
}

sessionID := fmt.Sprintf("%s-%s", sessionID, hex.EncodeToString(resourceID[:]))
return e.executeResourceProps(props, resource, sessionID)
})
}
return p.Wait()
}

func (e *Executor) executeResourceProps(props []*BtcTransferProposal, resource config.Resource, sessionID string) error {
log.Info().Str("SessionID", sessionID).Msgf("Executing proposals for resource %s", hex.EncodeToString(resource.ResourceID[:]))

tx, utxos, err := e.rawTx(props, resource)
if err != nil {
Expand Down Expand Up @@ -203,7 +225,11 @@ func (e *Executor) rawTx(proposals []*BtcTransferProposal, resource config.Resou
if err != nil {
return nil, nil, err
}
inputAmount, utxos, err := e.inputs(tx, resource.Address, outputAmount)
feeEstimate, err := e.fee(int64(len(proposals)), int64(len(proposals)))
if err != nil {
return nil, nil, err
}
inputAmount, utxos, err := e.inputs(tx, resource.Address, outputAmount+feeEstimate)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -345,6 +371,7 @@ func (e *Executor) isExecuted(prop *proposal.Proposal) (bool, error) {
}

func (e *Executor) storeProposalsStatus(props []*BtcTransferProposal, status store.PropStatus) {
e.propMutex.Lock()
for _, prop := range props {
err := e.propStorer.StorePropStatus(
prop.Source,
Expand All @@ -355,4 +382,5 @@ func (e *Executor) storeProposalsStatus(props []*BtcTransferProposal, status sto
log.Err(err).Msgf("Failed storing proposal %+v status %s", prop, status)
}
}
e.propMutex.Unlock()
}
40 changes: 22 additions & 18 deletions chains/btc/listener/event-handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
package listener

import (
"crypto/sha256"
"encoding/binary"
"math/big"
"strconv"

"github.com/ChainSafe/sygma-relayer/chains/btc/config"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/btcutil"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/sygmaprotocol/sygma-core/relayer/message"
)

type Deposit struct {
// ResourceID used to find address of handler to be used for deposit
// ID of the resource that is transfered
ResourceID [32]byte
// Address of sender (msg.sender: user)
SenderAddress string
Expand All @@ -38,16 +40,18 @@ type DepositHandler interface {
type FungibleTransferEventHandler struct {
depositHandler DepositHandler
domainID uint8
feeAddress btcutil.Address
log zerolog.Logger
conn Connection
msgChan chan []*message.Message
resource config.Resource
}

func NewFungibleTransferEventHandler(logC zerolog.Context, domainID uint8, depositHandler DepositHandler, msgChan chan []*message.Message, conn Connection, resource config.Resource) *FungibleTransferEventHandler {
func NewFungibleTransferEventHandler(logC zerolog.Context, domainID uint8, depositHandler DepositHandler, msgChan chan []*message.Message, conn Connection, resource config.Resource, feeAddress btcutil.Address) *FungibleTransferEventHandler {
return &FungibleTransferEventHandler{
depositHandler: depositHandler,
domainID: domainID,
feeAddress: feeAddress,
log: logC.Logger(),
conn: conn,
msgChan: msgChan,
Expand All @@ -62,23 +66,23 @@ func (eh *FungibleTransferEventHandler) HandleEvents(blockNumber *big.Int) error
eh.log.Error().Err(err).Msg("Error fetching events")
return err
}
for evtNumber, evt := range evts {
for _, evt := range evts {
err := func(evt btcjson.TxRawResult) error {
defer func() {
if r := recover(); r != nil {
log.Error().Msgf("panic occured while handling deposit %+v", evt)
}
}()

d, isDeposit, err := DecodeDepositEvent(evt, eh.resource)
d, isDeposit, err := DecodeDepositEvent(evt, eh.resource, eh.feeAddress)
if err != nil {
return err
}

if !isDeposit {
return nil
}
nonce, err := eh.CalculateNonce(blockNumber, evtNumber)
nonce, err := eh.CalculateNonce(blockNumber, evt.Hash)
if err != nil {
return err
}
Expand Down Expand Up @@ -119,23 +123,23 @@ func (eh *FungibleTransferEventHandler) FetchEvents(startBlock *big.Int) ([]btcj
return block.Tx, nil
}

func (eh *FungibleTransferEventHandler) CalculateNonce(blockNumber *big.Int, evtNumber int) (uint64, error) {
func (eh *FungibleTransferEventHandler) CalculateNonce(blockNumber *big.Int, transactionHash string) (uint64, error) {
// Convert blockNumber to string
blockNumberStr := blockNumber.String()

// Convert evtNumber to *big.Int
evtNumberBigInt := big.NewInt(int64(evtNumber))
// Concatenate blockNumberStr and transactionHash with a separator
concatenatedStr := blockNumberStr + "-" + transactionHash

// Convert evtNumberBigInt to string
evtNumberStr := evtNumberBigInt.String()
// Calculate SHA-256 hash of the concatenated string
hash := sha256.New()
hash.Write([]byte(concatenatedStr))
hashBytes := hash.Sum(nil)

// Concatenate blockNumberStr and evtNumberStr
concatenatedStr := blockNumberStr + evtNumberStr

// Parse the concatenated string to uint64
result, err := strconv.ParseUint(concatenatedStr, 10, 64)
if err != nil {
return 0, err
// XOR fold the hash to get a 64-bit value
var result uint64
for i := 0; i < 4; i++ {
part := binary.BigEndian.Uint64(hashBytes[i*8 : (i+1)*8])
result ^= part
}

return result, nil
Expand Down
36 changes: 19 additions & 17 deletions chains/btc/listener/event-handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type DepositHandlerTestSuite struct {
resource config.Resource
msgChan chan []*message.Message
mockConn *mock_listener.MockConnection
feeAddress btcutil.Address
}

func TestRunDepositHandlerTestSuite(t *testing.T) {
Expand All @@ -43,12 +44,14 @@ func TestRunDepositHandlerTestSuite(t *testing.T) {
func (s *DepositHandlerTestSuite) SetupTest() {
ctrl := gomock.NewController(s.T())
s.domainID = 1
address, _ := btcutil.DecodeAddress("tb1qln69zuhdunc9stwfh6t7adexxrcr04ppy6thgm", &chaincfg.TestNet3Params)
s.resource = config.Resource{Address: address, ResourceID: [32]byte{}}
address, _ := btcutil.DecodeAddress("tb1pdf5c3q35ssem2l25n435fa69qr7dzwkc6gsqehuflr3euh905l2slafjvv", &chaincfg.TestNet3Params)
s.feeAddress, _ = btcutil.DecodeAddress("tb1qln69zuhdunc9stwfh6t7adexxrcr04ppy6thgm", &chaincfg.TestNet3Params)

s.resource = config.Resource{Address: address, ResourceID: [32]byte{}, FeeAmount: big.NewInt(10000)}
s.mockDepositHandler = mock_listener.NewMockDepositHandler(ctrl)
s.msgChan = make(chan []*message.Message, 2)
s.mockConn = mock_listener.NewMockConnection(ctrl)
s.fungibleTransferEventHandler = listener.NewFungibleTransferEventHandler(zerolog.Context{}, s.domainID, s.mockDepositHandler, s.msgChan, s.mockConn, s.resource)
s.fungibleTransferEventHandler = listener.NewFungibleTransferEventHandler(zerolog.Context{}, s.domainID, s.mockDepositHandler, s.msgChan, s.mockConn, s.resource, s.feeAddress)
}

func (s *DepositHandlerTestSuite) Test_FetchDepositFails_GetBlockHashError() {
Expand All @@ -67,26 +70,18 @@ func (s *DepositHandlerTestSuite) Test_FetchDepositFails_GetBlockVerboseTxError(
s.NotNil(err)
}

func (s *DepositHandlerTestSuite) Test_CalculateNonceFail_BlockNumberOverflow() {

blockNumber := new(big.Int)
blockNumber.SetString("18446744073709551616", 10)
nonce, err := s.fungibleTransferEventHandler.CalculateNonce(blockNumber, 5)
s.Equal(nonce, uint64(0))
s.NotNil(err)
}

func (s *DepositHandlerTestSuite) Test_CalculateNonce() {
blockNumber := big.NewInt(123)
nonce, err := s.fungibleTransferEventHandler.CalculateNonce(blockNumber, 4)
s.Equal(nonce, uint64(1234))
blockNumber := big.NewInt(850000)
nonce, err := s.fungibleTransferEventHandler.CalculateNonce(blockNumber, "a3f1e4d8b3c5e2a1f6d3c7e4b8a9f3e2c1d4a6b7c8e3f1d2c4b5a6e7")
fmt.Println(nonce)
s.Equal(nonce, uint64(12849897320021645821))
s.Nil(err)
}

func (s *DepositHandlerTestSuite) Test_HandleDepositFails_ExecutionContinue() {
blockNumber := big.NewInt(100)
data2 := map[string]any{
"deposit_nonce": uint64(1001),
"deposit_nonce": uint64(8228687738678474667),
"resource_id": [32]byte{0},
"amount": big.NewInt(19000),
"deposit_data": "0xe9f23A8289764280697a03aC06795eA92a170e42_1",
Expand Down Expand Up @@ -129,10 +124,17 @@ func (s *DepositHandlerTestSuite) Test_HandleDepositFails_ExecutionContinue() {
{
ScriptPubKey: btcjson.ScriptPubKeyResult{
Type: "witness_v1_taproot",
Address: "tb1qln69zuhdunc9stwfh6t7adexxrcr04ppy6thgm",
Address: "tb1pdf5c3q35ssem2l25n435fa69qr7dzwkc6gsqehuflr3euh905l2slafjvv",
},
Value: float64(0.00019),
},
{
ScriptPubKey: btcjson.ScriptPubKeyResult{
Type: "witness_v1_taproot",
Address: "tb1qln69zuhdunc9stwfh6t7adexxrcr04ppy6thgm",
},
Value: float64(0.0002),
},
},
}

Expand Down
Loading

0 comments on commit 0a859da

Please sign in to comment.