mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-18 15:41:20 +00:00
implementing ExecTx...
This commit is contained in:
@ -9,8 +9,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
AccountBalanceStatusNominal = byte(0x00)
|
||||
AccountBalanceStatusBonded = byte(0x01)
|
||||
AccountDetailStatusNominal = byte(0x00)
|
||||
AccountDetailStatusBonded = byte(0x01)
|
||||
AccountDetailStatusUnbonding = byte(0x02)
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
@ -31,7 +32,7 @@ func (account Account) WriteTo(w io.Writer) (n int64, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (account Account) Verify(msg []byte, sig Signature) bool {
|
||||
func (account Account) VerifyBytes(msg []byte, sig Signature) bool {
|
||||
if sig.SignerId != account.Id {
|
||||
panic("account.id doesn't match sig.signerid")
|
||||
}
|
||||
@ -44,32 +45,37 @@ func (account Account) Verify(msg []byte, sig Signature) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func (account Account) VerifySignable(o Signable) bool {
|
||||
msg := o.GenDocument()
|
||||
func (account Account) Verify(o Signable) bool {
|
||||
sig := o.GetSignature()
|
||||
return account.Verify(msg, sig)
|
||||
o.SetSignature(Signature{}) // clear
|
||||
msg := BinaryBytes(o)
|
||||
o.SetSignature(sig) // restore
|
||||
return account.VerifyBytes(msg, sig)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
type AccountBalance struct {
|
||||
type AccountDetail struct {
|
||||
Account
|
||||
Balance uint64
|
||||
Status byte
|
||||
Sequence uint64
|
||||
Balance uint64
|
||||
Status byte
|
||||
}
|
||||
|
||||
func ReadAccountBalance(r io.Reader, n *int64, err *error) *AccountBalance {
|
||||
return &AccountBalance{
|
||||
Account: ReadAccount(r, n, err),
|
||||
Balance: ReadUInt64(r, n, err),
|
||||
Status: ReadByte(r, n, err),
|
||||
func ReadAccountDetail(r io.Reader, n *int64, err *error) *AccountDetail {
|
||||
return &AccountDetail{
|
||||
Account: ReadAccount(r, n, err),
|
||||
Sequence: ReadUInt64(r, n, err),
|
||||
Balance: ReadUInt64(r, n, err),
|
||||
Status: ReadByte(r, n, err),
|
||||
}
|
||||
}
|
||||
|
||||
func (accBal AccountBalance) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteBinary(w, accBal.Account, &n, &err)
|
||||
WriteUInt64(w, accBal.Balance, &n, &err)
|
||||
WriteByte(w, accBal.Status, &n, &err)
|
||||
func (accDet AccountDetail) WriteTo(w io.Writer) (n int64, err error) {
|
||||
WriteBinary(w, accDet.Account, &n, &err)
|
||||
WriteUInt64(w, accDet.Sequence, &n, &err)
|
||||
WriteUInt64(w, accDet.Balance, &n, &err)
|
||||
WriteByte(w, accDet.Status, &n, &err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -94,7 +100,7 @@ func GenPrivAccount() *PrivAccount {
|
||||
}
|
||||
}
|
||||
|
||||
func (pa *PrivAccount) Sign(msg []byte) Signature {
|
||||
func (pa *PrivAccount) SignBytes(msg []byte) Signature {
|
||||
signature := crypto.SignMessage(msg, pa.PrivKey, pa.PubKey)
|
||||
sig := Signature{
|
||||
SignerId: pa.Id,
|
||||
@ -103,8 +109,9 @@ func (pa *PrivAccount) Sign(msg []byte) Signature {
|
||||
return sig
|
||||
}
|
||||
|
||||
func (pa *PrivAccount) SignSignable(o Signable) {
|
||||
msg := o.GenDocument()
|
||||
sig := pa.Sign(msg)
|
||||
func (pa *PrivAccount) Sign(o Signable) {
|
||||
o.SetSignature(Signature{}) // clear
|
||||
msg := BinaryBytes(o)
|
||||
sig := pa.SignBytes(msg)
|
||||
o.SetSignature(sig)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ func TestSignAndValidate(t *testing.T) {
|
||||
account := &privAccount.Account
|
||||
|
||||
msg := CRandBytes(128)
|
||||
sig := privAccount.Sign(msg)
|
||||
sig := privAccount.SignBytes(msg)
|
||||
t.Logf("msg: %X, sig: %X", msg, sig)
|
||||
|
||||
// Test the signature
|
||||
|
156
state/state.go
156
state/state.go
@ -12,62 +12,67 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrStateInvalidAccountId = errors.New("Error State invalid account id")
|
||||
ErrStateInvalidSignature = errors.New("Error State invalid signature")
|
||||
ErrStateInvalidSequenceNumber = errors.New("Error State invalid sequence number")
|
||||
ErrStateInvalidAccountState = errors.New("Error State invalid account state")
|
||||
ErrStateInvalidValidationStateHash = errors.New("Error State invalid ValidationStateHash")
|
||||
ErrStateInvalidAccountStateHash = errors.New("Error State invalid AccountStateHash")
|
||||
ErrStateInsufficientFunds = errors.New("Error State insufficient funds")
|
||||
|
||||
stateKey = []byte("stateKey")
|
||||
stateKey = []byte("stateKey")
|
||||
minBondAmount = uint64(1) // TODO adjust
|
||||
)
|
||||
|
||||
type accountBalanceCodec struct{}
|
||||
type accountDetailCodec struct{}
|
||||
|
||||
func (abc accountBalanceCodec) Write(accBal interface{}) (accBalBytes []byte, err error) {
|
||||
func (abc accountDetailCodec) Write(accDet interface{}) (accDetBytes []byte, err error) {
|
||||
w := new(bytes.Buffer)
|
||||
_, err = accBal.(*AccountBalance).WriteTo(w)
|
||||
_, err = accDet.(*AccountDetail).WriteTo(w)
|
||||
return w.Bytes(), err
|
||||
}
|
||||
|
||||
func (abc accountBalanceCodec) Read(accBalBytes []byte) (interface{}, error) {
|
||||
n, err, r := new(int64), new(error), bytes.NewBuffer(accBalBytes)
|
||||
return ReadAccountBalance(r, n, err), *err
|
||||
func (abc accountDetailCodec) Read(accDetBytes []byte) (interface{}, error) {
|
||||
n, err, r := new(int64), new(error), bytes.NewBuffer(accDetBytes)
|
||||
return ReadAccountDetail(r, n, err), *err
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// NOTE: not goroutine-safe.
|
||||
type State struct {
|
||||
DB DB
|
||||
Height uint32 // Last known block height
|
||||
BlockHash []byte // Last known block hash
|
||||
CommitTime time.Time
|
||||
AccountBalances *merkle.TypedTree
|
||||
Validators *ValidatorSet
|
||||
DB DB
|
||||
Height uint32 // Last known block height
|
||||
BlockHash []byte // Last known block hash
|
||||
CommitTime time.Time
|
||||
AccountDetails *merkle.TypedTree
|
||||
Validators *ValidatorSet
|
||||
}
|
||||
|
||||
func GenesisState(db DB, genesisTime time.Time, accBals []*AccountBalance) *State {
|
||||
func GenesisState(db DB, genesisTime time.Time, accDets []*AccountDetail) *State {
|
||||
|
||||
// TODO: Use "uint64Codec" instead of BasicCodec
|
||||
accountBalances := merkle.NewTypedTree(merkle.NewIAVLTree(db), BasicCodec, accountBalanceCodec{})
|
||||
accountDetails := merkle.NewTypedTree(merkle.NewIAVLTree(db), BasicCodec, accountDetailCodec{})
|
||||
validators := map[uint64]*Validator{}
|
||||
|
||||
for _, accBal := range accBals {
|
||||
accountBalances.Set(accBal.Id, accBal)
|
||||
validators[accBal.Id] = &Validator{
|
||||
Account: accBal.Account,
|
||||
for _, accDet := range accDets {
|
||||
accountDetails.Set(accDet.Id, accDet)
|
||||
validators[accDet.Id] = &Validator{
|
||||
Account: accDet.Account,
|
||||
BondHeight: 0,
|
||||
VotingPower: accBal.Balance,
|
||||
VotingPower: accDet.Balance,
|
||||
Accum: 0,
|
||||
}
|
||||
}
|
||||
validatorSet := NewValidatorSet(validators)
|
||||
|
||||
return &State{
|
||||
DB: db,
|
||||
Height: 0,
|
||||
BlockHash: nil,
|
||||
CommitTime: genesisTime,
|
||||
AccountBalances: accountBalances,
|
||||
Validators: validatorSet,
|
||||
DB: db,
|
||||
Height: 0,
|
||||
BlockHash: nil,
|
||||
CommitTime: genesisTime,
|
||||
AccountDetails: accountDetails,
|
||||
Validators: validatorSet,
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,8 +88,8 @@ func LoadState(db DB) *State {
|
||||
s.Height = ReadUInt32(reader, &n, &err)
|
||||
s.CommitTime = ReadTime(reader, &n, &err)
|
||||
s.BlockHash = ReadByteSlice(reader, &n, &err)
|
||||
accountBalancesHash := ReadByteSlice(reader, &n, &err)
|
||||
s.AccountBalances = merkle.NewTypedTree(merkle.LoadIAVLTreeFromHash(db, accountBalancesHash), BasicCodec, accountBalanceCodec{})
|
||||
accountDetailsHash := ReadByteSlice(reader, &n, &err)
|
||||
s.AccountDetails = merkle.NewTypedTree(merkle.LoadIAVLTreeFromHash(db, accountDetailsHash), BasicCodec, accountDetailCodec{})
|
||||
var validators = map[uint64]*Validator{}
|
||||
for reader.Len() > 0 {
|
||||
validator := ReadValidator(reader, &n, &err)
|
||||
@ -103,14 +108,14 @@ func LoadState(db DB) *State {
|
||||
// is saved here.
|
||||
func (s *State) Save(commitTime time.Time) {
|
||||
s.CommitTime = commitTime
|
||||
s.AccountBalances.Tree.Save()
|
||||
s.AccountDetails.Tree.Save()
|
||||
var buf bytes.Buffer
|
||||
var n int64
|
||||
var err error
|
||||
WriteUInt32(&buf, s.Height, &n, &err)
|
||||
WriteTime(&buf, commitTime, &n, &err)
|
||||
WriteByteSlice(&buf, s.BlockHash, &n, &err)
|
||||
WriteByteSlice(&buf, s.AccountBalances.Tree.Hash(), &n, &err)
|
||||
WriteByteSlice(&buf, s.AccountDetails.Tree.Hash(), &n, &err)
|
||||
for _, validator := range s.Validators.Map() {
|
||||
WriteBinary(&buf, validator, &n, &err)
|
||||
}
|
||||
@ -122,26 +127,76 @@ func (s *State) Save(commitTime time.Time) {
|
||||
|
||||
func (s *State) Copy() *State {
|
||||
return &State{
|
||||
DB: s.DB,
|
||||
Height: s.Height,
|
||||
CommitTime: s.CommitTime,
|
||||
BlockHash: s.BlockHash,
|
||||
AccountBalances: s.AccountBalances.Copy(),
|
||||
Validators: s.Validators.Copy(),
|
||||
DB: s.DB,
|
||||
Height: s.Height,
|
||||
CommitTime: s.CommitTime,
|
||||
BlockHash: s.BlockHash,
|
||||
AccountDetails: s.AccountDetails.Copy(),
|
||||
Validators: s.Validators.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// If the tx is invalid, an error will be returned.
|
||||
// Unlike AppendBlock(), state will not be altered.
|
||||
func (s *State) ExecTx(tx Tx) error {
|
||||
/*
|
||||
// Get the signer's incr
|
||||
signerId := tx.Signature().SignerId
|
||||
if mem.state.AccountSequence(signerId) != tx.Sequence() {
|
||||
return ErrStateInvalidSequenceNumber
|
||||
accDet := s.GetAccountDetail(tx.GetSignature().SignerId)
|
||||
if accDet == nil {
|
||||
return ErrStateInvalidAccountId
|
||||
}
|
||||
// Check signature
|
||||
if !accDet.Verify(tx) {
|
||||
return ErrStateInvalidSignature
|
||||
}
|
||||
// Check sequence
|
||||
if tx.GetSequence() <= accDet.Sequence {
|
||||
return ErrStateInvalidSequenceNumber
|
||||
}
|
||||
// Exec tx
|
||||
switch tx.(type) {
|
||||
case *SendTx:
|
||||
stx := tx.(*SendTx)
|
||||
toAccDet := s.GetAccountDetail(stx.To)
|
||||
// Accounts must be nominal
|
||||
if accDet.Status != AccountDetailStatusNominal {
|
||||
return ErrStateInvalidAccountState
|
||||
}
|
||||
*/
|
||||
// XXX commit the tx
|
||||
if toAccDet.Status != AccountDetailStatusNominal {
|
||||
return ErrStateInvalidAccountState
|
||||
}
|
||||
// Check account balance
|
||||
if accDet.Balance < stx.Fee+stx.Amount {
|
||||
return ErrStateInsufficientFunds
|
||||
}
|
||||
// Check existence of destination account
|
||||
if toAccDet == nil {
|
||||
return ErrStateInvalidAccountId
|
||||
}
|
||||
// Good!
|
||||
accDet.Balance -= (stx.Fee + stx.Amount)
|
||||
toAccDet.Balance += (stx.Amount)
|
||||
s.SetAccountDetail(accDet)
|
||||
s.SetAccountDetail(toAccDet)
|
||||
//case *NameTx
|
||||
case *BondTx:
|
||||
btx := tx.(*BondTx)
|
||||
// Account must be nominal
|
||||
if accDet.Status != AccountDetailStatusNominal {
|
||||
return ErrStateInvalidAccountState
|
||||
}
|
||||
// Check account balance
|
||||
if accDet.Balance < minBondAmount {
|
||||
return ErrStateInsufficientFunds
|
||||
}
|
||||
// TODO: max number of validators?
|
||||
// Good!
|
||||
accDet.Balance -= btx.Fee // remaining balance are bonded coins.
|
||||
accDet.Status = AccountDetailStatusBonded
|
||||
s.SetAccountDetail(accDet)
|
||||
// XXX add validator
|
||||
case *UnbondTx:
|
||||
case *TimeoutTx:
|
||||
case *DupeoutTx:
|
||||
}
|
||||
panic("Implement ExecTx()")
|
||||
return nil
|
||||
}
|
||||
@ -170,7 +225,7 @@ func (s *State) AppendBlock(b *Block) error {
|
||||
if !bytes.Equal(s.Validators.Hash(), b.ValidationStateHash) {
|
||||
return ErrStateInvalidValidationStateHash
|
||||
}
|
||||
if !bytes.Equal(s.AccountBalances.Tree.Hash(), b.AccountStateHash) {
|
||||
if !bytes.Equal(s.AccountDetails.Tree.Hash(), b.AccountStateHash) {
|
||||
return ErrStateInvalidAccountStateHash
|
||||
}
|
||||
|
||||
@ -179,10 +234,15 @@ func (s *State) AppendBlock(b *Block) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *State) AccountBalance(accountId uint64) *AccountBalance {
|
||||
accBal := s.AccountBalances.Get(accountId)
|
||||
if accBal == nil {
|
||||
func (s *State) GetAccountDetail(accountId uint64) *AccountDetail {
|
||||
accDet := s.AccountDetails.Get(accountId)
|
||||
if accDet == nil {
|
||||
return nil
|
||||
}
|
||||
return accBal.(*AccountBalance)
|
||||
return accDet.(*AccountDetail)
|
||||
}
|
||||
|
||||
// Returns false if new, true if updated.
|
||||
func (s *State) SetAccountDetail(accDet *AccountDetail) (updated bool) {
|
||||
return s.AccountDetails.Set(accDet.Id, accDet)
|
||||
}
|
||||
|
Reference in New Issue
Block a user