Browse Source

Address is generated with VMAppState, and it increments the nonce too.

pull/32/head
Jae Kwon 10 years ago
parent
commit
b7553e2bfe
5 changed files with 65 additions and 35 deletions
  1. +30
    -11
      state/state.go
  2. +15
    -2
      state/vm_app_state.go
  3. +17
    -7
      vm/test/fake_app_state.go
  4. +1
    -1
      vm/types.go
  5. +2
    -14
      vm/vm.go

+ 30
- 11
state/state.go View File

@ -277,8 +277,10 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
return nil return nil
case *blk.CallTx: case *blk.CallTx:
var inAcc, outAcc *account.Account
// Validate input // Validate input
inAcc := s.GetAccount(tx.Input.Address)
inAcc = s.GetAccount(tx.Input.Address)
if inAcc == nil { if inAcc == nil {
return blk.ErrTxInvalidAddress return blk.ErrTxInvalidAddress
} }
@ -295,13 +297,16 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
return blk.ErrTxInsufficientFunds return blk.ErrTxInsufficientFunds
} }
// Validate output
if len(tx.Address) != 20 {
return blk.ErrTxInvalidAddress
}
outAcc := s.GetAccount(tx.Address)
if outAcc == nil {
return blk.ErrTxInvalidAddress
createAccount := len(tx.Address) == 0
if !createAccount {
// Validate output
if len(tx.Address) != 20 {
return blk.ErrTxInvalidAddress
}
outAcc = s.GetAccount(tx.Address)
if outAcc == nil {
return blk.ErrTxInvalidAddress
}
} }
// Good! // Good!
@ -316,9 +321,18 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
BlockTime: s.LastBlockTime.Unix(), BlockTime: s.LastBlockTime.Unix(),
GasLimit: 10000000, GasLimit: 10000000,
} }
caller := toVMAccount(inAcc)
callee := toVMAccount(outAcc)
appState.AddAccount(caller) // because we adjusted by input above.
var caller, callee *vm.Account
var err error
caller = toVMAccount(inAcc)
if outAcc == nil {
callee = toVMAccount(outAcc)
} else {
callee, err = appState.CreateAccount(caller)
if err != nil {
return err
}
}
appState.AddAccount(caller) // because we adjusted by input above, and bumped nonce maybe.
appState.AddAccount(callee) // because we adjusted by input above. appState.AddAccount(callee) // because we adjusted by input above.
vmach := vm.NewVM(appState, params, caller.Address) vmach := vm.NewVM(appState, params, caller.Address)
gas := tx.GasLimit gas := tx.GasLimit
@ -330,6 +344,9 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
// Throw away 'appState' which holds incomplete updates. // Throw away 'appState' which holds incomplete updates.
} else { } else {
// Success // Success
if createAccount {
callee.Code = ret
}
appState.Sync() appState.Sync()
} }
// Create a receipt from the ret and whether errored. // Create a receipt from the ret and whether errored.
@ -339,6 +356,8 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
// the proposer determines the order of txs. // the proposer determines the order of txs.
// So mempool will skip the actual .Call(), // So mempool will skip the actual .Call(),
// and only deduct from the caller's balance. // and only deduct from the caller's balance.
inAcc.Balance -= value
s.UpdateAccount(inAcc)
} }
return nil return nil


+ 15
- 2
state/vm_app_state.go View File

