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

Add SC calls handling for ETH->MvX #267

Merged
merged 19 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
141 changes: 137 additions & 4 deletions bridges/ethMultiversX/bridgeExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ type bridgeExecutor struct {
maxQuorumRetriesOnMultiversX uint64
maxRetriesOnWasProposed uint64

// TODO: when implementing MVX->ETH direction, batch should be removed
batch *clients.TransferBatch
transfersBatch *clients.TransferBatch
scExecutionTransfersBatch *clients.TransferBatch
scExecutionMetadataBatch *clients.SCBatch
actionID uint64
batchTypeExecutionStep core.StepIdentifier
msgHash common.Hash
quorumRetriesOnEthereum uint64
quorumRetriesOnMultiversX uint64
Expand Down Expand Up @@ -169,6 +174,16 @@ func (executor *bridgeExecutor) GetStoredBatch() *clients.TransferBatch {
return executor.batch
}

// GetTransfersStoredBatch filters out SC calls from the current batch and only returns regular transfers
func (executor *bridgeExecutor) GetTransfersStoredBatch() *clients.TransferBatch {
return executor.transfersBatch
}

// GetSCExecStoredBatch returns only SC calls from the current bridge
func (executor *bridgeExecutor) GetSCExecStoredBatch() *clients.TransferBatch {
return executor.scExecutionTransfersBatch
}

// GetLastExecutedEthBatchIDFromMultiversX returns the last executed batch ID that is stored on the MultiversX SC
func (executor *bridgeExecutor) GetLastExecutedEthBatchIDFromMultiversX(ctx context.Context) (uint64, error) {
batchID, err := executor.multiversXClient.GetLastExecutedEthBatchID(ctx)
Expand Down Expand Up @@ -221,6 +236,22 @@ func (executor *bridgeExecutor) GetAndStoreActionIDForProposeTransferOnMultivers
return actionID, nil
}

// GetAndStoreActionIDForProposeSCTransferOnMultiversX fetches the action ID for ProposeSCTransfer by using the stored batch. Stores the action ID and returns it
func (executor *bridgeExecutor) GetAndStoreActionIDForProposeSCTransferOnMultiversX(ctx context.Context) (uint64, error) {
if executor.scExecutionTransfersBatch == nil {
return InvalidActionID, ErrNilBatch
}

actionID, err := executor.multiversXClient.GetActionIDForProposeTransfer(ctx, executor.scExecutionTransfersBatch)
if err != nil {
return InvalidActionID, err
}

executor.actionID = actionID

return actionID, nil
}

// GetAndStoreActionIDForProposeSetStatusFromMultiversX fetches the action ID for SetStatus by using the stored batch. Stores the action ID and returns it
func (executor *bridgeExecutor) GetAndStoreActionIDForProposeSetStatusFromMultiversX(ctx context.Context) (uint64, error) {
if executor.batch == nil {
Expand All @@ -242,18 +273,40 @@ func (executor *bridgeExecutor) GetStoredActionID() uint64 {
return executor.actionID
}

// GetBatchTypeExecutionStep returns the current batch type execution step - we could be either
//
// processing transactions, either smart contract calls
func (executor *bridgeExecutor) GetBatchTypeExecutionStep() core.StepIdentifier {
return executor.batchTypeExecutionStep
}

// SetBatchTypeExecutionStep sets the progress of the tx type being executed from the current batch
func (executor *bridgeExecutor) SetBatchTypeExecutionStep(identifier core.StepIdentifier) {
executor.batchTypeExecutionStep = identifier
}

// WasTransferProposedOnMultiversX checks if the transfer was proposed on MultiversX
func (executor *bridgeExecutor) WasTransferProposedOnMultiversX(ctx context.Context) (bool, error) {
if executor.batch == nil {
if executor.batch == nil || executor.transfersBatch == nil {
fmt.Println("returning false")
return false, ErrNilBatch
}

return executor.multiversXClient.WasProposedTransfer(ctx, executor.transfersBatch)
}

// WasSCTransferProposedOnMultiversX checks if the transfer containing sc calls was proposed on MultiversX
func (executor *bridgeExecutor) WasSCTransferProposedOnMultiversX(ctx context.Context) (bool, error) {
if executor.batch == nil || executor.scExecutionTransfersBatch == nil {
return false, ErrNilBatch
}

return executor.multiversXClient.WasProposedTransfer(ctx, executor.batch)
return executor.multiversXClient.WasProposedTransfer(ctx, executor.scExecutionTransfersBatch)
}

// ProposeTransferOnMultiversX propose the transfer on MultiversX
func (executor *bridgeExecutor) ProposeTransferOnMultiversX(ctx context.Context) error {
if executor.batch == nil {
if executor.batch == nil || executor.transfersBatch == nil {
return ErrNilBatch
}

Expand All @@ -268,6 +321,23 @@ func (executor *bridgeExecutor) ProposeTransferOnMultiversX(ctx context.Context)
return nil
}

// ProposeSCTransferOnMultiversX sends the proposal for smart contract transfers to the MultiversX bridge smart contract
func (executor *bridgeExecutor) ProposeSCTransferOnMultiversX(ctx context.Context) error {
if executor.batch == nil || executor.scExecutionMetadataBatch == nil {
return ErrNilBatch
}

hash, err := executor.multiversXClient.ProposeSCTransfer(ctx, executor.scExecutionTransfersBatch, executor.scExecutionMetadataBatch)
if err != nil {
return err
}

executor.log.Info("proposed transfer", "hash", hash,
"batch ID", executor.batch.ID, "action ID", executor.actionID)

return nil
}

// ProcessMaxRetriesOnWasTransferProposedOnMultiversX checks if the retries on MultiversX were reached and increments the counter
func (executor *bridgeExecutor) ProcessMaxRetriesOnWasTransferProposedOnMultiversX() bool {
if executor.retriesOnWasProposed < executor.maxRetriesOnWasProposed {
Expand Down Expand Up @@ -441,17 +511,80 @@ func (executor *bridgeExecutor) GetAndStoreBatchFromEthereum(ctx context.Context
return err
}

isBatchInvalid := batch.ID != nonce || len(batch.Deposits) == 0
isBatchInvalid := batch.ID != nonce || len(batch.Deposits) == 0 || len(batch.Deposits) != len(batch.Statuses)
if isBatchInvalid {
return fmt.Errorf("%w, requested nonce: %d, fetched nonce: %d, num deposits: %d",
ErrBatchNotFound, nonce, batch.ID, len(batch.Deposits))
}

executor.batch = batch

transfers := &clients.TransferBatch{
ID: executor.batch.ID,
Statuses: make([]byte, 0),
Deposits: make([]*clients.DepositTransfer, 0),
}
scCalls := &clients.TransferBatch{
ID: executor.batch.ID,
Statuses: make([]byte, 0),
Deposits: make([]*clients.DepositTransfer, 0),
}

for i := 0; i < len(executor.batch.Deposits); i++ {
if executor.ethereumClient.IsDepositSCCall(executor.batch.Deposits[i]) {
scCalls.Statuses = append(scCalls.Statuses, executor.batch.Statuses[i])
scCalls.Deposits = append(scCalls.Deposits, executor.batch.Deposits[i])
} else {
transfers.Statuses = append(transfers.Statuses, executor.batch.Statuses[i])
transfers.Deposits = append(transfers.Deposits, executor.batch.Deposits[i])
}
}

executor.transfersBatch = transfers
executor.scExecutionTransfersBatch = scCalls

return nil
}

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

if executor.scExecutionMetadataBatch != nil && executor.scExecutionMetadataBatch.ID == executor.scExecutionTransfersBatch.ID {
return executor.scExecutionMetadataBatch, nil
}

depositsMetadata := &clients.SCBatch{
ID: executor.scExecutionTransfersBatch.ID,
Deposits: make([]*clients.DepositSCMetadata, 0),
}

if len(executor.scExecutionTransfersBatch.Deposits) == 0 {
return depositsMetadata, nil
}

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

for _, event := range events {
dm := &clients.DepositSCMetadata{
BatchNonce: event.BatchNonce,
DepositNonce: event.DepositNonce,
CallData: event.CallData,
}

depositsMetadata.Deposits = append(depositsMetadata.Deposits, dm)
}

executor.scExecutionMetadataBatch = depositsMetadata

return depositsMetadata, nil
}

// 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
Loading
Loading