Skip to content

Commit

Permalink
Merge pull request #280 from multiversx/merge-v3-feat-native-esdts
Browse files Browse the repository at this point in the history
Merge v3 feat native esdts
  • Loading branch information
iulianpascalau authored Dec 27, 2023
2 parents 0267f24 + 3172fd0 commit eb5baab
Show file tree
Hide file tree
Showing 48 changed files with 1,889 additions and 203 deletions.
59 changes: 58 additions & 1 deletion bridges/ethMultiversX/bridgeExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package ethmultiversx

import (
"context"
"encoding/hex"
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/multiversx/mx-bridge-eth-go/clients"
"github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract"
"github.com/multiversx/mx-bridge-eth-go/core"
"github.com/multiversx/mx-bridge-eth-go/core/batchProcessor"
"github.com/multiversx/mx-chain-core-go/core/check"
Expand All @@ -17,9 +19,11 @@ import (
// splits - represent the number of times we split the maximum interval
// we wait for the transfer confirmation on Ethereum
const splits = 10

const minRetries = 1

// MissingCallData is a placeholder for wrongly initiated contract calls that do not contain data
const MissingCallData = "<missing call data>"

// ArgsBridgeExecutor is the arguments DTO struct used in both bridges
type ArgsBridgeExecutor struct {
Log logger.Logger
Expand Down Expand Up @@ -450,11 +454,64 @@ func (executor *bridgeExecutor) GetAndStoreBatchFromEthereum(ctx context.Context
ErrBatchNotFound, nonce, batch.ID, len(batch.Deposits))
}

batch, err = executor.addBatchSCMetadata(ctx, batch)
if err != nil {
return err
}
executor.batch = batch

return nil
}

// addBatchSCMetadata fetches the logs containing sc calls metadata for the current batch
func (executor *bridgeExecutor) addBatchSCMetadata(ctx context.Context, transfers *clients.TransferBatch) (*clients.TransferBatch, error) {
if transfers == nil {
return nil, ErrNilBatch
}

if !executor.hasSCCalls(transfers) {
return transfers, nil
}

events, err := executor.ethereumClient.GetBatchSCMetadata(ctx, transfers.ID)
if err != nil {
return nil, err
}

for i, t := range transfers.Deposits {
transfers.Deposits[i] = executor.addMetadataToTransfer(t, events)
}

return transfers, nil
}

func (executor *bridgeExecutor) addMetadataToTransfer(transfer *clients.DepositTransfer, events []*contract.SCExecProxyERC20SCDeposit) *clients.DepositTransfer {
for _, event := range events {
if event.DepositNonce == transfer.Nonce {
transfer.ExtraGasLimit = event.MvxGasLimit
transfer.Data = []byte(event.CallData)
if len(transfer.Data) == 0 {
// will add a dummy data so the relayers won't panic
transfer.Data = []byte(MissingCallData)
}
transfer.DisplayableData = hex.EncodeToString(transfer.Data)

return transfer
}
}
return transfer
}

func (executor *bridgeExecutor) hasSCCalls(transfers *clients.TransferBatch) bool {
for _, t := range transfers.Deposits {
if executor.ethereumClient.IsDepositSCCall(t) {
return true
}
}

return false
}

// WasTransferPerformedOnEthereum returns true if the batch was performed on Ethereum
func (executor *bridgeExecutor) WasTransferPerformedOnEthereum(ctx context.Context) (bool, error) {
if executor.batch == nil {
Expand Down
71 changes: 71 additions & 0 deletions bridges/ethMultiversX/bridgeExecutor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/multiversx/mx-bridge-eth-go/clients"
"github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract"
"github.com/multiversx/mx-bridge-eth-go/core"
"github.com/multiversx/mx-bridge-eth-go/core/batchProcessor"
"github.com/multiversx/mx-bridge-eth-go/testsCommon"
Expand Down Expand Up @@ -363,6 +364,76 @@ func TestEthToMultiversXBridgeExecutor_GetAndStoreBatchFromEthereum(t *testing.T
assert.True(t, expectedBatch == executor.GetStoredBatch()) // pointer testing
assert.True(t, expectedBatch == executor.batch)
})
t.Run("should add deposits metadata for sc calls", func(t *testing.T) {
args := createMockExecutorArgs()
providedNonce := uint64(8346)
depositNonce := uint64(100)
depositData := "testData"
expectedBatch := &clients.TransferBatch{
ID: providedNonce,
Deposits: []*clients.DepositTransfer{
{
Nonce: depositNonce,
},
},
}
args.EthereumClient = &bridgeTests.EthereumClientStub{
GetBatchCalled: func(ctx context.Context, nonce uint64) (*clients.TransferBatch, error) {
assert.Equal(t, providedNonce, nonce)
return expectedBatch, nil
},
GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.SCExecProxyERC20SCDeposit, error) {
return []*contract.SCExecProxyERC20SCDeposit{{
DepositNonce: depositNonce,
CallData: depositData,
}}, nil
},
IsDepositSCCallCalled: func(deposit *clients.DepositTransfer) bool {
return deposit.Nonce == depositNonce
},
}
executor, _ := NewBridgeExecutor(args)
err := executor.GetAndStoreBatchFromEthereum(context.Background(), providedNonce)

assert.Nil(t, err)
assert.True(t, expectedBatch == executor.GetStoredBatch()) // pointer testing
assert.Equal(t, depositData, string(executor.batch.Deposits[0].Data))
})
t.Run("should add deposits metadata for sc calls even if with invalid data", func(t *testing.T) {
args := createMockExecutorArgs()
providedNonce := uint64(8346)
depositNonce := uint64(100)
depositData := ""
expectedBatch := &clients.TransferBatch{
ID: providedNonce,
Deposits: []*clients.DepositTransfer{
{
Nonce: depositNonce,
},
},
}
args.EthereumClient = &bridgeTests.EthereumClientStub{
GetBatchCalled: func(ctx context.Context, nonce uint64) (*clients.TransferBatch, error) {
assert.Equal(t, providedNonce, nonce)
return expectedBatch, nil
},
GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.SCExecProxyERC20SCDeposit, error) {
return []*contract.SCExecProxyERC20SCDeposit{{
DepositNonce: depositNonce,
CallData: depositData,
}}, nil
},
IsDepositSCCallCalled: func(deposit *clients.DepositTransfer) bool {
return deposit.Nonce == depositNonce
},
}
executor, _ := NewBridgeExecutor(args)
err := executor.GetAndStoreBatchFromEthereum(context.Background(), providedNonce)

assert.Nil(t, err)
assert.True(t, expectedBatch == executor.GetStoredBatch()) // pointer testing
assert.Equal(t, MissingCallData, string(executor.batch.Deposits[0].Data))
})
}

