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

Adding benchmark test - root/child chain measurements #1510

Draft
wants to merge 7 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 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
10 changes: 10 additions & 0 deletions benchmark/benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package benchmark

import (
"testing"
)

func Benchmark_RunTests(b *testing.B) {
// benchmark tests
rootChildSendTx(b)
}
81 changes: 81 additions & 0 deletions benchmark/contract_codes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//nolint:lll
package benchmark

// pragma solidity ^0.5.16;

// contract SingleCallContract {
// uint256[] private val;

// function addValue(uint256 value) public {
// val.push(value);
// }

// function getValue() public view returns (uint256[] memory) {
// return val;
// }

// function compute(uint256 x, uint256 y) public pure returns (uint256) {
// uint256 result = x + y;
// for (uint256 i = 0; i < 10; i++) {
// result = result * 2;
// }
// return result;
// }
// }
const singleContByteCode = `608060405234801561001057600080fd5b50610210806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806320965255146100465780635b9af12b146100a55780637a85644b146100d3575b600080fd5b61004e61011f565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610091578082015181840152602081019050610076565b505050509050019250505060405180910390f35b6100d1600480360360208110156100bb57600080fd5b8101908080359060200190929190505050610177565b005b610109600480360360408110156100e957600080fd5b8101908080359060200190929190803590602001909291905050506101a6565b6040518082815260200191505060405180910390f35b6060600080548060200260200160405190810160405280929190818152602001828054801561016d57602002820191906000526020600020905b815481526020019060010190808311610159575b5050505050905090565b600081908060018154018082558091505090600182039060005260206000200160009091929091909150555050565b600080828401905060008090505b600a8110156101d05760028202915080806001019150506101b4565b50809150509291505056fea265627a7a72315820ec23cf989c20e0d41d7819001da6dfe6cc129988f15cd8a7b79595a2e61a93d264736f6c63430005100032`

//MULTI CONTRACTS CALL: A->B->C

// pragma solidity ^0.5.16;
// interface IContractB {
// function fnB() external returns (uint256);
// }
// contract ContractA {
// address contractAddr;
//
// function setContractAddr(address _contract) public {
// contractAddr = _contract;
// }

// function fnA() public returns (uint256) {
// uint256 valB = IContractB(contractAddr).fnB();
// return valB;
// }
// }
const multiContAByteCode = `608060405234801561001057600080fd5b506101c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063286d2e3a1461003b57806368685ad31461007f575b600080fd5b61007d6004803603602081101561005157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061009d565b005b6100876100e0565b6040518082815260200191505060405180910390f35b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636cde00cd6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561014c57600080fd5b505af1158015610160573d6000803e3d6000fd5b505050506040513d602081101561017657600080fd5b81019080805190602001909291905050509050809150509056fea265627a7a7231582082d7a079b4ea6bcf371ef0665da89a56bd53bdc82ae90daa9dd21b61fc6c115864736f6c63430005100032`

// pragma solidity ^0.5.16;
// interface IContractC {
// function fnC1() external returns (uint256);
// }
// contract ContractB {
// uint256 public valB;
// address contractAddr;

// function setContractAddr(address _contract) public {
// contractAddr = _contract;
// }

// function fnB() external returns (uint256) {
// uint256 valC = IContractC(contractAddr).fnC1();
// valB += valC;
// return valC;
// }

// }
const multiContBByteCode = `608060405234801561001057600080fd5b50610205806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063286d2e3a146100465780636cde00cd1461008a578063735b7e6f146100a8575b600080fd5b6100886004803603602081101561005c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100c6565b005b61009261010a565b6040518082815260200191505060405180910390f35b6100b06101ca565b6040518082815260200191505060405180910390f35b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166349ec07186040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561017757600080fd5b505af115801561018b573d6000803e3d6000fd5b505050506040513d60208110156101a157600080fd5b810190808051906020019092919050505090508060008082825401925050819055508091505090565b6000548156fea265627a7a7231582082a5dbbf184a5c59907837a73f0ea2083719218b0bd60ef31a3ef2b209aad00764736f6c63430005100032`

// pragma solidity ^0.5.16;
// contract ContractC {
// uint256 public valC;
// function fnC1() external returns (uint256) {
// uint256 valC2 = fnC2();
// valC++;
// return valC2;
// }

// function fnC2() public view returns (uint256) {
// return uint256(keccak256(abi.encode(block.timestamp, block.difficulty))) % 100;
// }
// }
const multiContCByteCode = `608060405234801561001057600080fd5b50610143806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80631990ceb9146100465780633b3cf4e31461006457806349ec071814610082575b600080fd5b61004e6100a0565b6040518082815260200191505060405180910390f35b61006c6100e3565b6040518082815260200191505060405180910390f35b61008a6100e9565b6040518082815260200191505060405180910390f35b60006064424460405160200180838152602001828152602001925050506040516020818303038152906040528051906020012060001c816100dd57fe5b06905090565b60005481565b6000806100f46100a0565b90506000808154809291906001019190505550809150509056fea265627a7a72315820834484e13fa60ebe10a9d7102df12bafa8db4d9cdad5a38d2af6d360adc7ff4064736f6c63430005100032`
61 changes: 61 additions & 0 deletions benchmark/executors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package benchmark

