Skip to content

Commit

Permalink
add GetBatchSCMetadata logic
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmatudor committed Sep 18, 2024
1 parent 648c93a commit e1261bf
Show file tree
Hide file tree
Showing 14 changed files with 374 additions and 117 deletions.
102 changes: 60 additions & 42 deletions bridges/ethMultiversX/bridgeExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ 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/clients/multiversx"
"github.com/multiversx/mx-bridge-eth-go/core"
bridgeCore "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"
"github.com/multiversx/mx-chain-core-go/data/transaction"
logger "github.com/multiversx/mx-chain-logger-go"
)

Expand Down Expand Up @@ -153,10 +155,24 @@ func (executor *bridgeExecutor) MyTurnAsLeader() bool {
// GetBatchFromMultiversX fetches the pending batch from MultiversX
func (executor *bridgeExecutor) GetBatchFromMultiversX(ctx context.Context) (*bridgeCore.TransferBatch, error) {
batch, err := executor.multiversXClient.GetPendingBatch(ctx)
if err == nil {
executor.statusHandler.SetIntMetric(core.MetricNumBatches, int(batch.ID)-1)
if err != nil {
return nil, err
}

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

isBatchInvalid := len(batch.Deposits) == 0
if isBatchInvalid {
return nil, fmt.Errorf("%w, fetched nonce: %d, num deposits: %d",
ErrFinalBatchNotFound, batch.ID, len(batch.Deposits))
}

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

return batch, nil
}

// StoreBatchFromMultiversX saves the pending batch from MultiversX
Expand All @@ -169,6 +185,47 @@ func (executor *bridgeExecutor) StoreBatchFromMultiversX(batch *bridgeCore.Trans
return nil
}

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

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

for i, t := range transfers.Deposits {
transfers.Deposits[i], err = executor.addMetadataToTransferMvx(t, events)
if err != nil {
return nil, err
}
}

return transfers, nil
}

// addMetadataToTransferMvx fetches the logs containing sc calls metadata for the current batch
func (executor *bridgeExecutor) addMetadataToTransferMvx(transfer *bridgeCore.DepositTransfer, events []*transaction.Events) (*bridgeCore.DepositTransfer, error) {
for _, event := range events {
depositNonce, err := multiversx.ParseUInt64FromByteSlice(event.Topics[1])
if err != nil {
return nil, fmt.Errorf("%w while parsing batch ID", err)
}

if depositNonce == transfer.Nonce {
processData(transfer, event.Topics[7])
return transfer, nil
}
}

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

return transfer, nil
}

// GetStoredBatch returns the stored batch
func (executor *bridgeExecutor) GetStoredBatch() *bridgeCore.TransferBatch {
return executor.batch
Expand Down Expand Up @@ -439,45 +496,6 @@ func (executor *bridgeExecutor) ResetRetriesCountOnMultiversX() {
executor.quorumRetriesOnMultiversX = 0
}

//// GetAndStoreBatchFromMultiversX fetches the logs containing sc calls metadata for the current batch from MultiversX side
//func (executor *bridgeExecutor) GetAndStoreBatchFromMultiversX(ctx context.Context, nonce uint64) error {
// batch, err := executor.multiversXClient.GetBatch(ctx, nonce)
// if err != nil {
// return err
// }
//
// isBatchInvalid := batch.ID != nonce || len(batch.Deposits) == 0
// if isBatchInvalid {
// return fmt.Errorf("%w, requested nonce: %d, fetched nonce: %d, num deposits: %d",
// ErrFinalBatchNotFound, nonce, batch.ID, len(batch.Deposits))
// }
//
// batch, err = executor.addBatchSCMetadataMvx(ctx, batch)
// if err != nil {
// return err
// }
// executor.batch = batch
//
// return nil
//}
//
//func (executor *bridgeExecutor) addBatchSCMetadataMvx(ctx context.Context, transfers *bridgeCore.TransferBatch) (*bridgeCore.TransferBatch, error) {
// if transfers == nil {
// return nil, ErrNilBatch
// }
//
// events, err := executor.multiversXClient.GetBatchSCMetadata(ctx, transfers.ID, transfers.BlockNumber)
// if err != nil {
// return nil, err
// }
//
// for i, t := range transfers.Deposits {
// transfers.Deposits[i] = executor.addMetadataToTransfer(t, events)
// }
//
// return transfers, nil
//}

// GetAndStoreBatchFromEthereum fetches and stores the batch from the ethereum client
func (executor *bridgeExecutor) GetAndStoreBatchFromEthereum(ctx context.Context, nonce uint64) error {
batch, isFinal, err := executor.ethereumClient.GetBatch(ctx, nonce)
Expand Down
150 changes: 146 additions & 4 deletions bridges/ethMultiversX/bridgeExecutor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ethmultiversx

import (
"context"
"encoding/binary"
"errors"
"fmt"
"math/big"
Expand All @@ -17,12 +18,14 @@ import (
"github.com/multiversx/mx-bridge-eth-go/testsCommon"
bridgeTests "github.com/multiversx/mx-bridge-eth-go/testsCommon/bridge"
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/data/transaction"
logger "github.com/multiversx/mx-chain-logger-go"
"github.com/stretchr/testify/assert"
)

var expectedErr = errors.New("expected error")
var providedBatch = &bridgeCore.TransferBatch{}
var providedTxnEvents []*transaction.Events
var expectedMaxRetries = uint64(3)

func createMockExecutorArgs() ArgsBridgeExecutor {
Expand Down Expand Up @@ -991,11 +994,11 @@ func TestMultiversXToEthBridgeExecutor_GetAndStoreBatchFromMultiversX(t *testing
err := executor.StoreBatchFromMultiversX(nil)
assert.Equal(t, ErrNilBatch, err)
})
t.Run("should work", func(t *testing.T) {
t.Run("no deposits should error", func(t *testing.T) {
t.Parallel()

wasCalled := false
args := createMockExecutorArgs()
wasCalled := false
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
wasCalled = true
Expand All @@ -1006,12 +1009,151 @@ func TestMultiversXToEthBridgeExecutor_GetAndStoreBatchFromMultiversX(t *testing
executor, _ := NewBridgeExecutor(args)
batch, err := executor.GetBatchFromMultiversX(context.Background())
assert.True(t, wasCalled)
assert.Equal(t, providedBatch, batch)
assert.Nil(t, batch)
assert.Equal(t, fmt.Errorf("%w, fetched nonce: %d, num deposits: %d", ErrFinalBatchNotFound, 0, 0), err)
})
t.Run("should work", func(t *testing.T) {
t.Parallel()

wasPendingBatchCalled := false
wasGetBatchSCMetadataCalled := false
providedBatchWithDeposits := &bridgeCore.TransferBatch{
Deposits: []*bridgeCore.DepositTransfer{{}, {}},
}
args := createMockExecutorArgs()
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
wasPendingBatchCalled = true
return providedBatchWithDeposits, nil
},
GetBatchSCMetadataCalled: func(ctx context.Context, batch *bridgeCore.TransferBatch) ([]*transaction.Events, error) {
wasGetBatchSCMetadataCalled = true
return providedTxnEvents, nil
},
}

executor, _ := NewBridgeExecutor(args)
batch, err := executor.GetBatchFromMultiversX(context.Background())
assert.True(t, wasPendingBatchCalled)
assert.True(t, wasGetBatchSCMetadataCalled)
assert.Equal(t, providedBatchWithDeposits, batch)
assert.Nil(t, err)

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

providedNonce := uint64(8346)
depositNonce := uint64(100)
depositData := []byte("testData")
expectedBatch := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
},
},
}
args := createMockExecutorArgs()
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
return expectedBatch, 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)
expectedDepositData := []byte{bridgeCore.DataPresentProtocolMarker, 0, 0, 0, byte(len(depositData))}
expectedDepositData = append(expectedDepositData, depositData...)
assert.Equal(t, string(expectedDepositData), string(batch.Deposits[0].Data))
})
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)
depositData := append([]byte{bridgeCore.MissingDataProtocolMarker}, "testData"...)
expectedBatch := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
},
},
}
args := createMockExecutorArgs()
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
return expectedBatch, 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)

