Browse Source

Merge pull request #37 from tendermint/create_and_transact

state: fixes for creating a contract and msging it in the same block
pull/40/head
ebuchman 10 years ago
parent
commit
3b05b24b68
2 changed files with 35 additions and 8 deletions
  1. +9
    -1
      block/tx.go
  2. +26
    -7
      state/state.go

+ 9
- 1
block/tx.go View File

@ -18,9 +18,17 @@ var (
ErrTxUnknownPubKey = errors.New("Error unknown pubkey")
ErrTxInvalidPubKey = errors.New("Error invalid pubkey")
ErrTxInvalidSignature = errors.New("Error invalid signature")
ErrTxInvalidSequence = errors.New("Error invalid sequence")
)
type ErrTxInvalidSequence struct {
Got uint64
Expected uint64
}
func (e ErrTxInvalidSequence) Error() string {
return Fmt("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected)
}
/*
Tx (Transaction) is an atomic operation on the ledger state.


+ 26
- 7
state/state.go View File

@ -196,7 +196,10 @@ func (s *State) ValidateInput(acc *account.Account, signBytes []byte, in *blk.Tx
}
// Check sequences
if acc.Sequence+1 != in.Sequence {
return blk.ErrTxInvalidSequence
return blk.ErrTxInvalidSequence{
Got: uint64(in.Sequence),
Expected: uint64(acc.Sequence + 1),
}
}
// Check amount
if acc.Balance < in.Amount {
@ -308,13 +311,14 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
log.Debug(Fmt("Destination address is not 20 bytes %X", tx.Address))
return blk.ErrTxInvalidAddress
}
// this may be nil if we are still in mempool and contract was created in same block as this tx
// but that's fine, because the account will be created properly when the create tx runs in the block
// and then this won't return nil. otherwise, we take their fee
outAcc = s.GetAccount(tx.Address)
if outAcc == nil {
log.Debug(Fmt("Cannot find destination address %X", tx.Address))
return blk.ErrTxInvalidAddress
}
}
log.Debug(Fmt("Out account: %v", outAcc))
// Good!
value := tx.Input.Amount - tx.Fee
inAcc.Sequence += 1
@ -338,9 +342,18 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
// Maybe create a new callee account if
// this transaction is creating a new contract.
if outAcc != nil {
if !createAccount {
if outAcc == nil {
// take fees (sorry pal)
inAcc.Balance -= tx.Fee
s.UpdateAccount(inAcc)
log.Debug(Fmt("Cannot find destination address %X. Deducting fee from caller", tx.Address))
return blk.ErrTxInvalidAddress
}
callee = toVMAccount(outAcc)
code = callee.Code
log.Debug(Fmt("Calling contract %X with code %X", callee.Address.Address(), callee.Code))
} else {
callee, err = appState.CreateAccount(caller)
if err != nil {
@ -350,6 +363,7 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
log.Debug(Fmt("Created new account %X", callee.Address.Address()))
code = tx.Data
}
log.Debug(Fmt("Code for this contract: %X", code))
appState.UpdateAccount(caller) // because we adjusted by input above, and bumped nonce maybe.
appState.UpdateAccount(callee) // because we adjusted by input above.
@ -358,10 +372,12 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
if err != nil {
// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
log.Debug(Fmt("Error on execution: %v", err))
inAcc.Balance -= tx.Fee
s.UpdateAccount(inAcc)
// Throw away 'appState' which holds incomplete updates.
// Throw away 'appState' which holds incomplete updates (don't sync it).
} else {
log.Debug("Successful execution")
// Success
if createAccount {
callee.Code = ret
@ -377,6 +393,9 @@ func (s *State) ExecTx(tx_ blk.Tx, runCall bool) error {
// So mempool will skip the actual .Call(),
// and only deduct from the caller's balance.
inAcc.Balance -= value
if createAccount {
inAcc.Sequence += 1
}
s.UpdateAccount(inAcc)
}


Loading…
Cancel
Save