Refactoring genesis, including PubKey into TxInput

This commit is contained in:
Jae Kwon
2014-12-28 00:44:56 -08:00
parent 70eb75dca7
commit f91665fe07
17 changed files with 308 additions and 178 deletions
+64 -14
View File
@@ -1,6 +1,8 @@
package state
import (
"bytes"
"encoding/base64"
"encoding/json"
"io/ioutil"
"time"
@@ -13,10 +15,21 @@ import (
"github.com/tendermint/tendermint/merkle"
)
type GenesisAccount struct {
Address string
Amount uint64
}
type GenesisValidator struct {
PubKey string
Amount uint64
UnbondTo []GenesisAccount
}
type GenesisDoc struct {
GenesisTime time.Time
Accounts []*Account
Validators []*ValidatorInfo
Accounts []GenesisAccount
Validators []GenesisValidator
}
func GenesisDocFromJSON(jsonBlob []byte) (genState *GenesisDoc) {
@@ -38,7 +51,7 @@ func MakeGenesisStateFromFile(db db_.DB, genDocFile string) *State {
func MakeGenesisState(db db_.DB, genDoc *GenesisDoc) *State {
if len(genDoc.Validators) == 0 {
panic("Must have some validators")
Exitf("The genesis file has no validators")
}
if genDoc.GenesisTime.IsZero() {
@@ -48,22 +61,59 @@ func MakeGenesisState(db db_.DB, genDoc *GenesisDoc) *State {
// Make accounts state tree
accounts := merkle.NewIAVLTree(BasicCodec, AccountCodec, defaultAccountsCacheCapacity, db)
for _, acc := range genDoc.Accounts {
accounts.Set(acc.Address, acc)
address, err := base64.StdEncoding.DecodeString(acc.Address)
if err != nil {
Exitf("Invalid account address: %v", acc.Address)
}
account := &Account{
Address: address,
PubKey: PubKeyNil{},
Sequence: 0,
Balance: acc.Amount,
}
accounts.Set(address, account)
}
// Make validatorInfos state tree
// Make validatorInfos state tree && validators slice
validatorInfos := merkle.NewIAVLTree(BasicCodec, ValidatorInfoCodec, 0, db)
for _, valInfo := range genDoc.Validators {
validatorInfos.Set(valInfo.Address, valInfo)
}
// Make validators
validators := make([]*Validator, len(genDoc.Validators))
for i, valInfo := range genDoc.Validators {
for i, val := range genDoc.Validators {
pubKeyBytes, err := base64.StdEncoding.DecodeString(val.PubKey)
if err != nil {
Exitf("Invalid validator pubkey: %v", val.PubKey)
}
pubKey := ReadBinary(PubKeyEd25519{},
bytes.NewBuffer(pubKeyBytes), new(int64), &err).(PubKeyEd25519)
if err != nil {
Exitf("Invalid validator pubkey: %v", val.PubKey)
}
address := pubKey.Address()
// Make ValidatorInfo
valInfo := &ValidatorInfo{
Address: address,
PubKey: pubKey,
UnbondTo: make([]*TxOutput, len(val.UnbondTo)),
FirstBondHeight: 0,
FirstBondAmount: val.Amount,
}
for i, unbondTo := range val.UnbondTo {
address, err := base64.StdEncoding.DecodeString(unbondTo.Address)
if err != nil {
Exitf("Invalid unbond-to address: %v", unbondTo.Address)
}
valInfo.UnbondTo[i] = &TxOutput{
Address: address,
Amount: unbondTo.Amount,
}
}
validatorInfos.Set(address, valInfo)
// Make validator
validators[i] = &Validator{
Address: valInfo.Address,
PubKey: valInfo.PubKey,
VotingPower: valInfo.FirstBondAmount,
Address: address,
PubKey: pubKey,
VotingPower: val.Amount,
}
}
+10 -5
View File
@@ -126,6 +126,14 @@ func (privVal *PrivValidator) Save() {
}
func (privVal *PrivValidator) save() {
jsonBytes := privVal.JSONBytes()
err := ioutil.WriteFile(privVal.filename, jsonBytes, 0700)
if err != nil {
panic(err)
}
}
func (privVal *PrivValidator) JSONBytes() []byte {
privValJSON := PrivValidatorJSON{
Address: base64.StdEncoding.EncodeToString(privVal.Address),
PubKey: base64.StdEncoding.EncodeToString(BinaryBytes(privVal.PubKey)),
@@ -134,14 +142,11 @@ func (privVal *PrivValidator) save() {
LastRound: privVal.LastRound,
LastStep: privVal.LastStep,
}
privValJSONBytes, err := json.Marshal(privValJSON)
if err != nil {
panic(err)
}
err = ioutil.WriteFile(privVal.filename, privValJSONBytes, 0700)
privValJSONBytes, err := json.MarshalIndent(privValJSON, "", " ")
if err != nil {
panic(err)
}
return privValJSONBytes
}
// TODO: test
+23 -1
View File
@@ -108,6 +108,9 @@ func (s *State) Copy() *State {
}
}
// The accounts from the TxInputs must either already have
// account.PubKey.(type) != PubKeyNil, (it must be known),
// or it must be specified in the TxInput. But not both.
func (s *State) GetOrMakeAccounts(ins []*TxInput, outs []*TxOutput) (map[string]*Account, error) {
accounts := map[string]*Account{}
for _, in := range ins {
@@ -119,6 +122,20 @@ func (s *State) GetOrMakeAccounts(ins []*TxInput, outs []*TxOutput) (map[string]
if account == nil {
return nil, ErrTxInvalidAddress
}
// PubKey should be present in either "account" or "in"
if _, isNil := account.PubKey.(PubKeyNil); isNil {
if _, isNil := in.PubKey.(PubKeyNil); isNil {
return nil, ErrTxUnknownPubKey
}
if !bytes.Equal(in.PubKey.Address(), account.Address) {
return nil, ErrTxInvalidPubKey
}
account.PubKey = in.PubKey
} else {
if _, isNil := in.PubKey.(PubKeyNil); !isNil {
return nil, ErrTxRedeclaredPubKey
}
}
accounts[string(in.Address)] = account
}
for _, out := range outs {
@@ -129,7 +146,12 @@ func (s *State) GetOrMakeAccounts(ins []*TxInput, outs []*TxOutput) (map[string]
account := s.GetAccount(out.Address)
// output account may be nil (new)
if account == nil {
account = NewAccount(NewPubKeyUnknown(out.Address))
account = &Account{
Address: out.Address,
PubKey: PubKeyNil{},
Sequence: 0,
Balance: 0,
}
}
accounts[string(out.Address)] = account
}
+25 -8
View File
@@ -2,9 +2,11 @@ package state
import (
"bytes"
"encoding/base64"
"sort"
. "github.com/tendermint/tendermint/account"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/block"
. "github.com/tendermint/tendermint/common"
db_ "github.com/tendermint/tendermint/db"
@@ -24,9 +26,12 @@ func Tempfile(prefix string) (*os.File, string) {
func RandAccount(randBalance bool, minBalance uint64) (*Account, *PrivAccount) {
privAccount := GenPrivAccount()
account := NewAccount(privAccount.PubKey)
account.Sequence = RandUint()
account.Balance = minBalance
account := &Account{
Address: privAccount.PubKey.Address(),
PubKey: privAccount.PubKey,
Sequence: RandUint(),
Balance: minBalance,
}
if randBalance {
account.Balance += uint64(RandUint32())
}
@@ -53,20 +58,32 @@ func RandValidator(randBonded bool, minBonded uint64) (*ValidatorInfo, *PrivVali
return valInfo, privVal
}
// The first numValidators accounts are validators.
func RandGenesisState(numAccounts int, randBalance bool, minBalance uint64, numValidators int, randBonded bool, minBonded uint64) (*State, []*PrivAccount, []*PrivValidator) {
db := db_.NewMemDB()
accounts := make([]*Account, numAccounts)
accounts := make([]GenesisAccount, numAccounts)
privAccounts := make([]*PrivAccount, numAccounts)
for i := 0; i < numAccounts; i++ {
account, privAccount := RandAccount(randBalance, minBalance)
accounts[i], privAccounts[i] = account, privAccount
accounts[i] = GenesisAccount{
Address: base64.StdEncoding.EncodeToString(account.Address),
Amount: account.Balance,
}
privAccounts[i] = privAccount
}
validators := make([]*ValidatorInfo, numValidators)
validators := make([]GenesisValidator, numValidators)
privValidators := make([]*PrivValidator, numValidators)
for i := 0; i < numValidators; i++ {
valInfo, privVal := RandValidator(randBonded, minBonded)
validators[i] = valInfo
validators[i] = GenesisValidator{
PubKey: base64.StdEncoding.EncodeToString(BinaryBytes(valInfo.PubKey)),
Amount: valInfo.FirstBondAmount,
UnbondTo: []GenesisAccount{
{
Address: base64.StdEncoding.EncodeToString(valInfo.PubKey.Address()),
Amount: valInfo.FirstBondAmount,
},
},
}
privValidators[i] = privVal
}
sort.Sort(PrivValidatorsByAddress(privValidators))