err = executor.StoreBatchFromMultiversX(batch)
assert.Equal(t, providedBatch, executor.batch)
assert.Nil(t, err)
assert.True(t, expectedBatch == executor.GetStoredBatch()) // pointer testing
expectedDepositData := []byte{bridgeCore.DataPresentProtocolMarker, 0, 0, 0, byte(len(depositData))}
expectedDepositData = append(expectedDepositData, depositData...)
assert.Equal(t, string(expectedDepositData), string(executor.batch.Deposits[0].Data))
})
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)
depositData := []byte{bridgeCore.MissingDataProtocolMarker}
expectedBatch := &bridgeCore.TransferBatch{
ID: providedNonce,
Deposits: []*bridgeCore.DepositTransfer{
{
Nonce: depositNonce,
},
},
}
args := createMockExecutorArgs()
args.MultiversXClient = &bridgeTests.MultiversXClientStub{
GetPendingBatchCalled: func(ctx context.Context) (*bridgeCore.TransferBatch, error) {
return expectedBatch, 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)

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

Expand Down
3 changes: 2 additions & 1 deletion bridges/ethMultiversX/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract"
bridgeCore "github.com/multiversx/mx-bridge-eth-go/core"
"github.com/multiversx/mx-bridge-eth-go/core/batchProcessor"
"github.com/multiversx/mx-chain-core-go/data/transaction"
)

// MultiversXClient defines the behavior of the MultiversX client able to communicate with the MultiversX chain
Expand All @@ -25,7 +26,7 @@ type MultiversXClient interface {
GetLastExecutedEthBatchID(ctx context.Context) (uint64, error)
GetLastExecutedEthTxID(ctx context.Context) (uint64, error)
GetCurrentNonce(ctx context.Context) (uint64, error)
GetBatchSCMetadata(ctx context.Context, nonce uint64, blockNumber uint64)
GetBatchSCMetadata(ctx context.Context, batch *bridgeCore.TransferBatch) ([]*transaction.Events, error)

ProposeSetStatus(ctx context.Context, batch *bridgeCore.TransferBatch) (string, error)
ProposeTransfer(ctx context.Context, batch *bridgeCore.TransferBatch) (string, error)
Expand Down
Loading

0 comments on commit e1261bf

Please sign in to comment.