Skip to content

Commit

Permalink
Handle deployments and calls, with value, with signal error.
Browse files Browse the repository at this point in the history
  • Loading branch information
andreibancioiu committed Aug 20, 2024
1 parent bbc257b commit 5908701
Show file tree
Hide file tree
Showing 7 changed files with 392 additions and 49 deletions.
52 changes: 52 additions & 0 deletions server/services/testdata/blocks_with_contract_calls.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[
{
"comment": "block with intra-shard contract call, with move balance, with signal error",
"miniBlocks": [
{
"transactions": [
{
"type": "normal",
"processingTypeOnSource": "SCInvoking",
"processingTypeOnDestination": "SCInvoking",
"hash": "9851ab6cb221bce5800030f9db2a5fbd8ed4a9db4c6f9d190c16113f2b080e57",
"value": "10000000000000000",
"receiver": "erd1qqqqqqqqqqqqqpgqagjekf5mxv86hy5c62vvtug5vc6jmgcsq6uq8reras",
"sender": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"sourceShard": 0,
"destinationShard": 0,
"logs": {
"address": "erd1qqqqqqqqqqqqqpgqagjekf5mxv86hy5c62vvtug5vc6jmgcsq6uq8reras",
"events": [
{
"address": "erd1qqqqqqqqqqqqqpgqagjekf5mxv86hy5c62vvtug5vc6jmgcsq6uq8reras",
"identifier": "signalError",
"topics": [
"XPSryD5QxTCdgH/D9naYh1mh4wEAG8mgJlgE9Cr4Brg=",
"aW52YWxpZCBmdW5jdGlvbiAobm90IGZvdW5kKQ=="
],
"data": "QDY2NzU2ZTYzNzQ2OTZmNmUyMDZlNmY3NDIwNjY2Zjc1NmU2NA==",
"additionalData": [
"QDY2NzU2ZTYzNzQ2OTZmNmUyMDZlNmY3NDIwNjY2Zjc1NmU2NA=="
]
},
{
"address": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"identifier": "internalVMErrors",
"topics": [
"AAAAAAAAAAAFAOolmyabMw+rkpjSmMXxFGY1LaMQBrg=",
"bWlzc2luZ0Z1bmN0aW9u"
],
"data": "CglydW50aW1lLmdvOjgzMSBbaW52YWxpZCBmdW5jdGlvbiAobm90IGZvdW5kKV0gW21pc3NpbmdGdW5jdGlvbl0=",
"additionalData": [
"CglydW50aW1lLmdvOjgzMSBbaW52YWxpZCBmdW5jdGlvbiAobm90IGZvdW5kKV0gW21pc3NpbmdGdW5jdGlvbl0="
]
}
]
},
"initiallyPaidFee": "144050000000000"
}
]
}
]
}
]
98 changes: 98 additions & 0 deletions server/services/testdata/blocks_with_contract_deployments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
[
{
"comment": "block with contract deployment, with move balance",
"miniBlocks": [
{
"transactions": [
{
"type": "normal",
"processingTypeOnSource": "SCDeployment",
"processingTypeOnDestination": "SCDeployment",
"hash": "2459bb2b9a64c1c920777ecbdaf0fa33d7fe8bcd24d7164562f341b2e4f702da",
"value": "10000000000000000",
"receiver": "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu",
"sender": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"logs": {
"address": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"events": [
{
"address": "erd1qqqqqqqqqqqqqpgqc4vdnqgc48ww26ljxqe2flgl86jewg0nq6uqna2ymj",
"identifier": "SCDeploy",
"topics": [
"AAAAAAAAAAAFAMVY2YEYqdzla/IwMqT9Hz6llyHzBrg=",
"XPSryD5QxTCdgH/D9naYh1mh4wEAG8mgJlgE9Cr4Brg=",
"v5gJ+IK1KdPGJfGYibrKij1SO0bzAAhfUVsODJ8midg="
],
"data": null,
"additionalData": null
},
{
"address": "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu",
"identifier": "writeLog",
"topics": [
"XPSryD5QxTCdgH/D9naYh1mh4wEAG8mgJlgE9Cr4Brg=",
"QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNDU4ODUwMCwgZ2FzIHVzZWQgPSAzMzQ1MDU="
],
"data": "QDZmNmI=",
"additionalData": ["QDZmNmI="]
}
]
},
"operation": "scDeploy",
"initiallyPaidFee": "457385000000000"
}
]
}
]
},
{
"comment": "block with contract deployment, with move balance, with signal error",
"miniBlocks": [
{
"transactions": [
{
"type": "normal",
"processingTypeOnSource": "SCDeployment",
"processingTypeOnDestination": "SCDeployment",
"hash": "52b74f025158f18512353da5f23c2e31c78c49d7b73da7d24f048f86da48b5c5",
"value": "77",
"receiver": "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu",
"sender": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"sourceShard": 0,
"destinationShard": 0,
"logs": {
"address": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"events": [
{
"address": "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu",
"identifier": "signalError",
"topics": [
"XPSryD5QxTCdgH/D9naYh1mh4wEAG8mgJlgE9Cr4Brg=",
"ZnVuY3Rpb24gZG9lcyBub3QgYWNjZXB0IEVHTEQgcGF5bWVudA=="
],
"data": "QDY1Nzg2NTYzNzU3NDY5NmY2ZTIwNjY2MTY5NmM2NTY0",
"additionalData": [
"QDY1Nzg2NTYzNzU3NDY5NmY2ZTIwNjY2MTY5NmM2NTY0"
]
},
{
"address": "erd1tn62hjp72rznp8vq0lplva5csav6rccpqqdungpxtqz0g2hcq6uq9k4cc6",
"identifier": "internalVMErrors",
"topics": [
"XPSryD5QxTCdgH/D9naYh1mh4wEAG8mgJlgE9Cr4Brg=",
"X2luaXQ="
],
"data": "CglydW50aW1lLmdvOjgzNCBbZXhlY3V0aW9uIGZhaWxlZF0gW10KCXJ1bnRpbWUuZ286ODM0IFtleGVjdXRpb24gZmFpbGVkXSBbXQoJcnVudGltZS5nbzo4MzEgW2Z1bmN0aW9uIGRvZXMgbm90IGFjY2VwdCBFR0xEIHBheW1lbnRd",
"additionalData": [
"CglydW50aW1lLmdvOjgzNCBbZXhlY3V0aW9uIGZhaWxlZF0gW10KCXJ1bnRpbWUuZ286ODM0IFtleGVjdXRpb24gZmFpbGVkXSBbXQoJcnVudGltZS5nbzo4MzEgW2Z1bmN0aW9uIGRvZXMgbm90IGFjY2VwdCBFR0xEIHBheW1lbnRd"
]
}
]
},
"initiallyPaidFee": "2206715000000000"
}
]
}
]
}
]
20 changes: 20 additions & 0 deletions server/services/transactionsFeaturesDetector.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,23 @@ func (detector *transactionsFeaturesDetector) isRelayedV1TransactionCompletelyIn
isWithSignalError := detector.eventsController.hasAnySignalError(tx)
return isWithSignalError
}