func TestEthToMultiversXBridgeExecutor_GetLastExecutedEthBatchIDFromMultiversX(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions bridges/ethMultiversX/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/multiversx/mx-bridge-eth-go/clients"
"github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract"
"github.com/multiversx/mx-bridge-eth-go/core/batchProcessor"
)

Expand Down Expand Up @@ -40,13 +41,15 @@ type MultiversXClient interface {
type EthereumClient interface {
GetBatch(ctx context.Context, nonce uint64) (*clients.TransferBatch, error)
WasExecuted(ctx context.Context, batchID uint64) (bool, error)
IsDepositSCCall(deposit *clients.DepositTransfer) bool
GenerateMessageHash(batch *batchProcessor.ArgListsBatch, batchId uint64) (common.Hash, error)

BroadcastSignatureForMessageHash(msgHash common.Hash)
ExecuteTransfer(ctx context.Context, msgHash common.Hash, batch *batchProcessor.ArgListsBatch, batchId uint64, quorum int) (string, error)
GetTransactionsStatuses(ctx context.Context, batchId uint64) ([]byte, error)
GetQuorumSize(ctx context.Context) (*big.Int, error)
IsQuorumReached(ctx context.Context, msgHash common.Hash) (bool, error)
GetBatchSCMetadata(ctx context.Context, nonce uint64) ([]*contract.SCExecProxyERC20SCDeposit, error)
CheckClientAvailability(ctx context.Context) error
CheckRequiredBalance(ctx context.Context, erc20Address common.Address, value *big.Int) error
TokenMintedBalances(ctx context.Context, token common.Address) (*big.Int, error)
Expand Down
2 changes: 1 addition & 1 deletion bridges/ethMultiversX/steps/ethToMultiversX/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const (
// GettingPendingBatchFromEthereum is the step identifier for fetching the pending batch from the Ethereum chain
GettingPendingBatchFromEthereum = "get pending batch from Ethereum"

// ProposingTransferOnMultiversX is the step idetifier for proposing transfer on MultiversX
// ProposingTransferOnMultiversX is the step identifier for proposing transfer on MultiversX
ProposingTransferOnMultiversX = "propose transfer"

// SigningProposedTransferOnMultiversX is the step identifier for signing proposed transfer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import (

var expectedError = errors.New("expected error")
var testBatch = &clients.TransferBatch{
ID: 112233,
Deposits: nil,
Statuses: nil,
ID: 112233,
Deposits: []*clients.DepositTransfer{
{},
},
Statuses: []byte{0},
}

func TestExecuteGetPending(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions bridges/ethMultiversX/steps/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Executor interface {
GetBatchFromMultiversX(ctx context.Context) (*clients.TransferBatch, error)
StoreBatchFromMultiversX(batch *clients.TransferBatch) error
GetStoredBatch() *clients.TransferBatch

GetLastExecutedEthBatchIDFromMultiversX(ctx context.Context) (uint64, error)
VerifyLastDepositNonceExecutedOnEthereumBatch(ctx context.Context) error

Expand Down
4 changes: 2 additions & 2 deletions bridges/ethMultiversX/topology/topologyHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ func (t *topologyHandler) MyTurnAsLeader() bool {
}

t.log.Debug(msg,
"leader", t.addressConverter.ToBech32String(leaderAddress),
"leader", t.addressConverter.ToBech32StringSilent(leaderAddress),
"index", index,
"self address", t.addressConverter.ToBech32String(t.addressBytes))
"self address", t.addressConverter.ToBech32StringSilent(t.addressBytes))

return isLeader
}
Expand Down
10 changes: 8 additions & 2 deletions clients/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,15 @@ type DepositTransfer struct {
ConvertedTokenBytes []byte `json:"-"`
DisplayableToken string `json:"token"`
Amount *big.Int `json:"amount"`
ExtraGasLimit uint64 `json:"gasLimit"`
Data []byte `json:"-"`
DisplayableData string `json:"data"`
}

// String will convert the deposit transfer to a string
func (dt *DepositTransfer) String() string {
return fmt.Sprintf("to: %s, from: %s, token address: %s, amount: %v, deposit nonce: %d",
dt.DisplayableTo, dt.DisplayableFrom, dt.DisplayableToken, dt.Amount, dt.Nonce)
return fmt.Sprintf("to: %s, from: %s, token address: %s, amount: %v, deposit nonce: %d, gas limit: %d, hex data: %s",
dt.DisplayableTo, dt.DisplayableFrom, dt.DisplayableToken, dt.Amount, dt.Nonce, dt.ExtraGasLimit, dt.DisplayableData)
}

// Clone will deep clone the current DepositTransfer instance
Expand All @@ -94,12 +97,15 @@ func (dt *DepositTransfer) Clone() *DepositTransfer {
ConvertedTokenBytes: make([]byte, len(dt.ConvertedTokenBytes)),
DisplayableToken: dt.DisplayableToken,
Amount: big.NewInt(0),
Data: make([]byte, len(dt.Data)),
DisplayableData: dt.DisplayableData,
}

copy(cloned.ToBytes, dt.ToBytes)
copy(cloned.FromBytes, dt.FromBytes)
copy(cloned.TokenBytes, dt.TokenBytes)
copy(cloned.ConvertedTokenBytes, dt.ConvertedTokenBytes)
copy(cloned.Data, dt.Data)
if dt.Amount != nil {
cloned.Amount.Set(dt.Amount)
}
Expand Down
2 changes: 1 addition & 1 deletion clients/batchValidator/batchValidator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func TestBatchValidator_ValidateBatch(t *testing.T) {
},
Statuses: []byte{0x3, 0x4},
}
expectedJsonString := `{"batchId":1,"deposits":[{"nonce":1,"to":"to1","from":"from1","token":"token1","amount":1000000000000000000001},{"nonce":2,"to":"to2","from":"from2","token":"token2","amount":1000000000000000000002}],"statuses":"AwQ="}`
expectedJsonString := `{"batchId":1,"deposits":[{"nonce":1,"to":"to1","from":"from1","token":"token1","amount":1000000000000000000001,"gasLimit":0,"data":""},{"nonce":2,"to":"to2","from":"from2","token":"token2","amount":1000000000000000000002,"gasLimit":0,"data":""}],"statuses":"AwQ="}`

t.Run("server errors with Bad Request, but no reason", func(t *testing.T) {
t.Parallel()
Expand Down
9 changes: 6 additions & 3 deletions clients/batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestDepositTransfer_Clone(t *testing.T) {
DisplayableToken: "token",
Amount: big.NewInt(7463),
ConvertedTokenBytes: []byte("converted token"),
Data: []byte("tx data"),
}

cloned := dt.Clone()
Expand All @@ -42,7 +43,7 @@ func TestDepositTransfer_String(t *testing.T) {
Amount: big.NewInt(7463),
}

expectedString := "to: to, from: from, token address: token, amount: 7463, deposit nonce: 112334"
expectedString := "to: to, from: from, token address: token, amount: 7463, deposit nonce: 112334, gas limit: 0, hex data: "
assert.Equal(t, expectedString, dt.String())
}

Expand All @@ -62,6 +63,7 @@ func TestTransferBatch_Clone(t *testing.T) {
DisplayableToken: "token1",
Amount: big.NewInt(3344),
ConvertedTokenBytes: []byte("converted token1"),
Data: []byte("tx data"),
},
{
Nonce: 2,
Expand All @@ -73,6 +75,7 @@ func TestTransferBatch_Clone(t *testing.T) {
DisplayableToken: "token2",
Amount: big.NewInt(5566),
ConvertedTokenBytes: []byte("converted token2"),
Data: []byte("tx data"),
},
},
Statuses: []byte{Executed, Rejected},
Expand Down Expand Up @@ -115,8 +118,8 @@ func TestTransferBatch_String(t *testing.T) {
}

expectedString := `Batch id 2243:
to: to1, from: from1, token address: token1, amount: 3344, deposit nonce: 1
to: to2, from: from2, token address: token2, amount: 5566, deposit nonce: 2
to: to1, from: from1, token address: token1, amount: 3344, deposit nonce: 1, gas limit: 0, hex data:
to: to2, from: from2, token address: token2, amount: 5566, deposit nonce: 2, gas limit: 0, hex data:
Statuses: 0304`
assert.Equal(t, expectedString, tb.String())
}
Expand Down
Loading

0 comments on commit eb5baab

Please sign in to comment.