Browse Source

block/state: add CallTx type

pull/32/head
Ethan Buchman 10 years ago
committed by Jae Kwon
parent
commit
7a33aba6e5
2 changed files with 84 additions and 10 deletions
  1. +27
    -0
      block/tx.go
  2. +57
    -10
      state/state.go

+ 27
- 0
block/tx.go View File

@ -25,6 +25,7 @@ Tx (Transaction) is an atomic operation on the ledger state.
Account Txs: Account Txs:
- SendTx Send coins to address - SendTx Send coins to address
- CallTx Send a msg to a contract that runs in the vm
Validation Txs: Validation Txs:
- BondTx New validator posts a bond - BondTx New validator posts a bond
@ -39,6 +40,7 @@ type Tx interface {
const ( const (
// Account transactions // Account transactions
TxTypeSend = byte(0x01) TxTypeSend = byte(0x01)
TxTypeCall = byte(0x02)
// Validation transactions // Validation transactions
TxTypeBond = byte(0x11) TxTypeBond = byte(0x11)
@ -51,6 +53,7 @@ const (
var _ = binary.RegisterInterface( var _ = binary.RegisterInterface(
struct{ Tx }{}, struct{ Tx }{},
binary.ConcreteType{&SendTx{}}, binary.ConcreteType{&SendTx{}},
binary.ConcreteType{&CallTx{}},
binary.ConcreteType{&BondTx{}}, binary.ConcreteType{&BondTx{}},
binary.ConcreteType{&UnbondTx{}}, binary.ConcreteType{&UnbondTx{}},
binary.ConcreteType{&RebondTx{}}, binary.ConcreteType{&RebondTx{}},
@ -139,6 +142,30 @@ func (tx *SendTx) String() string {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
type CallTx struct {
Input *TxInput
Address []byte
GasLimit uint64
FeeLimit uint64
Data []byte
}
func (tx *CallTx) TypeByte() byte { return TxTypeCall }
func (tx *CallTx) WriteSignBytes(w io.Writer, n *int64, err *error) {
tx.Input.WriteSignBytes(w, n, err)
binary.WriteByteSlice(tx.Address, w, n, err)
binary.WriteUint64(tx.GasLimit, w, n, err)
binary.WriteUint64(tx.FeeLimit, w, n, err)
binary.WriteByteSlice(tx.Data, w, n, err)
}
func (tx *CallTx) String() string {
return Fmt("CallTx{%v -> %x: %x}", tx.Input, tx.Address, tx.Data)
}
//-----------------------------------------------------------------------------
type BondTx struct { type BondTx struct {
PubKey account.PubKeyEd25519 PubKey account.PubKeyEd25519
Inputs []*TxInput Inputs []*TxInput


+ 57
- 10
state/state.go View File

@ -128,16 +128,8 @@ func (s *State) GetOrMakeAccounts(ins []*blk.TxInput, outs []*blk.TxOutput) (map
return nil, blk.ErrTxInvalidAddress return nil, blk.ErrTxInvalidAddress
} }
// PubKey should be present in either "account" or "in" // PubKey should be present in either "account" or "in"
if _, isNil := acc.PubKey.(account.PubKeyNil); isNil {
if _, isNil := in.PubKey.(account.PubKeyNil); isNil {
return nil, blk.ErrTxUnknownPubKey
}
if !bytes.Equal(in.PubKey.Address(), acc.Address) {
return nil, blk.ErrTxInvalidPubKey
}
acc.PubKey = in.PubKey
} else {
in.PubKey = account.PubKeyNil{}
if err := checkInputPubKey(acc, in); err != nil {
return nil, err
} }
accounts[string(in.Address)] = acc accounts[string(in.Address)] = acc
} }
@ -161,6 +153,21 @@ func (s *State) GetOrMakeAccounts(ins []*blk.TxInput, outs []*blk.TxOutput) (map
return accounts, nil return accounts, nil
} }
func checkInputPubKey(acc *account.Account, in *blk.TxInput) error {
if _, isNil := acc.PubKey.(account.PubKeyNil); isNil {
if _, isNil := in.PubKey.(account.PubKeyNil); isNil {
return blk.ErrTxUnknownPubKey
}
if !bytes.Equal(in.PubKey.Address(), acc.Address) {
return blk.ErrTxInvalidPubKey
}
acc.PubKey = in.PubKey
} else {
in.PubKey = account.PubKeyNil{}
}
return nil
}
func (s *State) ValidateInputs(accounts map[string]*account.Account, signBytes []byte, ins []*blk.TxInput) (total uint64, err error) { func (s *State) ValidateInputs(accounts map[string]*account.Account, signBytes []byte, ins []*blk.TxInput) (total uint64, err error) {
for _, in := range ins { for _, in := range ins {
acc := accounts[string(in.Address)] acc := accounts[string(in.Address)]
@ -261,6 +268,46 @@ func (s *State) ExecTx(tx_ blk.Tx) error {
s.UpdateAccounts(accounts) s.UpdateAccounts(accounts)
return nil return nil
case *blk.CallTx:
tx := tx_.(*blk.CallTx)
accounts := map[string]*account.Account{}
inAcc := s.GetAccount(tx.Input.Address)
if inAcc == nil {
return blk.ErrTxInvalidAddress
}
// PubKey should be present in either "inAcc" or "tx.Input"
if err := checkInputPubKey(inAcc, tx.Input); err != nil {
return err
}
accounts[string(tx.Input.Address)] = inAcc
signBytes := account.SignBytes(tx)
inTotal, err := s.ValidateInputs(accounts, signBytes, []*blk.TxInput{tx.Input})
if err != nil {
return err
}
// validate output address
if len(tx.Address) != 20 {
return blk.ErrTxInvalidAddress
}
outAcc := s.GetAccount(tx.Address)
if outAcc == nil {
return blk.ErrTxInvalidAddress
}
accounts[string(tx.Address)] = outAcc
// TODO: fees
// inTotal -= fees
// Good! Adjust accounts
s.AdjustByInputs(accounts, []*blk.TxInput{tx.Input})
outAcc.Balance += inTotal
s.UpdateAccounts(accounts)
// TODO: Run the contract call!
return nil
case *blk.BondTx: case *blk.BondTx:
tx := tx_.(*blk.BondTx) tx := tx_.(*blk.BondTx)
valInfo := s.GetValidatorInfo(tx.PubKey.Address()) valInfo := s.GetValidatorInfo(tx.PubKey.Address())


Loading…
Cancel
Save