func (detector *transactionsFeaturesDetector) isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx *transaction.ApiTransactionResult) bool {
return detector.isContractDeploymentWithSignalError(tx) || (detector.isIntrashard(tx) && detector.isContractCallWithSignalError(tx))
}

func (detector *transactionsFeaturesDetector) isContractDeploymentWithSignalError(tx *transaction.ApiTransactionResult) bool {
return tx.ProcessingTypeOnSource == transactionProcessingTypeContractDeployment &&
tx.ProcessingTypeOnDestination == transactionProcessingTypeContractDeployment &&
detector.eventsController.hasAnySignalError(tx)
}

func (detector *transactionsFeaturesDetector) isContractCallWithSignalError(tx *transaction.ApiTransactionResult) bool {
return tx.ProcessingTypeOnSource == transactionProcessingTypeContractInvoking &&
tx.ProcessingTypeOnDestination == transactionProcessingTypeContractInvoking &&
detector.eventsController.hasAnySignalError(tx)
}

func (detector *transactionsFeaturesDetector) isIntrashard(tx *transaction.ApiTransactionResult) bool {
return tx.SourceShard == tx.DestinationShard
}
104 changes: 104 additions & 0 deletions server/services/transactionsFeaturesDetector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,107 @@ func TestTransactionsFeaturesDetector_isRelayedV1TransactionCompletelyIntrashard
require.True(t, featureDetected)
})
}

func TestTransactionsFeatureDetector_isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(t *testing.T) {
networkProvider := testscommon.NewNetworkProviderMock()
detector := newTransactionsFeaturesDetector(networkProvider)

t.Run("contract deployment, with signal error", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
ProcessingTypeOnSource: transactionProcessingTypeContractDeployment,
ProcessingTypeOnDestination: transactionProcessingTypeContractDeployment,
Logs: &transaction.ApiLogs{
Events: []*transaction.Events{
{
Identifier: transactionEventSignalError,
},
},
},
}

require.True(t, detector.isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx))
})

