Skip to content

Commit

Permalink
Merge pull request #319 from multiversx/relayed-v3-multiple-scrs-with…
Browse files Browse the repository at this point in the history
…-refund

Multiple scrs with refund
  • Loading branch information
miiu96 authored Jan 16, 2025
2 parents 5b15bfa + 62f5c34 commit 5e055ee
Show file tree
Hide file tree
Showing 13 changed files with 281 additions and 18 deletions.
1 change: 1 addition & 0 deletions data/scresult.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ type ScResult struct {
SenderAddressBytes []byte `json:"-"`
InitialTxGasUsed uint64 `json:"-"`
InitialTxFee string `json:"-"`
GasRefunded uint64 `json:"-"`
}
11 changes: 6 additions & 5 deletions data/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ type Transaction struct {
CompletedEvent bool `json:"completedEvent,omitempty"`
RelayedAddr string `json:"relayer,omitempty"`
RelayedSignature string `json:"relayerSignature,omitempty"`
HadRefund bool `json:"hadRefund,omitempty"`
ExecutionOrder int `json:"-"`
SmartContractResults []*ScResult `json:"-"`
Hash string `json:"-"`
BlockHash string `json:"-"`
HadRefund bool `json:"-"`
}

// Receipt is a structure containing all the fields that need to be safe for a Receipt
Expand Down Expand Up @@ -89,8 +89,9 @@ type ResponseTransactionDB struct {

// FeeData is the structure that contains data about transaction fee and gas used
type FeeData struct {
FeeNum float64
Fee string
GasUsed uint64
Receiver string
FeeNum float64
Fee string
GasUsed uint64
Receiver string
GasRefunded uint64
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/gin-contrib/cors v1.4.0
github.com/gin-gonic/gin v1.9.1
github.com/multiversx/mx-chain-communication-go v1.1.0
github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8
github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4
github.com/multiversx/mx-chain-logger-go v1.0.15
github.com/multiversx/mx-chain-vm-common-go v1.5.13
github.com/prometheus/client_model v0.4.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiversx/mx-chain-communication-go v1.1.0 h1:J7bX6HoN3HiHY7cUeEjG8AJWgQDDPcY+OPDOsSUOkRE=
github.com/multiversx/mx-chain-communication-go v1.1.0/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM=
github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8 h1:0ivlwcl+dKK7BTVngm1uNM2aDneaXK2rhS0HVeBkvYg=
github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE=
github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4 h1:rWYFL38q5cbo5MtdW2DvAp4+WMaVp8e7gBjmrLQ9SCY=
github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE=
github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk=
github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc=
github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ=
Expand Down
139 changes: 139 additions & 0 deletions integrationtests/relayedV3_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//go:build integrationtests

package integrationtests

import (
"context"
"encoding/hex"
"math/big"
"testing"

dataBlock "github.com/multiversx/mx-chain-core-go/data/block"
"github.com/multiversx/mx-chain-core-go/data/outport"
"github.com/multiversx/mx-chain-core-go/data/smartContractResult"
"github.com/multiversx/mx-chain-core-go/data/transaction"
indexerdata "github.com/multiversx/mx-chain-es-indexer-go/process/dataindexer"
"github.com/stretchr/testify/require"
)

func TestRelayedV3TransactionWithMultipleRefunds(t *testing.T) {
setLogLevelDebug()

esClient, err := createESClient(esURL)
require.Nil(t, err)

esProc, err := CreateElasticProcessor(esClient)
require.Nil(t, err)

txHash := []byte("relayedTxV3WithMultipleRefunds")
header := &dataBlock.Header{
Round: 50,
TimeStamp: 5040,
}

body := &dataBlock.Body{
MiniBlocks: dataBlock.MiniBlockSlice{
{
Type: dataBlock.TxBlock,
SenderShardID: 0,
ReceiverShardID: 0,
TxHashes: [][]byte{txHash},
},
},
}

initialTx := &transaction.Transaction{
Nonce: 1000,
SndAddr: decodeAddress("erd1ykqd64fxxpp4wsz0v7sjqem038wfpzlljhx4mhwx8w9lcxmdzcfszrp64a"),
RcvAddr: decodeAddress("erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3"),
RelayerAddr: decodeAddress("erd10ksryjr065ad5475jcg82pnjfg9j9qtszjsrp24anl6ym7cmeddshwnru8"),
Signature: []byte("d"),
RelayerSignature: []byte("a"),
GasLimit: 500_000_000,
GasPrice: 1000000000,
Value: big.NewInt(0),
Data: []byte("doSomething"),
}

txInfo := &outport.TxInfo{
Transaction: initialTx,
FeeInfo: &outport.FeeInfo{
GasUsed: 180_150_000,
Fee: big.NewInt(2864760000000000),
InitialPaidFee: big.NewInt(2864760000000000),
},
ExecutionOrder: 0,
}

pool := &outport.TransactionPool{
Transactions: map[string]*outport.TxInfo{
hex.EncodeToString(txHash): txInfo,
},
}
err = esProc.SaveTransactions(createOutportBlockWithHeader(body, header, pool, nil, testNumOfShards))
require.Nil(t, err)

ids := []string{hex.EncodeToString(txHash)}
genericResponse := &GenericResponse{}
err = esClient.DoMultiGet(context.Background(), ids, indexerdata.TransactionsIndex, true, genericResponse)
require.Nil(t, err)

require.JSONEq(t,
readExpectedResult("./testdata/relayedTxV3/relayed-v3-no-refund.json"),
string(genericResponse.Docs[0].Source),
)

// execute first SCR with refund
pool = &outport.TransactionPool{
SmartContractResults: map[string]*outport.SCRInfo{
"scrHash": {
SmartContractResult: &smartContractResult.SmartContractResult{
OriginalTxHash: txHash,
},
FeeInfo: &outport.FeeInfo{
GasRefunded: 9_692_000,
Fee: big.NewInt(96920000000000),
},
},
},
}
err = esProc.SaveTransactions(createOutportBlockWithHeader(body, header, pool, nil, testNumOfShards))
require.Nil(t, err)

ids = []string{hex.EncodeToString(txHash)}
genericResponse = &GenericResponse{}
err = esClient.DoMultiGet(context.Background(), ids, indexerdata.TransactionsIndex, true, genericResponse)
require.Nil(t, err)

require.JSONEq(t,
readExpectedResult("./testdata/relayedTxV3/relayed-v3-with-one-refund.json"),
string(genericResponse.Docs[0].Source),
)

// execute second SCR with refund
pool = &outport.TransactionPool{
SmartContractResults: map[string]*outport.SCRInfo{
"scrHash": {
SmartContractResult: &smartContractResult.SmartContractResult{
OriginalTxHash: txHash,
},
FeeInfo: &outport.FeeInfo{
GasRefunded: 9_692_000,
Fee: big.NewInt(96920000000000),
},
},
},
}
err = esProc.SaveTransactions(createOutportBlockWithHeader(body, header, pool, nil, testNumOfShards))
require.Nil(t, err)

ids = []string{hex.EncodeToString(txHash)}
genericResponse = &GenericResponse{}
err = esClient.DoMultiGet(context.Background(), ids, indexerdata.TransactionsIndex, true, genericResponse)
require.Nil(t, err)

require.JSONEq(t,
readExpectedResult("./testdata/relayedTxV3/relayed-v3-with-two-refunds.json"),
string(genericResponse.Docs[0].Source),
)
}
28 changes: 28 additions & 0 deletions integrationtests/testdata/relayedTxV3/relayed-v3-no-refund.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"miniBlockHash": "785a251c08b314939528e553ac879dbee0627fbe2b76c0bca601c3f1e7162640",
"nonce": 1000,
"round": 50,
"value": "0",
"valueNum": 0,
"receiver": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3",
"sender": "erd1ykqd64fxxpp4wsz0v7sjqem038wfpzlljhx4mhwx8w9lcxmdzcfszrp64a",
"receiverShard": 0,
"senderShard": 0,
"gasPrice": 1000000000,
"gasLimit": 500000000,
"gasUsed": 180150000,
"fee": "2864760000000000",
"feeNum": 0.00286476,
"initialPaidFee": "2864760000000000",
"data": "ZG9Tb21ldGhpbmc=",
"signature": "64",
"timestamp": 5040,
"status": "success",
"searchOrder": 0,
"isScCall": true,
"operation": "transfer",
"function": "doSomething",
"isRelayed": true,
"relayer": "erd10ksryjr065ad5475jcg82pnjfg9j9qtszjsrp24anl6ym7cmeddshwnru8",
"relayerSignature": "61"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"miniBlockHash": "785a251c08b314939528e553ac879dbee0627fbe2b76c0bca601c3f1e7162640",
"nonce": 1000,
"round": 50,
"value": "0",
"valueNum": 0,
"receiver": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3",
"sender": "erd1ykqd64fxxpp4wsz0v7sjqem038wfpzlljhx4mhwx8w9lcxmdzcfszrp64a",
"receiverShard": 0,
"senderShard": 0,
"gasPrice": 1000000000,
"gasLimit": 500000000,
"gasUsed": 170458000,
"fee": "2767840000000000",
"feeNum": 0.00276784,
"initialPaidFee": "2864760000000000",
"data": "ZG9Tb21ldGhpbmc=",
"signature": "64",
"timestamp": 5040,
"status": "success",
"searchOrder": 0,
"isScCall": true,
"operation": "transfer",
"function": "doSomething",
"isRelayed": true,
"relayer": "erd10ksryjr065ad5475jcg82pnjfg9j9qtszjsrp24anl6ym7cmeddshwnru8",
"relayerSignature": "61",
"hadRefund": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"miniBlockHash": "785a251c08b314939528e553ac879dbee0627fbe2b76c0bca601c3f1e7162640",
"nonce": 1000,
"round": 50,
"value": "0",
"valueNum": 0,
"receiver": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3",
"sender": "erd1ykqd64fxxpp4wsz0v7sjqem038wfpzlljhx4mhwx8w9lcxmdzcfszrp64a",
"receiverShard": 0,
"senderShard": 0,
"gasPrice": 1000000000,
"gasLimit": 500000000,
"gasUsed": 160766000,
"fee": "2670920000000000",
"feeNum": 0.0026709200000000002,
"initialPaidFee": "2864760000000000",
"data": "ZG9Tb21ldGhpbmc=",
"signature": "64",
"timestamp": 5040,
"status": "success",
"searchOrder": 0,
"isScCall": true,
"operation": "transfer",
"function": "doSomething",
"isRelayed": true,
"relayer": "erd10ksryjr065ad5475jcg82pnjfg9j9qtszjsrp24anl6ym7cmeddshwnru8",
"relayerSignature": "61",
"hadRefund": true
}
11 changes: 6 additions & 5 deletions process/elasticproc/transactions/scrsDataToTransactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (st *scrsDataToTransactions) processTransactionsAfterSCRsWereAttached(trans
func (st *scrsDataToTransactions) processSCRsWithoutTx(scrs []*data.ScResult) map[string]*data.FeeData {
txHashRefund := make(map[string]*data.FeeData)
for _, scr := range scrs {
if scr.InitialTxGasUsed == 0 {
if scr.InitialTxGasUsed == 0 && scr.GasRefunded == 0 {
continue
}

Expand All @@ -70,10 +70,11 @@ func (st *scrsDataToTransactions) processSCRsWithoutTx(scrs []*data.ScResult) ma
}

txHashRefund[scr.OriginalTxHash] = &data.FeeData{
FeeNum: feeNum,
Fee: scr.InitialTxFee,
GasUsed: scr.InitialTxGasUsed,
Receiver: scr.Receiver,
FeeNum: feeNum,
Fee: scr.InitialTxFee,
GasUsed: scr.InitialTxGasUsed,
Receiver: scr.Receiver,
GasRefunded: scr.GasRefunded,
}
}

Expand Down
35 changes: 32 additions & 3 deletions process/elasticproc/transactions/serialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,35 @@ func (tdp *txsDatabaseProcessor) SerializeReceipts(receipts []*data.Receipt, buf
func (tdp *txsDatabaseProcessor) SerializeTransactionsFeeData(txHashRefund map[string]*data.FeeData, buffSlice *data.BufferSlice, index string) error {
for txHash, feeData := range txHashRefund {
meta := []byte(fmt.Sprintf(`{"update":{ "_index":"%s","_id":"%s"}}%s`, index, converters.JsonEscape(txHash), "\n"))
codeToExecute := `

var codeToExecute string
if feeData.GasRefunded != 0 {
codeToExecute = `
if ('create' == ctx.op) {
ctx.op = 'noop'
} else {
BigInteger feeFromSource;
if ((ctx._source.containsKey('hadRefund')) && (ctx._source.hadRefund)) {
feeFromSource = new BigInteger(ctx._source.fee);
} else {
feeFromSource = new BigInteger(ctx._source.initialPaidFee);
ctx._source.hadRefund = true;
}
BigInteger fee = new BigInteger(params.fee);
if (feeFromSource.compareTo(fee) > 0) {
ctx._source.fee = feeFromSource.subtract(fee).toString();
}
if (ctx._source.feeNum > params.feeNum) {
ctx._source.feeNum -= params.feeNum;
}
if (ctx._source.gasUsed > params.gasRefunded) {
ctx._source.gasUsed -= params.gasRefunded;
}
}
`
} else {
codeToExecute = `
if ('create' == ctx.op) {
ctx.op = 'noop'
} else {
Expand All @@ -60,13 +88,14 @@ func (tdp *txsDatabaseProcessor) SerializeTransactionsFeeData(txHashRefund map[s
ctx._source.gasUsed = params.gasUsed;
}
`
}

serializedDataStr := fmt.Sprintf(`{"scripted_upsert": true, "script": {`+
`"source": "%s",`+
`"lang": "painless",`+
`"params": {"fee": "%s", "gasUsed": %d, "feeNum": %g}},`+
`"params": {"fee": "%s", "gasUsed": %d, "feeNum": %g, "gasRefunded": %d}},`+
`"upsert": {}}`,
converters.FormatPainlessSource(codeToExecute), feeData.Fee, feeData.GasUsed, feeData.FeeNum,
converters.FormatPainlessSource(codeToExecute), feeData.Fee, feeData.GasUsed, feeData.FeeNum, feeData.GasRefunded,
)

err := buffSlice.PutData(meta, []byte(serializedDataStr))
Expand Down
2 changes: 1 addition & 1 deletion process/elasticproc/transactions/serialize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func TestTxsDatabaseProcessor_SerializeTransactionWithRefund(t *testing.T) {
require.Nil(t, err)

expectedBuff := `{"update":{ "_index":"transactions","_id":"txHash"}}
{"scripted_upsert": true, "script": {"source": "if ('create' == ctx.op) {ctx.op = 'noop'} else {ctx._source.fee = params.fee;ctx._source.feeNum = params.feeNum;ctx._source.gasUsed = params.gasUsed;}","lang": "painless","params": {"fee": "100000", "gasUsed": 5000, "feeNum": 5e-15}},"upsert": {}}
{"scripted_upsert": true, "script": {"source": "if ('create' == ctx.op) {ctx.op = 'noop'} else {ctx._source.fee = params.fee;ctx._source.feeNum = params.feeNum;ctx._source.gasUsed = params.gasUsed;}","lang": "painless","params": {"fee": "100000", "gasUsed": 5000, "feeNum": 5e-15, "gasRefunded": 0}},"upsert": {}}
`
require.Equal(t, expectedBuff, buffSlice.Buffers()[0].String())
}
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ func (proc *smartContractResultsProcessor) prepareSmartContractResult(
OriginalSender: originalSenderAddr,
InitialTxFee: feeInfo.Fee.String(),
InitialTxGasUsed: feeInfo.GasUsed,
GasRefunded: feeInfo.GasRefunded,
ExecutionOrder: int(scrInfo.ExecutionOrder),
}
}
Expand Down
7 changes: 6 additions & 1 deletion process/elasticproc/transactions/transactionDBBuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,17 @@ func (dtb *dbTransactionBuilder) prepareTransaction(
Operation: res.Operation,
RelayedSignature: hex.EncodeToString(tx.RelayerSignature),
RelayedAddr: relayedAddress,
HadRefund: feeInfo.HadRefund,
}

hasValidRelayer := len(eTx.RelayedAddr) == len(eTx.Sender) && len(eTx.RelayedAddr) > 0
hasValidRelayerSignature := len(eTx.RelayedSignature) == len(eTx.Signature) && len(eTx.RelayedSignature) > 0
isRelayedV3 := hasValidRelayer && hasValidRelayerSignature

eTx.Function = converters.TruncateFieldIfExceedsMaxLength(res.Function)
eTx.Tokens = converters.TruncateSliceElementsIfExceedsMaxLength(res.Tokens)
eTx.ReceiversShardIDs = res.ReceiversShardID
eTx.IsRelayed = res.IsRelayed
eTx.IsRelayed = res.IsRelayed || isRelayedV3

return eTx
}
Expand Down

0 comments on commit 5e055ee

Please sign in to comment.