diff --git a/manager/eris-mint/evm/vm.go b/manager/eris-mint/evm/vm.go index d1c50df6937b3c4291353dc891d012377efb3d38..7f0c7c05509821bde984ce6b8500cb6417263d1d 100644 --- a/manager/eris-mint/evm/vm.go +++ b/manager/eris-mint/evm/vm.go @@ -735,6 +735,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas // TODO charge for gas to create account _ the code length * GasCreateByte newAccount := vm.appState.CreateAccount(callee) + // Run the input to get the contract code. // NOTE: no need to copy 'input' as per Call contract. ret, err_ := vm.Call(callee, newAccount, input, input, contractValue, gas) @@ -800,19 +801,16 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas } ret, err = vm.Call(callee, callee, acc.Code, args, value, gas) } else { + // nil account means we're sending funds to a new account if acc == nil { - // nil account means we're sending funds to a new account if !HasPermission(vm.appState, caller, ptypes.CreateAccount) { return nil, ErrPermission{"create_account"} } acc = &Account{Address: addr} - vm.appState.UpdateAccount(acc) - // send funds to new account - ret, err = vm.Call(callee, acc, acc.Code, args, value, gas) - } else { - // call standard contract - ret, err = vm.Call(callee, acc, acc.Code, args, value, gas) } + // add account to the tx cache + vm.appState.UpdateAccount(acc) + ret, err = vm.Call(callee, acc, acc.Code, args, value, gas) } } diff --git a/manager/eris-mint/state/execution.go b/manager/eris-mint/state/execution.go index 9d2aaa2e96965554b813a9f7171050b751acd737..54799c38b06213baeb36dad89750fb11f83d1769 100644 --- a/manager/eris-mint/state/execution.go +++ b/manager/eris-mint/state/execution.go @@ -513,7 +513,7 @@ func ExecTx(blockCache *BlockCache, tx txs.Tx, runCall bool, evc events.Fireable // and only deduct from the caller's balance. inAcc.Balance -= value if createContract { - inAcc.Sequence += 1 + inAcc.Sequence += 1 // XXX ?! } blockCache.UpdateAccount(inAcc) } diff --git a/manager/eris-mint/state/state_test.go b/manager/eris-mint/state/state_test.go index 9dcd465d19bdcd4a00acbbbd882a458800994549..7f8cb8f11258e167fd2fe99fe8bc0dc7c5d794e2 100644 --- a/manager/eris-mint/state/state_test.go +++ b/manager/eris-mint/state/state_test.go @@ -2,13 +2,16 @@ package state import ( "bytes" + "encoding/hex" "testing" //"time" + "github.com/tendermint/go-common" "github.com/tendermint/tendermint/config/tendermint_test" // tmtypes "github.com/tendermint/tendermint/types" core_types "github.com/eris-ltd/eris-db/core/types" + //evm "github.com/eris-ltd/eris-db/manager/eris-mint/evm" "github.com/eris-ltd/eris-db/txs" ) @@ -382,6 +385,156 @@ func TestNameTxs(t *testing.T) { } } +// Test creating a contract from futher down the call stack +/* +contract Factory { + address a; + function create() returns (address){ + a = new PreFactory(); + return a; + } +} + +contract PreFactory{ + address a; + function create(Factory c) returns (address) { + a = c.create(); + return a; + } +} +*/ + +// run-time byte code for each of the above +var preFactoryCode, _ = hex.DecodeString("60606040526000357C0100000000000000000000000000000000000000000000000000000000900480639ED933181461003957610037565B005B61004F600480803590602001909190505061007B565B604051808273FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16815260200191505060405180910390F35B60008173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1663EFC81A8C604051817C01000000000000000000000000000000000000000000000000000000000281526004018090506020604051808303816000876161DA5A03F1156100025750505060405180519060200150600060006101000A81548173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02191690830217905550600060009054906101000A900473FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16905061013C565B91905056") +var factoryCode, _ = hex.DecodeString("60606040526000357C010000000000000000000000000000000000000000000000000000000090048063EFC81A8C146037576035565B005B60426004805050606E565B604051808273FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16815260200191505060405180910390F35B6000604051610153806100E0833901809050604051809103906000F0600060006101000A81548173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02191690830217905550600060009054906101000A900473FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16905060DD565B90566060604052610141806100126000396000F360606040526000357C0100000000000000000000000000000000000000000000000000000000900480639ED933181461003957610037565B005B61004F600480803590602001909190505061007B565B604051808273FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16815260200191505060405180910390F35B60008173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1663EFC81A8C604051817C01000000000000000000000000000000000000000000000000000000000281526004018090506020604051808303816000876161DA5A03F1156100025750505060405180519060200150600060006101000A81548173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02191690830217905550600060009054906101000A900473FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16905061013C565B91905056") +var createData, _ = hex.DecodeString("9ed93318") + +func TestCreates(t *testing.T) { + //evm.SetDebug(true) + state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000) + + //val0 := state.GetValidatorInfo(privValidators[0].Address) + acc0 := state.GetAccount(privAccounts[0].PubKey.Address()) + acc0PubKey := privAccounts[0].PubKey + acc1 := state.GetAccount(privAccounts[1].PubKey.Address()) + acc2 := state.GetAccount(privAccounts[2].PubKey.Address()) + + state = state.Copy() + newAcc1 := state.GetAccount(acc1.Address) + newAcc1.Code = preFactoryCode + newAcc2 := state.GetAccount(acc2.Address) + newAcc2.Code = factoryCode + + state.UpdateAccount(newAcc1) + state.UpdateAccount(newAcc2) + + createData = append(createData, common.LeftPadBytes(acc2.Address, 32)...) + + // call the pre-factory, triggering the factory to run a create + tx := &txs.CallTx{ + Input: &txs.TxInput{ + Address: acc0.Address, + Amount: 1, + Sequence: acc0.Sequence + 1, + PubKey: acc0PubKey, + }, + Address: acc1.Address, + GasLimit: 10000, + Data: createData, + } + + tx.Input.Signature = privAccounts[0].Sign(state.ChainID, tx) + err := execTxWithState(state, tx, true) + if err != nil { + t.Errorf("Got error in executing call transaction, %v", err) + } + + acc1 = state.GetAccount(acc1.Address) + storage := state.LoadStorage(acc1.StorageRoot) + _, firstCreatedAddress, _ := storage.Get(common.LeftPadBytes([]byte{0}, 32)) + + acc0 = state.GetAccount(acc0.Address) + // call the pre-factory, triggering the factory to run a create + tx = &txs.CallTx{ + Input: &txs.TxInput{ + Address: acc0.Address, + Amount: 1, + Sequence: acc0.Sequence + 1, + PubKey: acc0PubKey, + }, + Address: acc1.Address, + GasLimit: 10000, + Data: createData, + } + + tx.Input.Signature = privAccounts[0].Sign(state.ChainID, tx) + err = execTxWithState(state, tx, true) + if err != nil { + t.Errorf("Got error in executing call transaction, %v", err) + } + + acc1 = state.GetAccount(acc1.Address) + storage = state.LoadStorage(acc1.StorageRoot) + _, secondCreatedAddress, _ := storage.Get(common.LeftPadBytes([]byte{0}, 32)) + + if bytes.Equal(firstCreatedAddress, secondCreatedAddress) { + t.Errorf("Multiple contracts created with the same address!") + } +} + +/* +contract Caller { + function send(address x){ + x.send(msg.value); + } +} +*/ +var callerCode, _ = hex.DecodeString("60606040526000357c0100000000000000000000000000000000000000000000000000000000900480633e58c58c146037576035565b005b604b6004808035906020019091905050604d565b005b8073ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f19350505050505b5056") +var sendData, _ = hex.DecodeString("3e58c58c") + +func TestContractSend(t *testing.T) { + state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000) + + //val0 := state.GetValidatorInfo(privValidators[0].Address) + acc0 := state.GetAccount(privAccounts[0].PubKey.Address()) + acc0PubKey := privAccounts[0].PubKey + acc1 := state.GetAccount(privAccounts[1].PubKey.Address()) + acc2 := state.GetAccount(privAccounts[2].PubKey.Address()) + + state = state.Copy() + newAcc1 := state.GetAccount(acc1.Address) + newAcc1.Code = callerCode + state.UpdateAccount(newAcc1) + + sendData = append(sendData, common.LeftPadBytes(acc2.Address, 32)...) + sendAmt := int64(10) + acc2Balance := acc2.Balance + + // call the contract, triggering the send + tx := &txs.CallTx{ + Input: &txs.TxInput{ + Address: acc0.Address, + Amount: sendAmt, + Sequence: acc0.Sequence + 1, + PubKey: acc0PubKey, + }, + Address: acc1.Address, + GasLimit: 1000, + Data: sendData, + } + + tx.Input.Signature = privAccounts[0].Sign(state.ChainID, tx) + err := execTxWithState(state, tx, true) + if err != nil { + t.Errorf("Got error in executing call transaction, %v", err) + } + + acc2 = state.GetAccount(acc2.Address) + if acc2.Balance != sendAmt+acc2Balance { + t.Errorf("Value transfer from contract failed! Got %d, expected %d", acc2.Balance, sendAmt+acc2Balance) + } +} + // TODO: test overflows. // TODO: test for unbonding validators. func TestTxs(t *testing.T) { diff --git a/manager/eris-mint/state/tx_cache.go b/manager/eris-mint/state/tx_cache.go index 265e4c63b3b4c71d8c74a20622cf28f36159c377..858dc68d719d945588315b2c050c3bc3e99dba44 100644 --- a/manager/eris-mint/state/tx_cache.go +++ b/manager/eris-mint/state/tx_cache.go @@ -120,7 +120,6 @@ func (cache *TxCache) SetStorage(addr Word256, key Word256, value Word256) { // These updates do not have to be in deterministic order, // the backend is responsible for ordering updates. func (cache *TxCache) Sync() { - // Remove or update storage for addrKey, value := range cache.storages { addr, key := Tuple256Split(addrKey)