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 7 commits
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
73 changes: 70 additions & 3 deletions bridges/ethMultiversX/bridgeExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import (
"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-bridge-eth-go/core/converters"
"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,28 @@ 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
}

//if transfers == nil {
// return nil, ErrNilBatch
//}
sstanculeanu marked this conversation as resolved.
Show resolved Hide resolved

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

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

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 +189,53 @@ 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, 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.
sstanculeanu marked this conversation as resolved.
Show resolved Hide resolved

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
}

// 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 {
sstanculeanu marked this conversation as resolved.
Show resolved Hide resolved
return ErrInvalidTopicsNumber
}

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

if depositNonce == transfer.Nonce {
calldataBytes := event.Topics[8]
iulianpascalau marked this conversation as resolved.
Show resolved Hide resolved
processData(transfer, calldataBytes) //TODO: Further discussions are needed on this part
return nil
}
}

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

return nil
}

// GetStoredBatch returns the stored batch
func (executor *bridgeExecutor) GetStoredBatch() *bridgeCore.TransferBatch {
return executor.batch
Expand Down
191 changes: 187 additions & 4 deletions bridges/ethMultiversX/bridgeExecutor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package ethmultiversx

import (
"context"
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"math/big"
Expand All @@ -17,6 +19,7 @@ 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"
)
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,192 @@ 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", ErrBatchWithoutDeposits, 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 []*transaction.Events{}, 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)

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

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)
iulianpascalau marked this conversation as resolved.
Show resolved Hide resolved
})
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)
iulianpascalau marked this conversation as resolved.
Show resolved Hide resolved
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: "",
},
},
}

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)

err = executor.StoreBatchFromMultiversX(batch)
assert.Equal(t, providedBatch, executor.batch)
assert.Nil(t, err)
assert.Equal(t, expectedBatch, batch)
})
}

Expand Down
6 changes: 6 additions & 0 deletions bridges/ethMultiversX/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ var ErrNilStatusHandler = errors.New("nil status handler")
// ErrFinalBatchNotFound signals that a final batch was not found
var ErrFinalBatchNotFound = errors.New("final batch not found")

// ErrBatchWithoutDeposits signals that a batch was found, but has no deposits
var ErrBatchWithoutDeposits = errors.New("batch was found, but has no deposits")

// ErrInvalidTopicsNumber signals that an invalid number of topics was provided
var ErrInvalidTopicsNumber = errors.New("invalid number of topics")

// ErrNilSignaturesHolder signals that a nil signatures holder was provided
var ErrNilSignaturesHolder = errors.New("nil signatures holder")

Expand Down
2 changes: 2 additions & 0 deletions 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,6 +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, 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
Loading