344 lines
14 KiB
Go
344 lines
14 KiB
Go
package builder_test
|
|
|
|
import (
|
|
"testing"
|
|
"math/big"
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
b "github.com/ethereum/go-ethereum/statediff/builder"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"bytes"
|
|
"reflect"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
)
|
|
|
|
var (
|
|
testdb = ethdb.NewMemDatabase()
|
|
|
|
testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) //0x71562b71999873DB5b286dF957af199Ec94617F7
|
|
testBankFunds = big.NewInt(100000000)
|
|
genesis = core.GenesisBlockForTesting(testdb, testBankAddress, testBankFunds)
|
|
|
|
account1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
|
account2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
|
|
account1Addr = crypto.PubkeyToAddress(account1Key.PublicKey) //0x703c4b2bD70c169f5717101CaeE543299Fc946C7
|
|
account2Addr = crypto.PubkeyToAddress(account2Key.PublicKey) //0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
|
|
|
|
contractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056")
|
|
contractAddr common.Address
|
|
|
|
emptyAccountDiffEventualMap = make(map[common.Address]b.AccountDiffEventual)
|
|
emptyAccountDiffIncrementalMap = make(map[common.Address]b.AccountDiffIncremental)
|
|
|
|
block0Hash, block1Hash, block2Hash, block3Hash common.Hash
|
|
block0, block1, block2, block3 *types.Block
|
|
builder b.Builder
|
|
miningReward = int64(3000000000000000000)
|
|
burnAddress = common.HexToAddress("0x0")
|
|
)
|
|
|
|
func TestBuilder(t *testing.T) {
|
|
_, blocks := makeChain(3, genesis)
|
|
block0Hash = common.HexToHash("0xd1721cfd0b29c36fd7a68f25c128e86413fb666a6e1d68e89b875bd299262661")
|
|
block1Hash = common.HexToHash("0x47c398dd688eaa4dd11b006888156783fe32df83d59b197c0fcd303408103d39")
|
|
block2Hash = common.HexToHash("0x351b2f531838683ba457e8ca4d3a844cc48147dceafbcb589dc6e3227856ee75")
|
|
block3Hash = common.HexToHash("0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73")
|
|
|
|
block0 = blocks[block0Hash]
|
|
block1 = blocks[block1Hash]
|
|
block2 = blocks[block2Hash]
|
|
block3 = blocks[block3Hash]
|
|
builder = b.NewBuilder(testdb)
|
|
|
|
type arguments struct {
|
|
oldStateRoot common.Hash
|
|
newStateRoot common.Hash
|
|
blockNumber int64
|
|
blockHash common.Hash
|
|
}
|
|
|
|
|
|
var (
|
|
balanceChange10000 = int64(10000)
|
|
balanceChange1000 = int64(1000)
|
|
block1BankBalance = int64(99990000)
|
|
block1Account1Balance = int64(10000)
|
|
block2Account2Balance = int64(1000)
|
|
nonce0 = uint64(0)
|
|
nonce1 = uint64(1)
|
|
nonce2 = uint64(2)
|
|
nonce3 = uint64(3)
|
|
originalContractRoot = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
|
|
newContractRoot = "0x9e676b23802aff85d29b4f0243939bc6ecfdca2a41532310091781854d6ffeb2"
|
|
newStorageValue = "0x03"
|
|
)
|
|
|
|
var tests = []struct{
|
|
name string
|
|
startingArguments arguments
|
|
expected *b.StateDiff
|
|
} {
|
|
{
|
|
"testEmptyDiff",
|
|
arguments{
|
|
oldStateRoot: block0.Root(),
|
|
newStateRoot: block0.Root(),
|
|
blockNumber: block0.Number().Int64(),
|
|
blockHash: block0Hash,
|
|
},
|
|
&b.StateDiff{
|
|
BlockNumber: block0.Number().Int64(),
|
|
BlockHash: block0Hash,
|
|
CreatedAccounts: emptyAccountDiffEventualMap,
|
|
DeletedAccounts: emptyAccountDiffEventualMap,
|
|
UpdatedAccounts: emptyAccountDiffIncrementalMap,
|
|
},
|
|
},
|
|
{
|
|
"testBlock1",
|
|
//10000 transferred from testBankAddress to account1Addr
|
|
arguments{
|
|
oldStateRoot: block0.Root(),
|
|
newStateRoot: block1.Root(),
|
|
blockNumber: block1.Number().Int64(),
|
|
blockHash: block1Hash,
|
|
},
|
|
&b.StateDiff{
|
|
BlockNumber: block1.Number().Int64(),
|
|
BlockHash: block1.Hash(),
|
|
CreatedAccounts: map[common.Address]b.AccountDiffEventual{
|
|
account1Addr: {
|
|
Nonce: b.DiffUint64{ Value: &nonce0 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(balanceChange10000) },
|
|
Code: nil,
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
burnAddress: {
|
|
Nonce: b.DiffUint64{ Value: &nonce0 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(miningReward)},
|
|
Code: nil,
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
},
|
|
DeletedAccounts: emptyAccountDiffEventualMap,
|
|
UpdatedAccounts: map[common.Address]b.AccountDiffIncremental{
|
|
testBankAddress: {
|
|
Nonce: b.DiffUint64{ Value: &nonce1 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(testBankFunds.Int64() - balanceChange10000) },
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"testBlock2",
|
|
//1000 transferred from testBankAddress to account1Addr
|
|
//1000 transferred from account1Addr to account2Addr
|
|
arguments{
|
|
oldStateRoot: block1.Root(),
|
|
newStateRoot: block2.Root(),
|
|
blockNumber: block2.Number().Int64(),
|
|
blockHash: block2Hash,
|
|
},
|
|
&b.StateDiff{
|
|
BlockNumber: block2.Number().Int64(),
|
|
BlockHash: block2.Hash(),
|
|
CreatedAccounts: map[common.Address]b.AccountDiffEventual{
|
|
account2Addr: {
|
|
Nonce: b.DiffUint64{ Value: &nonce0 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(balanceChange1000) },
|
|
Code: nil,
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot},
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
contractAddr: {
|
|
Nonce: b.DiffUint64{ Value: &nonce1 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(0) },
|
|
Code: []byte{96, 96, 96, 64, 82, 96, 0, 53, 124, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 4, 128, 99, 96, 205, 38, 133, 20, 96, 65, 87, 128, 99, 193, 100, 49, 185, 20, 96, 107, 87, 96, 63, 86, 91, 0, 91, 96, 85, 96, 4, 128, 128, 53, 144, 96, 32, 1, 144, 145, 144, 80, 80, 96, 169, 86, 91, 96, 64, 81, 128, 130, 129, 82, 96, 32, 1, 145, 80, 80, 96, 64, 81, 128, 145, 3, 144, 243, 91, 96, 136, 96, 4, 128, 128, 53, 144, 96, 32, 1, 144, 145, 144, 128, 53, 144, 96, 32, 1, 144, 145, 144, 80, 80, 96, 138, 86, 91, 0, 91, 128, 96, 0, 96, 0, 80, 131, 96, 100, 129, 16, 21, 96, 2, 87, 144, 144, 1, 96, 0, 91, 80, 129, 144, 85, 80, 91, 80, 80, 86, 91, 96, 0, 96, 0, 96, 0, 80, 130, 96, 100, 129, 16, 21, 96, 2, 87, 144, 144, 1, 96, 0, 91, 80, 84, 144, 80, 96, 199, 86, 91, 145, 144, 80, 86},
|
|
CodeHash: "0x1c671ee4ae8abbacab7da59d6f8785cce8295eb086551ce7ac266a2e93666c0f",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot},
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
},
|
|
DeletedAccounts: emptyAccountDiffEventualMap,
|
|
UpdatedAccounts: map[common.Address]b.AccountDiffIncremental{
|
|
testBankAddress: {
|
|
Nonce: b.DiffUint64{ Value: &nonce2 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(block1BankBalance - balanceChange1000) },
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
account1Addr: {
|
|
Nonce: b.DiffUint64{ Value: &nonce2 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000) },
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
burnAddress: {
|
|
Nonce: b.DiffUint64{ Value: &nonce0 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(miningReward + miningReward) },
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"testBlock3",
|
|
//the contract's storage is changed
|
|
//and the block is mined by account 2
|
|
arguments{
|
|
oldStateRoot: block2.Root(),
|
|
newStateRoot: block3.Root(),
|
|
blockNumber: block3.Number().Int64(),
|
|
blockHash: block3.Hash(),
|
|
},
|
|
&b.StateDiff{
|
|
BlockNumber: block3.Number().Int64(),
|
|
BlockHash: block3.Hash(),
|
|
CreatedAccounts: map[common.Address]b.AccountDiffEventual{},
|
|
DeletedAccounts: emptyAccountDiffEventualMap,
|
|
UpdatedAccounts: map[common.Address]b.AccountDiffIncremental{
|
|
account2Addr: {
|
|
Nonce: b.DiffUint64{ Value: &nonce0 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(block2Account2Balance + miningReward) },
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
contractAddr: {
|
|
Nonce: b.DiffUint64{ Value: &nonce1 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(0) },
|
|
CodeHash: "0x1c671ee4ae8abbacab7da59d6f8785cce8295eb086551ce7ac266a2e93666c0f",
|
|
ContractRoot: b.DiffString{ Value: &newContractRoot },
|
|
Storage: map[string]b.DiffString{
|
|
"0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": {
|
|
Value: &newStorageValue },
|
|
},
|
|
},
|
|
testBankAddress: {
|
|
Nonce: b.DiffUint64{ Value: &nonce3 },
|
|
Balance: b.DiffBigInt{ Value: big.NewInt(99989000) },
|
|
CodeHash: "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
ContractRoot: b.DiffString{ Value: &originalContractRoot },
|
|
Storage: map[string]b.DiffString{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
arguments := test.startingArguments
|
|
diff, err := builder.BuildStateDiff(arguments.oldStateRoot, arguments.newStateRoot, arguments.blockNumber, arguments.blockHash)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
fields := []string{"BlockNumber", "BlockHash", "DeletedAccounts", "UpdatedAccounts", "CreatedAccounts"}
|
|
|
|
for _, field := range fields {
|
|
reflectionOfDiff := reflect.ValueOf(diff)
|
|
diffValue := reflect.Indirect(reflectionOfDiff).FieldByName(field)
|
|
|
|
reflectionOfExpected := reflect.ValueOf(test.expected)
|
|
expectedValue := reflect.Indirect(reflectionOfExpected).FieldByName(field)
|
|
|
|
diffValueInterface := diffValue.Interface()
|
|
expectedValueInterface := expectedValue.Interface()
|
|
|
|
if !equals(diffValueInterface, expectedValueInterface) {
|
|
t.Logf("Test failed: %s", test.name)
|
|
t.Errorf("field: %+v\nactual: %+v\nexpected: %+v", field, diffValueInterface, expectedValueInterface)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func equals(actual, expected interface{}) (success bool) {
|
|
if actualByteSlice, ok := actual.([]byte); ok {
|
|
if expectedByteSlice, ok := expected.([]byte); ok {
|
|
return bytes.Equal(actualByteSlice, expectedByteSlice)
|
|
}
|
|
}
|
|
|
|
return reflect.DeepEqual(actual, expected)
|
|
}
|
|
|
|
// makeChain creates a chain of n blocks starting at and including parent.
|
|
// the returned hash chain is ordered head->parent. In addition, every 3rd block
|
|
// contains a transaction and every 5th an uncle to allow testing correct block
|
|
// reassembly.
|
|
func makeChain(n int, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
|
|
blocks, _ := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), testdb, n, testChainGen)
|
|
hashes := make([]common.Hash, n+1)
|
|
hashes[len(hashes)-1] = parent.Hash()
|
|
blockm := make(map[common.Hash]*types.Block, n+1)
|
|
blockm[parent.Hash()] = parent
|
|
for i, b := range blocks {
|
|
hashes[len(hashes)-i-2] = b.Hash()
|
|
blockm[b.Hash()] = b
|
|
}
|
|
return hashes, blockm
|
|
}
|
|
|
|
func testChainGen(i int, block *core.BlockGen) {
|
|
signer := types.HomesteadSigner{}
|
|
switch i {
|
|
case 0:
|
|
// In block 1, the test bank sends account #1 some ether.
|
|
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), account1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
|
|
block.AddTx(tx)
|
|
case 1:
|
|
// In block 2, the test bank sends some more ether to account #1.
|
|
// account1Addr passes it on to account #2.
|
|
// account1Addr creates a test contract.
|
|
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), account1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
|
|
nonce := block.TxNonce(account1Addr)
|
|
tx2, _ := types.SignTx(types.NewTransaction(nonce, account2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, account1Key)
|
|
nonce++
|
|
tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), contractCode), signer, account1Key)
|
|
contractAddr = crypto.CreateAddress(account1Addr, nonce) //0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592
|
|
block.AddTx(tx1)
|
|
block.AddTx(tx2)
|
|
block.AddTx(tx3)
|
|
case 2:
|
|
// Block 3 is empty but was mined by account #2.
|
|
block.SetCoinbase(account2Addr)
|
|
//get function: 60cd2685
|
|
//put function: c16431b9
|
|
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003")
|
|
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), contractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey)
|
|
block.AddTx(tx)
|
|
}
|
|
}
|
|
|
|
/*
|
|
contract test {
|
|
|
|
uint256[100] data;
|
|
|
|
function Put(uint256 addr, uint256 value) {
|
|
data[addr] = value;
|
|
}
|
|
|
|
function Get(uint256 addr) constant returns (uint256 value) {
|
|
return data[addr];
|
|
}
|
|
}
|
|
*/
|