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 datacopy contract test #2788

Merged
merged 10 commits into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from 9 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
143 changes: 91 additions & 52 deletions action/protocol/execution/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,52 @@ import (
"github.com/iotexproject/iotex-core/testutil"
)

// ExpectedBalance defines an account-balance pair
type ExpectedBalance struct {
Account string `json:"account"`
RawBalance string `json:"rawBalance"`
}
type (
// ExpectedBalance defines an account-balance pair
ExpectedBalance struct {
Account string `json:"account"`
RawBalance string `json:"rawBalance"`
}

// GenesisBlockHeight defines an genesis blockHeight
type GenesisBlockHeight struct {
IsBering bool `json:"isBering"`
IsIceland bool `json:"isIceland"`
}
ExpectedBlockInfo struct {
TxRootHash string `json:"txRootHash"`
StateRootHash string `json:"stateRootHash"`
ReceiptRootHash string `json:"receiptRootHash"`
}

// GenesisBlockHeight defines an genesis blockHeight
GenesisBlockHeight struct {
IsBering bool `json:"isBering"`
IsIceland bool `json:"isIceland"`
}

Log struct {
Topics []string `json:"topics"`
Data string `json:"data"`
}

ExecutionConfig struct {
Comment string `json:"comment"`
ContractIndex int `json:"contractIndex"`
AppendContractAddress bool `json:"appendContractAddress"`
ContractIndexToAppend int `json:"contractIndexToAppend"`
ContractAddressToAppend string `json:"contractAddressToAppend"`
ReadOnly bool `json:"readOnly"`
RawPrivateKey string `json:"rawPrivateKey"`
RawByteCode string `json:"rawByteCode"`
RawAmount string `json:"rawAmount"`
RawGasLimit uint `json:"rawGasLimit"`
RawGasPrice string `json:"rawGasPrice"`
Failed bool `json:"failed"`
RawReturnValue string `json:"rawReturnValue"`
RawExpectedGasConsumed uint `json:"rawExpectedGasConsumed"`
ExpectedStatus uint64 `json:"expectedStatus"`
ExpectedBalances []ExpectedBalance `json:"expectedBalances"`
ExpectedLogs []Log `json:"expectedLogs"`
ExpectedErrorMsg string `json:"expectedErrorMsg"`
ExpectedBlockInfos ExpectedBlockInfo `json:"expectedBlockInfos"`
}
)