t.Run("contract deployment, without signal error", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
ProcessingTypeOnSource: transactionProcessingTypeContractDeployment,
ProcessingTypeOnDestination: transactionProcessingTypeContractDeployment,
}

require.False(t, detector.isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx))
})

t.Run("contract call, with signal error, intra-shard", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
ProcessingTypeOnSource: transactionProcessingTypeContractInvoking,
ProcessingTypeOnDestination: transactionProcessingTypeContractInvoking,
SourceShard: 2,
DestinationShard: 2,
Logs: &transaction.ApiLogs{
Events: []*transaction.Events{
{
Identifier: transactionEventSignalError,
},
},
},
}

require.True(t, detector.isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx))
})

t.Run("contract call, with signal error, cross-shard", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
ProcessingTypeOnSource: transactionProcessingTypeContractInvoking,
ProcessingTypeOnDestination: transactionProcessingTypeContractInvoking,
SourceShard: 0,
DestinationShard: 1,
Logs: &transaction.ApiLogs{
Events: []*transaction.Events{
{
Identifier: transactionEventSignalError,
},
},
},
}

require.False(t, detector.isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx))
})

t.Run("contract call, without signal error", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
ProcessingTypeOnSource: transactionProcessingTypeContractInvoking,
ProcessingTypeOnDestination: transactionProcessingTypeContractInvoking,
}

require.False(t, detector.isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx))
})

t.Run("arbitrary transaction", func(t *testing.T) {
tx := &transaction.ApiTransactionResult{
ProcessingTypeOnSource: transactionProcessingTypeMoveBalance,
ProcessingTypeOnDestination: transactionProcessingTypeMoveBalance,
}

require.False(t, detector.isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx))
})
}

func TestTransactionsFeaturesDetector_isIntrashard(t *testing.T) {
networkProvider := testscommon.NewNetworkProviderMock()
detector := newTransactionsFeaturesDetector(networkProvider)

require.True(t, detector.isIntrashard(&transaction.ApiTransactionResult{
SourceShard: 0,
DestinationShard: 0,
}))

require.True(t, detector.isIntrashard(&transaction.ApiTransactionResult{
SourceShard: 1,
DestinationShard: 1,
}))

require.False(t, detector.isIntrashard(&transaction.ApiTransactionResult{
SourceShard: 0,
DestinationShard: 1,
}))
}
15 changes: 12 additions & 3 deletions server/services/transactionsTransformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,15 @@ func (transformer *transactionsTransformer) rewardTxToRosettaTx(tx *transaction.
}

func (transformer *transactionsTransformer) normalTxToRosetta(tx *transaction.ApiTransactionResult) (*types.Transaction, error) {
hasValue := !isZeroAmount(tx.Value)
operations := make([]*types.Operation, 0)

if hasValue {
// Special handling of:
// - intra-shard contract calls, bearing value, which fail with signal error
// - direct contract deployments, bearing value, which fail with signal error
// For these, the protocol does not generate an explicit SCR with the value refund (before Sirius, in some circumstances, it did).
// However, since the value remains at the sender, we don't emit any operations in these circumstances.
transfersValue := isNonZeroAmount(tx.Value) && !transformer.featuresDetector.isContractDeploymentWithSignalErrorOrIntrashardContractCallWithSignalError(tx)
if transfersValue {
operations = append(operations, &types.Operation{
Type: opTransfer,
Account: addressToAccountIdentifier(tx.Sender),
Expand All @@ -200,6 +205,10 @@ func (transformer *transactionsTransformer) normalTxToRosetta(tx *transaction.Ap
return nil, err
}

if len(innerTxOperationsIfRelayedCompletelyIntrashardWithSignalError) > 0 {
log.Info("normalTxToRosetta(): innerTxOperationsIfRelayedCompletelyIntrashardWithSignalError", "tx", tx.Hash, "block", tx.BlockNonce)
}

operations = append(operations, innerTxOperationsIfRelayedCompletelyIntrashardWithSignalError...)

return &types.Transaction{
Expand Down Expand Up @@ -364,7 +373,7 @@ func (transformer *transactionsTransformer) addOperationsGivenTransactionEvents(
}

for _, event := range eventsSCDeploy {
// Handle direct deployments with transfer of value (indirect deployments are currently excluded to prevent any potential misinterpretations)..
// Handle direct deployments with transfer of value (indirect deployments are currently excluded to prevent any potential misinterpretations).
if tx.Receiver == systemContractDeployAddress {
operations := []*types.Operation{
// Deployer's balance change is already captured in operations recovered not from logs / events, but from the transaction itself.
Expand Down
Loading

0 comments on commit 5908701

Please sign in to comment.