Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge implementation to v3.5 #342

Merged
merged 8 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 66 additions & 49 deletions bridges/ethMultiversX/bridgeExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,22 @@ 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

const (
// splits - represent the number of times we split the maximum interval
// we wait for the transfer confirmation on Ethereum
splits = 10

// Minimum number of retries
minRetries = 1

// Number of topics required for createTransactionScCallEvent
scCallEventTopicsCount = 9

// Indices for specific topics in createTransactionScCallEvent
depositNonceIndex = 1
calldataIndex = 8
)

// ArgsBridgeExecutor is the arguments DTO struct used in both bridges
type ArgsBridgeExecutor struct {
Expand Down Expand Up @@ -159,9 +173,9 @@ func (executor *bridgeExecutor) GetBatchFromMultiversX(ctx context.Context) (*br
return nil, err
}

//if transfers == nil {
// return nil, ErrNilBatch
//}
if batch == nil {
return nil, ErrNilBatch
}

executor.statusHandler.SetIntMetric(core.MetricNumBatches, int(batch.ID)-1)

Expand Down Expand Up @@ -192,48 +206,48 @@ func (executor *bridgeExecutor) StoreBatchFromMultiversX(batch *bridgeCore.Trans
// addBatchSCMetadataMvx fetches the logs containing sc calls metadata for the current batch
func (executor *bridgeExecutor) addBatchSCMetadataMvx(ctx context.Context, batch *bridgeCore.TransferBatch) (*bridgeCore.TransferBatch, error) {
events, err := executor.multiversXClient.GetBatchSCMetadata(ctx, batch)
// TODO: I was thinking that if we want to have a mapping of events based on the deposit nonce,
// it would be better to modify the FilterLogs function in the SDK directly to create and return such a mapping on the spot,
//rather than doing the mapping here. Otherwise, I still need to loop through the array to create the mapping.

if err != nil {
return nil, err
}

for _, t := range batch.Deposits {
err = executor.addMetadataToTransferMvx(t, events)
if err != nil {
return nil, err
}
}

return batch, nil
}
eventsByDepositNonce := make(map[uint64]*transaction.Events)

// addMetadataToTransferMvx fetches the logs containing sc calls metadata for the current batch
func (executor *bridgeExecutor) addMetadataToTransferMvx(transfer *bridgeCore.DepositTransfer, events []*transaction.Events) error {
for _, event := range events {
if len(event.Topics) != 9 {
return ErrInvalidTopicsNumber
if len(event.Topics) < scCallEventTopicsCount {
return nil, ErrInvalidTopicsNumber
}

depositNonceBytes := event.Topics[1]
depositNonceBytes := event.Topics[depositNonceIndex]
depositNonce, err := converters.ParseUInt64FromByteSlice(depositNonceBytes)
if err != nil {
return fmt.Errorf("%w while parsing deposit nonce", err)
return nil, fmt.Errorf("%w while parsing deposit nonce", err)
}

if depositNonce == transfer.Nonce {
calldataBytes := event.Topics[8]
processData(transfer, calldataBytes) //TODO: Further discussions are needed on this part
return nil
}
eventsByDepositNonce[depositNonce] = event
}

transfer.Data = []byte{bridgeCore.MissingDataProtocolMarker}
transfer.DisplayableData = ""
for _, t := range batch.Deposits {
executor.addMetadataToTransferMvx(t, eventsByDepositNonce)
}

return nil
return batch, nil
}

// addMetadataToTransferMvx fetches the logs containing sc calls metadata for the current batch
func (executor *bridgeExecutor) addMetadataToTransferMvx(transfer *bridgeCore.DepositTransfer, eventsByDepositNonce map[uint64]*transaction.Events) {
event, exists := eventsByDepositNonce[transfer.Nonce]
if !exists {
transfer.DisplayableData = ""
return
}

calldataBytes := event.Topics[calldataIndex]
processDataForMvx(transfer, calldataBytes)
}

func processDataForMvx(transfer *bridgeCore.DepositTransfer, buff []byte) {
transfer.Data = buff
transfer.DisplayableData = hex.EncodeToString(transfer.Data)
}

// GetStoredBatch returns the stored batch
Expand Down Expand Up @@ -529,38 +543,41 @@ func (executor *bridgeExecutor) GetAndStoreBatchFromEthereum(ctx context.Context
}

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

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

for i, t := range transfers.Deposits {
transfers.Deposits[i] = executor.addMetadataToTransfer(t, events)
eventsByDepositNonce := make(map[uint64]*contract.ERC20SafeERC20SCDeposit)

for _, event := range events {
eventsByDepositNonce[event.DepositNonce.Uint64()] = event
}

for _, t := range batch.Deposits {
executor.addMetadataToTransfer(t, eventsByDepositNonce)
}

return transfers, nil
return batch, nil
}

func (executor *bridgeExecutor) addMetadataToTransfer(transfer *bridgeCore.DepositTransfer, events []*contract.ERC20SafeERC20SCDeposit) *bridgeCore.DepositTransfer {
for _, event := range events {
if event.DepositNonce.Uint64() == transfer.Nonce {
processData(transfer, event.CallData)
return transfer
}
func (executor *bridgeExecutor) addMetadataToTransfer(transfer *bridgeCore.DepositTransfer, eventsByDepositNonce map[uint64]*contract.ERC20SafeERC20SCDeposit) {
event, exist := eventsByDepositNonce[transfer.Nonce]
if !exist {
transfer.Data = []byte{bridgeCore.MissingDataProtocolMarker}
transfer.DisplayableData = ""
return
}

transfer.Data = []byte{bridgeCore.MissingDataProtocolMarker}
transfer.DisplayableData = ""

return transfer
processDataForEth(transfer, event.CallData)
}

func processData(transfer *bridgeCore.DepositTransfer, buff []byte) {
func processDataForEth(transfer *bridgeCore.DepositTransfer, buff []byte) {
transfer.Data = buff
dataLen := len(transfer.Data)
if dataLen == 0 {
Expand Down
111 changes: 2 additions & 109 deletions bridges/ethMultiversX/bridgeExecutor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ func TestMultiversXToEthBridgeExecutor_GetAndStoreBatchFromMultiversX(t *testing
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
wasCalled = true
return providedBatch, nil
return &bridgeCore.TransferBatch{}, nil
},
}

Expand Down Expand Up @@ -1059,117 +1059,13 @@ func TestMultiversXToEthBridgeExecutor_GetAndStoreBatchFromMultiversX(t *testing
}

depositData := []byte("testData")
expectedDepositData := []byte{bridgeCore.DataPresentProtocolMarker, 0, 0, 0, byte(len(depositData))}
expectedDepositData = append(expectedDepositData, depositData...)
expectedBatch := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
Data: expectedDepositData,
DisplayableData: hex.EncodeToString(depositData),
},
},
}

args := createMockExecutorArgs()
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
return providedBatchWithDeposit, nil
},
GetBatchSCMetadataCalled: func(ctx context.Context, batch *bridgeCore.TransferBatch) ([]*transaction.Events, error) {
depositNonceBytes := make([]byte, 8)
binary.BigEndian.PutUint64(depositNonceBytes, depositNonce)
return []*transaction.Events{
{Topics: [][]byte{{}, depositNonceBytes, {}, {}, {}, {}, {}, {}, depositData}},
}, nil
},
}

executor, _ := NewBridgeExecutor(args)
batch, err := executor.GetBatchFromMultiversX(context.Background())
assert.Nil(t, err)
assert.Equal(t, expectedBatch, batch)
})
t.Run("should add deposits metadata for sc calls with a data starting with missing data marker", func(t *testing.T) {
t.Parallel()

providedNonce := uint64(8346)
depositNonce := uint64(100)

providedBatchWithDeposit := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
},
},
}