func (eb *ExpectedBalance) Balance() *big.Int {
balance, ok := new(big.Int).SetString(eb.RawBalance, 10)
Expand All @@ -78,32 +113,6 @@ func readCode(sr protocol.StateReader, addr []byte) ([]byte, error) {
return c[:], err
}

type Log struct {
Topics []string `json:"topics"`
Data string `json:"data"`
}

type ExecutionConfig struct {
Comment string `json:"comment"`
ContractIndex int `json:"contractIndex"`
AppendContractAddress bool `json:"appendContractAddress"`
ContractIndexToAppend int `json:"contractIndexToAppend"`
ContractAddressToAppend string `json:"contractAddressToAppend"`
ReadOnly bool `json:"readOnly"`
RawPrivateKey string `json:"rawPrivateKey"`
RawByteCode string `json:"rawByteCode"`
RawAmount string `json:"rawAmount"`
RawGasLimit uint `json:"rawGasLimit"`
RawGasPrice string `json:"rawGasPrice"`
Failed bool `json:"failed"`
RawReturnValue string `json:"rawReturnValue"`
RawExpectedGasConsumed uint `json:"rawExpectedGasConsumed"`
ExpectedStatus uint64 `json:"expectedStatus"`
ExpectedBalances []ExpectedBalance `json:"expectedBalances"`
ExpectedLogs []Log `json:"expectedLogs"`
ExpectedErrorMsg string `json:"expectedErrorMsg"`
}

func (cfg *ExecutionConfig) PrivateKey() crypto.PrivateKey {
priKey, err := crypto.HexStringToPrivateKey(cfg.RawPrivateKey)
if err != nil {
Expand Down Expand Up @@ -258,7 +267,7 @@ func runExecutions(
ap actpool.ActPool,
ecfgs []*ExecutionConfig,
contractAddrs []string,
) ([]*action.Receipt, error) {
) ([]*action.Receipt, *ExpectedBlockInfo, error) {
nonces := map[string]uint64{}
hashes := []hash.Hash256{}
for i, ecfg := range ecfgs {
Expand All @@ -269,7 +278,7 @@ func runExecutions(
if nonce, ok = nonces[executor]; !ok {
state, err := accountutil.AccountState(sf, executor)
if err != nil {
return nil, err
return nil, nil, err
}
nonce = state.Nonce
}
Expand All @@ -284,7 +293,7 @@ func runExecutions(
ecfg.ByteCode(),
)
if err != nil {
return nil, err
return nil, nil, err
}
builder := &action.EnvelopeBuilder{}
elp := builder.SetAction(exec).
Expand All @@ -294,34 +303,41 @@ func runExecutions(
Build()
selp, err := action.Sign(elp, ecfg.PrivateKey())
if err != nil {
return nil, err
return nil, nil, err
}
if err := ap.Add(context.Background(), selp); err != nil {
return nil, err
return nil, nil, err
}
selpHash, err := selp.Hash()
if err != nil {
return nil, err
return nil, nil, err
}
hashes = append(hashes, selpHash)
}
blk, err := bc.MintNewBlock(testutil.TimestampNow())
if err != nil {
return nil, err
return nil, nil, err
}

if err := bc.CommitBlock(blk); err != nil {
return nil, err
return nil, nil, err
}
receipts := []*action.Receipt{}
for _, hash := range hashes {
receipt, err := dao.GetReceiptByActionHash(hash, blk.Height())
if err != nil {
return nil, err
return nil, nil, err
}
receipts = append(receipts, receipt)
}
stateRootHash, txRootHash, receiptRootHash := blk.DeltaStateDigest(), blk.TxRoot(), blk.ReceiptRoot()
blkInfo := &ExpectedBlockInfo{
hex.EncodeToString(txRootHash[:]),
hex.EncodeToString(stateRootHash[:]),
hex.EncodeToString(receiptRootHash[:]),
}

return receipts, nil
return receipts, blkInfo, nil
}

func (sct *SmartContractTest) prepareBlockchain(
Expand Down Expand Up @@ -414,7 +430,7 @@ func (sct *SmartContractTest) deployContracts(
if contract.AppendContractAddress {
contract.ContractAddressToAppend = contractAddresses[contract.ContractIndexToAppend]
}
receipts, err := runExecutions(bc, sf, dao, ap, []*ExecutionConfig{&contract}, []string{action.EmptyAddress})
receipts, _, err := runExecutions(bc, sf, dao, ap, []*ExecutionConfig{&contract}, []string{action.EmptyAddress})
r.NoError(err)
r.Equal(1, len(receipts))
receipt := receipts[0]
Expand Down Expand Up @@ -455,6 +471,7 @@ func (sct *SmartContractTest) run(r *require.Assertions) {
// prepare blockchain
ctx := context.Background()
cfg := config.Default
cfg.Chain.ProducerPrivKey = identityset.PrivateKey(28).HexString()
cfg.Chain.EnableTrielessStateDB = false
bc, sf, dao, ap := sct.prepareBlockchain(ctx, cfg, r)
defer func() {
Expand All @@ -475,6 +492,7 @@ func (sct *SmartContractTest) run(r *require.Assertions) {
}
var retval []byte
var receipt *action.Receipt
var blkInfo *ExpectedBlockInfo
var err error
if exec.ReadOnly {
retval, receipt, err = readExecution(bc, sf, dao, ap, &exec, contractAddr)
Expand All @@ -486,7 +504,8 @@ func (sct *SmartContractTest) run(r *require.Assertions) {
r.Equal(expected, retval)
}
} else {
receipts, err := runExecutions(bc, sf, dao, ap, []*ExecutionConfig{&exec}, []string{contractAddr})
var receipts []*action.Receipt
receipts, blkInfo, err = runExecutions(bc, sf, dao, ap, []*ExecutionConfig{&exec}, []string{contractAddr})
r.NoError(err)
r.Equal(1, len(receipts))
receipt = receipts[0]
Expand All @@ -506,6 +525,11 @@ func (sct *SmartContractTest) run(r *require.Assertions) {
if exec.ExpectedGasConsumed() != 0 {
r.Equal(exec.ExpectedGasConsumed(), receipt.GasConsumed, i)
}
if exec.ExpectedBlockInfos != (ExpectedBlockInfo{}) {
r.Equal(exec.ExpectedBlockInfos.ReceiptRootHash, blkInfo.ReceiptRootHash)
r.Equal(exec.ExpectedBlockInfos.TxRootHash, blkInfo.TxRootHash)
r.Equal(exec.ExpectedBlockInfos.StateRootHash, blkInfo.StateRootHash)
}
for _, expectedBalance := range exec.ExpectedBalances {
account := expectedBalance.Account
if account == "" {
Expand Down Expand Up @@ -872,6 +896,15 @@ func TestProtocol_Handle(t *testing.T) {
t.Run("self-destruct", func(t *testing.T) {
NewSmartContractTest(t, "testdata/self-destruct.json")
})
// datacopy
t.Run("datacopy", func(t *testing.T) {
NewSmartContractTest(t, "testdata/datacopy.json")
})
// this test replay CVE-2021-39137 attack, see attack details
// at https://github.com/ethereum/go-ethereum/blob/master/docs/postmortems/2021-08-22-split-postmortem.md
t.Run("CVE-2021-39137-attack-replay", func(t *testing.T) {
NewSmartContractTest(t, "testdata/CVE-2021-39137-attack-replay.json")
})
}

func TestMaxTime(t *testing.T) {
Expand Down Expand Up @@ -956,6 +989,12 @@ func TestIstanbulEVM(t *testing.T) {
t.Run("self-destruct", func(t *testing.T) {
NewSmartContractTest(t, "testdata-istanbul/self-destruct.json")
})
t.Run("datacopy", func(t *testing.T) {
NewSmartContractTest(t, "testdata-istanbul/datacopy.json")
})
t.Run("CVE-2021-39137-attack-replay", func(t *testing.T) {
NewSmartContractTest(t, "testdata/CVE-2021-39137-attack-replay.json")
})
}

func benchmarkHotContractWithFactory(b *testing.B, async bool) {
Expand Down Expand Up @@ -996,7 +1035,7 @@ func benchmarkHotContractWithFactory(b *testing.B, async bool) {
contractAddr := contractAddresses[0]
b.ResetTimer()
for i := 0; i < b.N; i++ {
receipts, err := runExecutions(
receipts, _, err := runExecutions(
bc, sf, dao, ap, []*ExecutionConfig{
{
RawPrivateKey: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
Expand Down Expand Up @@ -1027,7 +1066,7 @@ func benchmarkHotContractWithFactory(b *testing.B, async bool) {
})
contractAddrs = append(contractAddrs, contractAddr)
}
receipts, err = runExecutions(bc, sf, dao, ap, ecfgs, contractAddrs)
receipts, _, err = runExecutions(bc, sf, dao, ap, ecfgs, contractAddrs)
r.NoError(err)
for _, receipt := range receipts {
r.Equal(uint64(1), receipt.Status)
Expand Down Expand Up @@ -1073,7 +1112,7 @@ func benchmarkHotContractWithStateDB(b *testing.B, cachedStateDBOption bool) {
contractAddr := contractAddresses[0]
b.ResetTimer()
for i := 0; i < b.N; i++ {
receipts, err := runExecutions(
receipts, _, err := runExecutions(
bc, sf, dao, ap, []*ExecutionConfig{
{
RawPrivateKey: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
Expand Down Expand Up @@ -1104,7 +1143,7 @@ func benchmarkHotContractWithStateDB(b *testing.B, cachedStateDBOption bool) {
})
contractAddrs = append(contractAddrs, contractAddr)
}
receipts, err = runExecutions(bc, sf, dao, ap, ecfgs, contractAddrs)
receipts, _, err = runExecutions(bc, sf, dao, ap, ecfgs, contractAddrs)
r.NoError(err)
for _, receipt := range receipts {
r.Equal(uint64(1), receipt.Status)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"initBalances": [{
"account": "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms",
"rawBalance": "1000000000000000000000000000"
}],
"deployments": [{
"rawByteCode": "0000000000000000000000008eae784e072e961f76948a785b62c9a950fb17ae62c9a950fb17ae00000000000000000000000000000000000000000000000000",
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawAmount": "0",
"rawGasLimit": 5000000,
"rawGasPrice": "0",
"rawExpectedGasConsumed": 16400,
"expectedBalances": [],
"comment": "deploy attack contract(https://etherscan.io/address/0x8eae784e072e961f76948a785b62c9a950fb17ae)"
}],
"executions": [{
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawByteCode": "3034526020600760203460045afa602034343e604034f3",
"rawAmount": "0",
"rawGasLimit": 1000000,
"rawGasPrice": "0",
"rawExpectedGasConsumed": 12300,
"comment": "launch attack(https://etherscan.io/tx/0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4)",
"expectedBlockInfos" : {
"txRootHash" : "a59ead74a3870e9b5ca352c5f59108df402ca203ef2109799fe2d8e1da49c83d",
"stateRootHash" : "ed9bd589ee5ab5660a3d5d863bbeea13020a0aacab18e8655a626beaf9a54713",
"receiptRootHash" : "3285579efa8521fbf95829b868ff5d37632c4feac6167e9ab2dc4961004c9272"
}
}]
}
30 changes: 30 additions & 0 deletions action/protocol/execution/testdata-istanbul/datacopy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"initBalances": [{
"account": "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms",
"rawBalance": "1000000000000000000000000000"
}],
"deployments": [{
"rawByteCode": "608060405234801561001057600080fd5b50610315806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063574c807814610046575b600080fd5b34801561005257600080fd5b5061005b61005d565b005b606060006060600060036040519080825280601f01601f1916602001820160405280156100995781602001602082028038833980820191505090505b50935060117f0100000000000000000000000000000000000000000000000000000000000000028460008151811015156100cf57fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060227f01000000000000000000000000000000000000000000000000000000000000000284600181518110151561013257fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060337f01000000000000000000000000000000000000000000000000000000000000000284600281518110151561019557fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508351925060036040519080825280601f01601f1916602001820160405280156101fd5781602001602082028038833980820191505090505b50915082602185018460208701600462010000fa9050826000602084013e6102248261022a565b50505050565b8060009080519060200190610240929190610244565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028557805160ff19168380011785556102b3565b828001600101855582156102b3579182015b828111156102b2578251825591602001919060010190610297565b5b5090506102c091906102c4565b5090565b6102e691905b808211156102e25760008160009055506001016102ca565b5090565b905600a165627a7a723058208a35fa3071989284284d5ed558296837ad55fae1b176b939e5b493485c4794170029",
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawAmount": "0",
"rawGasLimit": 5000000,
"rawGasPrice": "0",
"rawExpectedGasConsumed": 250102,
"expectedBalances": [],
"comment": "deploy datacopy contract"
}],
"executions": [{
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawByteCode": "574c8078",
"rawAmount": "0",
"rawGasLimit": 1000000,
"rawGasPrice": "0",
"rawExpectedGasConsumed": 32504,
"comment": "the data of return is [0x11, 0x22, 0x33]",
"expectedBlockInfos" : {
"txRootHash" : "3672945ca662bea4dd977e799374c5ce36c0c3e9ecbe98f1655f33439bbfe40c",
"stateRootHash" : "6fb3dc7f5ef66ce9b384f034191d6a67801e01961ecd824061c4101035844667",
"receiptRootHash" : "0dfe7718f029aaffccd9c20bfaa50a1fb3405014de68af4f89516160de53d2f2"
}
}]
}
24 changes: 24 additions & 0 deletions action/protocol/execution/testdata-istanbul/datacopy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma solidity ^0.8.3;

contract Datacopy {
Liuhaai marked this conversation as resolved.
Show resolved Hide resolved
bytes store;
function dataCopy() public {
bytes memory arr = new bytes(3);
arr[0] = 0x11;
arr[1] = 0x22;
arr[2] = 0x33;
uint length = arr.length;
bytes memory result = new bytes(3);
bool ret;
assembly {
// Call precompiled contract to copy data
ret := staticcall(0x10000, 0x04, add(arr, 0x20), length, add(arr, 0x21), length)
returndatacopy(add(result, 0x20), 0x00, length)
}
Liuhaai marked this conversation as resolved.
Show resolved Hide resolved
updateStore(result);
}

function updateStore(bytes memory ret) internal {
store = ret;
}
}
Loading