This repository was archived by the owner on Dec 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 569
Adding benchmark test - root/child chain measurements #1510
Draft
stana-miric
wants to merge
7
commits into
develop
Choose a base branch
from
EVM-639-analyze-storage-performance-edge-technical-challenges
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
4c1475f
Benchmark test - comparing diff eth clients
stana-miric 726fbea
cr fix - file reorganization
stana-miric 6e075ab
cr fix - introduce startCluster flag
stana-miric 99efd02
cr fix - move contract codes to contractsapi
stana-miric 38bc3ce
cr fix - remove flags from test
stana-miric 70b0df9
add transition benchmark test
stana-miric 8164f55
large data test
stana-miric File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Benchmark tests | ||
| The benchmark folder contains benchmark tests for the smart contracts. | ||
|
|
||
| ## Common directory | ||
| In the common directory, you'll find: | ||
| - the contract_code.go file that contains byte codes for the contracts used in the tests, | ||
| - helpers.go that has helper functions needed in tests like deploying contracts and similar, | ||
| - executors.go that holds executors which execute the test cases. For example, there is an executor that submits multiple transactions in parallel and measures the execution time. | ||
|
|
||
| ## Tests | ||
| All test scenarios are executed in benchmark_test.go. Decoupling test scenarios from execution enables the usage of different scenarios in the benchmark command, which is written for the purpose of executing the benchmark test on a test environment. The command can be run with in a following way: | ||
| polygon-edge benchmark-test --childJSONRPC="http://127.0.0.1:12001" --rootJSONRPC="http://127.0.0.1:8545" --privateKey="aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d" | ||
|
|
||
| ## Testing tx send on root and child chains | ||
| The RootChildSendTx function executes test cases that measure transaction execution on both the root and child chains. To do this, it first calls RootChildSendTxSetUp to set up the testing environment, which may include starting the cluster, deploying contracts, and building the test cases. After building the test cases, RootChildSendTx returns them along with a cleanup function that should be called after the test cases have been executed. | ||
|
|
||
| The test cases are executed by the TxTestCasesExecutor. The RootJSONRPC, ChildJSONRPC, and PrivateKey flags are used to configure the testing environment. If all of these flags are set, then the local cluster will not be started and the provided addresses will be used as the endpoints to the root and child chains. If any of these flags is not set, the local cluster will be started automatically. If the private key is specified, it will be used as the transaction sender. Otherwise, the local cluster will generate a sender key. If the cluster is not run locally, then the sender must have enough funds for sending transactions. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| //nolint:lll | ||
| package common | ||
|
|
||
| // 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` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package common | ||
|
|
||
| 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( | ||
| ðgo.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() | ||
| }) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| package common | ||
|
|
||
| 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( | ||
goran-ethernal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 := ðgo.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 | ||
goran-ethernal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| var 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( | ||
| ðgo.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 | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.