depositData := append([]byte{bridgeCore.MissingDataProtocolMarker}, "testData"...)
expectedDepositData := []byte{bridgeCore.DataPresentProtocolMarker, 0, 0, 0, byte(len(depositData))}
expectedDepositData = append(expectedDepositData, depositData...)
expectedBatch := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
Data: expectedDepositData,
DisplayableData: hex.EncodeToString(depositData),
},
},
}

args := createMockExecutorArgs()
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
return providedBatchWithDeposit, nil
},
GetBatchSCMetadataCalled: func(ctx context.Context, batch *bridgeCore.TransferBatch) ([]*transaction.Events, error) {
depositNonceBytes := make([]byte, 8)
binary.BigEndian.PutUint64(depositNonceBytes, depositNonce)
return []*transaction.Events{
{Topics: [][]byte{{}, depositNonceBytes, {}, {}, {}, {}, {}, {}, depositData}},
}, nil
},
}

executor, _ := NewBridgeExecutor(args)
batch, err := executor.GetBatchFromMultiversX(context.Background())
assert.Nil(t, err)

fmt.Println(expectedBatch.Deposits[0].Data)
fmt.Println(batch.Deposits[0].Data)
fmt.Println(expectedBatch.Deposits[0])
fmt.Println(batch.Deposits[0])