import (
"sync"
"testing"

"github.com/0xPolygon/polygon-edge/txrelayer"
"github.com/0xPolygon/polygon-edge/types"
"github.com/stretchr/testify/require"
"github.com/umbracle/ethgo"
)

// TxTestCase represents a test case data to be run with txTestCasesExecutor
type TxTestCase struct {
Name string
Relayer txrelayer.TxRelayer
ContractAddr ethgo.Address
Input [][]byte
Sender ethgo.Key
TxNumber int
}

// TxTestCasesExecutor executes transactions from testInput and waits in separate
// go routins for each tx receipt
func TxTestCasesExecutor(b *testing.B, testInput TxTestCase) {
b.Helper()
b.Run(testInput.Name, func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
var wg sync.WaitGroup

// submit all tx 'repeatCall' times
for i := 0; i < testInput.TxNumber; i++ {
// call contract for the all inputs
for j := 0; j < len(testInput.Input); j++ {
// the tx is submitted to the blockchain without waiting for the receipt,
// since we want to have multiple tx in one block
txHash, err := testInput.Relayer.SumbitTransaction(
&ethgo.Transaction{
To: &testInput.ContractAddr,
Input: testInput.Input[j],
}, testInput.Sender)
require.NoError(b, err)
require.NotEqual(b, ethgo.ZeroHash, txHash)

wg.Add(1)

// wait for receipt of submitted tx in a separate routine, and continue with the next tx
func(hash ethgo.Hash) {
defer wg.Done()

receipt, err := testInput.Relayer.WaitForReceipt(hash)
require.NoError(b, err)
require.Equal(b, uint64(types.ReceiptSuccess), receipt.Status)
}(txHash)
}
}

wg.Wait()
})
}
100 changes: 100 additions & 0 deletions benchmark/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package benchmark

import (
"encoding/hex"
"testing"

"github.com/0xPolygon/polygon-edge/txrelayer"
"github.com/0xPolygon/polygon-edge/types"
"github.com/stretchr/testify/require"
"github.com/umbracle/ethgo"
"github.com/umbracle/ethgo/abi"
"github.com/umbracle/ethgo/wallet"
)

// deployContractOnRootAndChild deploys contract code on both root and child chain
func deployContractOnRootAndChild(
b *testing.B,
childTxRelayer txrelayer.TxRelayer,
rootTxRelayer txrelayer.TxRelayer,
sender ethgo.Key,
byteCodeString string) (ethgo.Address, ethgo.Address) {
b.Helper()

// bytecode from string
byteCode, err := hex.DecodeString(byteCodeString)
require.NoError(b, err)

// deploy contract on the child chain
contractChildAddr := deployContract(b, childTxRelayer, sender, byteCode)

// deploy contract on the root chain
contractRootAddr := deployContract(b, rootTxRelayer, sender, byteCode)

return contractChildAddr, contractRootAddr
}

// deployContract deploys contract code for the given relayer
func deployContract(b *testing.B, txRelayer txrelayer.TxRelayer, sender ethgo.Key, byteCode []byte) ethgo.Address {
b.Helper()

txn := &ethgo.Transaction{
To: nil, // contract deployment
Input: byteCode,
}

receipt, err := txRelayer.SendTransaction(txn, sender)
require.NoError(b, err)
require.Equal(b, uint64(types.ReceiptSuccess), receipt.Status)
require.NotEqual(b, ethgo.ZeroAddress, receipt.ContractAddress)

return receipt.ContractAddress
}

// getTxInput returns input for sending tx, given the abi encoded method and call parameters
func getTxInput(b *testing.B, method *abi.Method, args interface{}) []byte {
b.Helper()

var (
input []byte
err error
)

if args != nil {
input, err = method.Encode(args)
} else {
input = method.ID()
}

require.NoError(b, err)

return input
}

// setContractDependencyAddress calls setContract function on caller contract, to set address of the callee contract
func setContractDependencyAddress(b *testing.B, txRelayer txrelayer.TxRelayer, callerContractAddr ethgo.Address,
calleeContractAddr ethgo.Address, setContractAbiMethod *abi.Method, sender ethgo.Key) {
b.Helper()

input := getTxInput(b, setContractAbiMethod, []interface{}{calleeContractAddr})
receipt, err := txRelayer.SendTransaction(
&ethgo.Transaction{
To: &callerContractAddr,
Input: input,
}, sender)
require.NoError(b, err)
require.Equal(b, uint64(types.ReceiptSuccess), receipt.Status)
}

// getPrivateKey initializes a private key from provided raw private key
func getPrivateKey(b *testing.B, privateKeyRaw string) ethgo.Key {
b.Helper()

dec, err := hex.DecodeString(privateKeyRaw)
require.NoError(b, err)

privateKey, err := wallet.NewWalletFromPrivKey(dec)
require.NoError(b, err)

return privateKey
}
Loading