Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3917e7b
Transaction background indexing/unindexing + improved chain initiatio…
error2215 Jun 29, 2022
4180502
core/rawdb: Stop freezer process as part of freezer.Close()
error2215 Jun 29, 2022
da9e4e2
PR#20302, PR#21010, PR#20758, PR#21212, PR#20837, PR#20808, PR#20692,…
error2215 Jul 1, 2022
ac2dc6f
define and test chain reparation cornercases
error2215 Jul 4, 2022
b482bbb
fix KnownDNSNetwork
error2215 Jul 4, 2022
1a51a2f
final fixes
error2215 Jul 4, 2022
9d6c1ea
remove verbosity in test
error2215 Jul 5, 2022
57739c1
test timeouts 20m
error2215 Jul 6, 2022
7691d3f
accounts/abi: implement new fallback functions #20764
error2215 Jul 6, 2022
b041414
accounts/abi: Prevent recalculation of internal fields #20895
error2215 Jul 6, 2022
192ea43
fix test
error2215 Jul 6, 2022
659ead9
improve EstimateEnergy API #20830
error2215 Jul 8, 2022
c1a7675
ignore long-running tests
error2215 Jul 8, 2022
e98e59a
ignore long-running tests
error2215 Jul 8, 2022
0acea1f
Merge remote-tracking branch 'origin/develop' into feature/chain_repa…
error2215 Jul 8, 2022
2dd7920
go mod tidy (add uint256 package)
error2215 Jul 13, 2022
bb9dc7c
Merge branch 'feature/chain_reparation_cornercases' into feature/less…
error2215 Jul 13, 2022
76b8a85
Merge branch 'feature/chain_reparation_cornercases' into feature/impr…
error2215 Jul 13, 2022
7b5bb00
merge
error2215 Jul 13, 2022
3e4e57b
merge develop
error2215 Jul 21, 2022
f68fde2
increase timeouts
error2215 Jul 22, 2022
3b5bb8d
Merge branch 'feature/less_allocations_for_various_call_variants_2' i…
error2215 Jul 22, 2022
ca357f4
merge develop
error2215 Jul 22, 2022
d4a898f
Merge branch 'feature/less_allocations_for_various_call_variants_2' i…
error2215 Jul 22, 2022
ec73e8c
Merge remote-tracking branch 'origin/develop' into feature/improve_es…
error2215 Jul 25, 2022
00be729
Merge remote-tracking branch 'origin/feature/improve_estimate_energy'…
error2215 Jul 25, 2022
e659691
update go-goldilocks
error2215 Jul 25, 2022
133cddc
Merge remote-tracking branch 'origin/develop' into feature/improve_es…
Jul 25, 2022
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
23 changes: 23 additions & 0 deletions accounts/abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/core-coin/go-core/crypto"
"io"

"github.com/core-coin/go-core/common"
Expand Down Expand Up @@ -236,3 +237,25 @@ func (abi *ABI) HasFallback() bool {
func (abi *ABI) HasReceive() bool {
return abi.Receive.Type == Receive
}

// revertSelector is a special function selector for revert reason unpacking.
var revertSelector = crypto.SHA3([]byte("Error(string)"))[:4]

// UnpackRevert resolves the abi-encoded revert reason. According to the solidity
// spec https://solidity.readthedocs.io/en/latest/control-structures.html#revert,
// the provided revert reason is abi-encoded as if it were a call to a function
// `Error(string)`. So it's a special tool for it.
func UnpackRevert(data []byte) (string, error) {
if len(data) < 4 {
return "", errors.New("invalid data for unpacking")
}
if !bytes.Equal(data[:4], revertSelector) {
return "", errors.New("invalid data for unpacking")
}
var reason string
typ, _ := NewType("string", "", nil)
if err := (Arguments{{Type: typ}}).Unpack(&reason, data[4:]); err != nil {
return "", err
}
return reason, nil
}
32 changes: 32 additions & 0 deletions accounts/abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package abi
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"math/big"
"reflect"
Expand Down Expand Up @@ -1082,3 +1083,34 @@ func TestUnnamedEventParam(t *testing.T) {
t.Fatalf("Could not find input")
}
}

func TestUnpackRevert(t *testing.T) {
t.Parallel()

var cases = []struct {
input string
expect string
expectErr error
}{
{"", "", errors.New("invalid data for unpacking")},
{"08c379a1", "", errors.New("invalid data for unpacking")},
{"4e401cbe0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000", "revert reason", nil},
}
for index, c := range cases {
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
got, err := UnpackRevert(common.Hex2Bytes(c.input))
if c.expectErr != nil {
if err == nil {
t.Fatalf("Expected non-nil error")
}
if err.Error() != c.expectErr.Error() {
t.Fatalf("Expected error mismatch, want %v, got %v", c.expectErr, err)
}
return
}
if c.expect != got {
t.Fatalf("Output mismatch, want %v, got %v", c.expect, got)
}
})
}
}
64 changes: 49 additions & 15 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
"github.com/core-coin/go-core/accounts/abi"
"math/big"
"sync"
"time"
Expand Down Expand Up @@ -49,7 +50,6 @@ var (
errBlockNumberUnsupported = errors.New("simulatedBackend cannot access blocks other than the latest block")
errBlockDoesNotExist = errors.New("block does not exist in blockchain")
errTransactionDoesNotExist = errors.New("transaction does not exist")
errEnergyEstimationFailed = errors.New("energy required exceeds allowance or always failing transaction")
)

// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
Expand Down Expand Up @@ -349,8 +349,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call gocore.CallMsg
if err != nil {
return nil, err
}
rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
return rval, err
res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
if err != nil {
return nil, err
}
return res.Return(), nil
}

// PendingCallContract executes a contract call on the pending state.
Expand All @@ -359,8 +362,11 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call gocore.
defer b.mu.Unlock()
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())

rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
return rval, err
res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
if err != nil {
return nil, err
}
return res.Return(), nil
}

// PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving
Expand Down Expand Up @@ -397,40 +403,68 @@ func (b *SimulatedBackend) EstimateEnergy(ctx context.Context, call gocore.CallM
}
cap = hi

// Create a helper to check if a energy allowance results in an executable transaction
executable := func(energy uint64) bool {
// Create a helper to check if an energy allowance results in an executable transaction
executable := func(energy uint64) (bool, *core.ExecutionResult, error) {
call.Energy = energy

snapshot := b.pendingState.Snapshot()
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
b.pendingState.RevertToSnapshot(snapshot)

if err != nil || failed {
return false
if err != nil {
if err == core.ErrIntrinsicEnergy {
return true, nil, nil // Special case, raise energy limit
}
return true, nil, err // Bail out
}
return true
return res.Failed(), res, nil
}
// Execute the binary search and hone in on an executable energy limit
for lo+1 < hi {
mid := (hi + lo) / 2
if !executable(mid) {
failed, _, err := executable(mid)

// If the error is not nil(consensus error), it means the provided message
// call or transaction will never be accepted no matter how much gas it is
// assigned. Return the error directly, don't struggle any more
if err != nil {
return 0, err
}
if failed {
lo = mid
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
if !executable(hi) {
return 0, errEnergyEstimationFailed
failed, result, err := executable(hi)
if err != nil {
return 0, err
}
if failed {
if result != nil && result.Err != vm.ErrOutOfEnergy {
errMsg := fmt.Sprintf("always failing transaction (%v)", result.Err)
if len(result.Revert()) > 0 {
ret, err := abi.UnpackRevert(result.Revert())
if err != nil {
errMsg += fmt.Sprintf(" (%#x)", result.Revert())
} else {
errMsg += fmt.Sprintf(" (%s)", ret)
}
}
return 0, errors.New(errMsg)
}
// Otherwise, the specified energy cap is too low
return 0, fmt.Errorf("energy required exceeds allowance (%d)", cap)
}
}
return hi, nil
}

// callContract implements common code between normal and pending contract calls.
// state is modified during execution, make sure to copy it if necessary.
func (b *SimulatedBackend) callContract(ctx context.Context, call gocore.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) {
func (b *SimulatedBackend) callContract(ctx context.Context, call gocore.CallMsg, block *types.Block, statedb *state.StateDB) (*core.ExecutionResult, error) {
// Ensure message is initialized properly.
if call.EnergyPrice == nil {
call.EnergyPrice = big.NewInt(1)
Expand Down
122 changes: 105 additions & 17 deletions accounts/abi/bind/backends/simulated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"context"
"crypto/rand"
"errors"
eddsa "github.com/core-coin/go-goldilocks"
"math/big"
"strings"
Expand Down Expand Up @@ -366,26 +367,113 @@ func TestSimulatedBackend_TransactionByHash(t *testing.T) {
}

func TestSimulatedBackend_EstimateEnergy(t *testing.T) {
sim := NewSimulatedBackend(
core.GenesisAlloc{}, 10000000,
)
/*
pragma solidity ^0.6.4;
contract EnergyEstimation {
function PureRevert() public { revert(); }
function Revert() public { revert("revert reason");}
function OOG() public { for (uint i = 0; ; i++) {}}
function Assert() public { assert(false);}
function Valid() public {}
}*/
const contractAbi = "[{\"inputs\":[],\"name\":\"Assert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OOG\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PureRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Revert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Valid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
const contractBin = "608060405234801561001057600080fd5b5061027a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80633ae247141461005c578063593b9361146100665780636c5fcd821461007057806396be6e031461007a578063a842ede314610084575b600080fd5b61006461008e565b005b61006e6100c9565b005b6100786100ce565b005b6100826100e4565b005b61008c6100e6565b005b6040517f4e401cbe0000000000000000000000000000000000000000000000000000000081526004016100c090610140565b60405180910390fd5b600080fd5b60005b80806100dc9061017b565b9150506100d1565b565b600061011b577f4b1f2ce300000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b565b600061012a600d83610160565b9150610135826101f3565b602082019050919050565b600060208201905081810360008301526101598161011d565b9050919050565b600082825260208201905092915050565b6000819050919050565b600061018682610171565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156101b9576101b86101c4565b5b600182019050919050565b7f4b1f2ce300000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f72657665727420726561736f6e0000000000000000000000000000000000000060008201525056fea26469706673582212202458901c98e418f9c6e0efe666fc13c1536b98db06e04c1d7bae3eede256401f64736f6c63782a302e382e342d646576656c6f702e323032322e372e382b636f6d6d69742e30353336326564342e6d6f64005b"

key, _ := crypto.GenerateKey(rand.Reader)
pub := eddsa.Ed448DerivePublicKey(*key)
addr := crypto.PubkeyToAddress(pub)
opts := bind.NewKeyedTransactor(key)

sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Core)}}, 10000000)
defer sim.Close()
bgCtx := context.Background()
pub := eddsa.Ed448DerivePublicKey(*testKey)
testAddr := crypto.PubkeyToAddress(pub)

energy, err := sim.EstimateEnergy(bgCtx, gocore.CallMsg{
From: testAddr,
To: &testAddr,
Value: big.NewInt(1000),
Data: []byte{},
})
if err != nil {
t.Errorf("could not estimate energy: %v", err)
}
parsed, _ := abi.JSON(strings.NewReader(contractAbi))
contractAddr, _, _, _ := bind.DeployContract(opts, parsed, common.FromHex(contractBin), sim)
sim.Commit()

if energy != params.TxEnergy {
t.Errorf("expected 21000 energy cost for a transaction got %v", energy)
var cases = []struct {
name string
message gocore.CallMsg
expect uint64
expectError error
}{
{"plain transfer(valid)", gocore.CallMsg{
From: addr,
To: &addr,
Energy: 0,
EnergyPrice: big.NewInt(0),
Value: big.NewInt(1),
Data: nil,
}, params.TxEnergy, nil},

{"plain transfer(invalid)", gocore.CallMsg{
From: addr,
To: &contractAddr,
Energy: 0,
EnergyPrice: big.NewInt(0),
Value: big.NewInt(1),
Data: nil,
}, 0, errors.New("always failing transaction (execution reverted)")},

{"Revert", gocore.CallMsg{
From: addr,
To: &contractAddr,
Energy: 0,
EnergyPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("3ae24714"),
}, 0, errors.New("always failing transaction (execution reverted) (revert reason)")},

{"PureRevert", gocore.CallMsg{
From: addr,
To: &contractAddr,
Energy: 0,
EnergyPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("593b9361"),
}, 0, errors.New("always failing transaction (execution reverted)")},

{"OOG", gocore.CallMsg{
From: addr,
To: &contractAddr,
Energy: 100000,
EnergyPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("6c5fcd82"),
}, 0, errors.New("energy required exceeds allowance (100000)")},

{"Assert", gocore.CallMsg{
From: addr,
To: &contractAddr,
Energy: 100000,
EnergyPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("a842ede3"),
}, 0, errors.New("always failing transaction (execution reverted) (0x4b1f2ce30000000000000000000000000000000000000000000000000000000000000001)")},

{"Valid", gocore.CallMsg{
From: addr,
To: &contractAddr,
Energy: 100000,
EnergyPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("96be6e03"),
}, 21252, nil},
}
for _, c := range cases {
got, err := sim.EstimateEnergy(context.Background(), c.message)
if c.expectError != nil {
if err == nil {
t.Fatalf("Expect error, got nil")
}
if c.expectError.Error() != err.Error() {
t.Fatalf("Expect error, want %v, got %v", c.expectError, err)
}
continue
}
if got != c.expect {
t.Fatalf("Energy estimation mismatch, want %d, got %d", c.expect, got)
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/gocore/retestxcb.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ func (api *RetestxcbAPI) AccountRange(ctx context.Context,
context := core.NewCVMContext(msg, block.Header(), api.blockchain, nil)
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewCVM(context, statedb, api.blockchain.Config(), vm.Config{})
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.EnergyPool).AddEnergy(tx.Energy())); err != nil {
if _, err := core.ApplyMessage(vmenv, msg, new(core.EnergyPool).AddEnergy(tx.Energy())); err != nil {
return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
Expand Down Expand Up @@ -701,7 +701,7 @@ func (api *RetestxcbAPI) StorageRangeAt(ctx context.Context,
context := core.NewCVMContext(msg, block.Header(), api.blockchain, nil)
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewCVM(context, statedb, api.blockchain.Config(), vm.Config{})
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.EnergyPool).AddEnergy(tx.Energy())); err != nil {
if _, err := core.ApplyMessage(vmenv, msg, new(core.EnergyPool).AddEnergy(tx.Energy())); err != nil {
return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
Expand Down
Loading