err = executor.StoreBatchFromMultiversX(batch)
assert.Nil(t, err)
assert.Equal(t, expectedBatch, batch)
})
t.Run("should add deposits metadata for sc calls even if with no data", func(t *testing.T) {
t.Parallel()

providedNonce := uint64(8346)
depositNonce := uint64(100)

providedBatchWithDeposit := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
},
},
}

depositData := []byte{bridgeCore.MissingDataProtocolMarker}
expectedBatch := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
Data: depositData,
DisplayableData: "",
DisplayableData: hex.EncodeToString(depositData),
},
},
}
Expand All @@ -1191,9 +1087,6 @@ func TestMultiversXToEthBridgeExecutor_GetAndStoreBatchFromMultiversX(t *testing
executor, _ := NewBridgeExecutor(args)
batch, err := executor.GetBatchFromMultiversX(context.Background())
assert.Nil(t, err)

err = executor.StoreBatchFromMultiversX(batch)
assert.Nil(t, err)
assert.Equal(t, expectedBatch, batch)
})
}
Expand Down
17 changes: 14 additions & 3 deletions clients/multiversx/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ func (c *client) GetBatchSCMetadata(ctx context.Context, batch *bridgeCore.Trans
return nil, err
}

eventInBytes := []byte("createTransactionScCallEvent")

minBlockNumber := int64(math.MaxInt64)
maxBlockNumber := int64(math.MinInt64)
for _, dt := range batch.Deposits {
Expand All @@ -266,13 +268,22 @@ func (c *client) GetBatchSCMetadata(ctx context.Context, batch *bridgeCore.Trans
}
}

eventInBytes := []byte("createTransactionScCallEvent")
// checks for underflow
fromBlock := minBlockNumber + c.eventsBlockRangeFrom
if fromBlock < 0 {
fromBlock = 0
}

toBlock := maxBlockNumber + c.eventsBlockRangeTo
if toBlock < 0 {
toBlock = 0
}

query := core.FilterQuery{
Addresses: []string{safeContractAddress},
Topics: [][]byte{eventInBytes},
FromBlock: mxCore.OptionalUint64{Value: uint64(minBlockNumber + c.eventsBlockRangeFrom), HasValue: true},
ToBlock: mxCore.OptionalUint64{Value: uint64(maxBlockNumber + c.eventsBlockRangeTo), HasValue: true},
FromBlock: mxCore.OptionalUint64{Value: uint64(fromBlock), HasValue: true},
ToBlock: mxCore.OptionalUint64{Value: uint64(toBlock), HasValue: true},
}

events, err := c.proxy.FilterLogs(ctx, &query)
Expand Down
Loading
Loading