@ -8,6 +8,7 @@ import (
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/merkle" "github.com/tendermint/tendermint/merkle"
"github.com/tendermint/tendermint/vm" "github.com/tendermint/tendermint/vm"
"github.com/tendermint/tendermint/vm/sha3"
) )
// Converts state.Account to vm.Account struct. // Converts state.Account to vm.Account struct.
@ -115,7 +116,18 @@ func (vas *VMAppState) DeleteAccount(account *vm.Account) error {
} }
} }
func (vas *VMAppState) CreateAccount(addr vm.Word) (*vm.Account, error) {
// Creates a 20 byte address and bumps the creator's nonce.
func (vas *VMAppState) CreateAccount(creator *vm.Account) (*vm.Account, error) {
// Generate an address
nonce := creator.Nonce
creator.Nonce += 1
temp := make([]byte, 32+8)
copy(temp, creator.Address[:])
vm.PutUint64(temp[32:], nonce)
addr := vm.RightPadWord(sha3.Sha3(temp)[:20])
// Create account from address.
account, deleted := unpack(vas.accounts[addr.String()]) account, deleted := unpack(vas.accounts[addr.String()])
if deleted || account == nil { if deleted || account == nil {
account = &vm.Account{ account = &vm.Account{
@ -128,7 +140,8 @@ func (vas *VMAppState) CreateAccount(addr vm.Word) (*vm.Account, error) {
vas.accounts[addr.String()] = AccountInfo{account, false} vas.accounts[addr.String()] = AccountInfo{account, false}
return account, nil return account, nil
} else { } else {
return nil, Errorf("Account already exists: %X", addr)
panic(Fmt("Could not create account, address already exists: %X", addr))
// return nil, Errorf("Account already exists: %X", addr)
} }
} }


+ 17
- 7
vm/test/fake_app_state.go View File

@ -5,6 +5,7 @@ import (
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
. "github.com/tendermint/tendermint/vm" . "github.com/tendermint/tendermint/vm"
"github.com/tendermint/tendermint/vm/sha3"
) )
type FakeAppState struct { type FakeAppState struct {
@ -43,7 +44,8 @@ func (fas *FakeAppState) DeleteAccount(account *Account) error {
} }
} }
func (fas *FakeAppState) CreateAccount(addr Word) (*Account, error) {
func (fas *FakeAppState) CreateAccount(creator *Account) (*Account, error) {
addr := createAddress(creator)
account := fas.accounts[addr.String()] account := fas.accounts[addr.String()]
if account == nil { if account == nil {
return &Account{ return &Account{
@ -102,16 +104,24 @@ func main() {
ourVm := NewVM(appState, params, Zero) ourVm := NewVM(appState, params, Zero)
// Create accounts // Create accounts
account1, err := appState.CreateAccount(Uint64ToWord(100))
if err != nil {
panic(err)
account1 := &Account{
Address: Uint64ToWord(100),
} }
account2, err := appState.CreateAccount(Uint64ToWord(101))
if err != nil {
panic(err)
account2 := &Account{
Address: Uint64ToWord(101),
} }
var gas uint64 = 1000 var gas uint64 = 1000
output, err := ourVm.Call(account1, account2, []byte{0x60, 0x01, 0x60, 0x01}, []byte{}, 0, &gas) output, err := ourVm.Call(account1, account2, []byte{0x60, 0x01, 0x60, 0x01}, []byte{}, 0, &gas)
fmt.Printf("Output: %v Error: %v\n", output, err) fmt.Printf("Output: %v Error: %v\n", output, err)
} }
// Creates a 20 byte address and bumps the nonce.
func createAddress(creator *Account) Word {
nonce := creator.Nonce
creator.Nonce += 1
temp := make([]byte, 32+8)
copy(temp, creator.Address[:])
PutUint64(temp[32:], nonce)
return RightPadWord(sha3.Sha3(temp)[:20])
}

+ 1
- 1
vm/types.go View File

@ -48,7 +48,7 @@ type AppState interface {
GetAccount(addr Word) (*Account, error) GetAccount(addr Word) (*Account, error)
UpdateAccount(*Account) error UpdateAccount(*Account) error
DeleteAccount(*Account) error DeleteAccount(*Account) error
CreateAccount(addr Word) (*Account, error)
CreateAccount(*Account) (*Account, error)
// Storage // Storage
GetStorage(Word, Word) (Word, error) GetStorage(Word, Word) (Word, error)


+ 2
- 14
vm/vm.go View File

@ -46,6 +46,7 @@ func NewVM(appState AppState, params Params, origin Word) *VM {
} }
} }
// CONTRACT appState is aware of caller and callee, so we can just mutate them.
// value: To be transferred from caller to callee. Refunded upon error. // value: To be transferred from caller to callee. Refunded upon error.
// gas: Available gas. No refunds for gas. // gas: Available gas. No refunds for gas.
func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
@ -541,14 +542,9 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrInsufficientBalance) return nil, firstErr(err, ErrInsufficientBalance)
} }
// Create a new address
nonce := caller.Nonce
addr := createAddress(caller.Address, nonce)
caller.Nonce += 1
// TODO charge for gas to create account _ the code length * GasCreateByte // TODO charge for gas to create account _ the code length * GasCreateByte
newAccount, err := vm.appState.CreateAccount(addr)
newAccount, err := vm.appState.CreateAccount(caller)
if err != nil { if err != nil {
stack.Push(Zero) stack.Push(Zero)
fmt.Printf(" (*) 0x0 %v\n", err) fmt.Printf(" (*) 0x0 %v\n", err)
@ -708,14 +704,6 @@ func useGas(gas *uint64, gasToUse uint64) bool {
} }
} }
// Creates a 20 byte address from the creatorAddr and nonce.
func createAddress(creatorAddr Word, nonce uint64) Word {
temp := make([]byte, 32+8)
copy(temp, creatorAddr[:])
PutUint64(temp[32:], nonce)
return RightPadWord(sha3.Sha3(temp)[:20])
}
func transfer(from, to *Account, amount uint64) error { func transfer(from, to *Account, amount uint64) error {
if from.Balance < amount { if from.Balance < amount {
return ErrInsufficientBalance return ErrInsufficientBalance


Loading…
Cancel
Save