You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

177 lines
4.3 KiB

package state
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"github.com/tendermint/go-ed25519"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/blocks"
. "github.com/tendermint/tendermint/common"
)
const (
AccountStatusNominal = byte(0x00)
AccountStatusBonded = byte(0x01)
AccountStatusUnbonding = byte(0x02)
AccountStatusDupedOut = byte(0x03)
)
type Account struct {
Id uint64 // Numeric id of account, incrementing.
PubKey []byte
}
func ReadAccount(r io.Reader, n *int64, err *error) Account {
return Account{
Id: ReadUInt64(r, n, err),
PubKey: ReadByteSlice(r, n, err),
}
}
func (account Account) WriteTo(w io.Writer) (n int64, err error) {
WriteUInt64(w, account.Id, &n, &err)
WriteByteSlice(w, account.PubKey, &n, &err)
return
}
func (account Account) VerifyBytes(msg []byte, sig Signature) bool {
if sig.SignerId != account.Id {
panic("account.id doesn't match sig.signerid")
}
if len(sig.Bytes) == 0 {
panic("signature is empty")
}
v1 := &ed25519.Verify{
Message: msg,
PubKey: account.PubKey,
Signature: sig.Bytes,
}
ok := ed25519.VerifyBatch([]*ed25519.Verify{v1})
return ok
}
func (account Account) Verify(o Signable) bool {
sig := o.GetSignature()
o.SetSignature(Signature{}) // clear
msg := BinaryBytes(o)
o.SetSignature(sig) // restore
return account.VerifyBytes(msg, sig)
}
func (account Account) String() string {
return fmt.Sprintf("Account{%v:%X}", account.Id, account.PubKey[:6])
}
//-----------------------------------------------------------------------------
type AccountDetail struct {
Account
Sequence uint
Balance uint64
Status byte
}
func ReadAccountDetail(r io.Reader, n *int64, err *error) *AccountDetail {
return &AccountDetail{
Account: ReadAccount(r, n, err),
Sequence: ReadUVarInt(r, n, err),
Balance: ReadUInt64(r, n, err),
Status: ReadByte(r, n, err),
}
}
func (accDet *AccountDetail) WriteTo(w io.Writer) (n int64, err error) {
WriteBinary(w, accDet.Account, &n, &err)
WriteUVarInt(w, accDet.Sequence, &n, &err)
WriteUInt64(w, accDet.Balance, &n, &err)
WriteByte(w, accDet.Status, &n, &err)
return
}
func (accDet *AccountDetail) String() string {
return fmt.Sprintf("AccountDetail{%v:%X Sequence:%v Balance:%v Status:%X}",
accDet.Id, accDet.PubKey, accDet.Sequence, accDet.Balance, accDet.Status)
}
func (accDet *AccountDetail) Copy() *AccountDetail {
accDetCopy := *accDet
return &accDetCopy
}
//-------------------------------------
var AccountDetailCodec = accountDetailCodec{}
type accountDetailCodec struct{}
func (abc accountDetailCodec) Encode(accDet interface{}, w io.Writer, n *int64, err *error) {
WriteBinary(w, accDet.(*AccountDetail), n, err)
}
func (abc accountDetailCodec) Decode(r io.Reader, n *int64, err *error) interface{} {
return ReadAccountDetail(r, n, err)
}
func (abc accountDetailCodec) Compare(o1 interface{}, o2 interface{}) int {
panic("AccountDetailCodec.Compare not implemented")
}
//-----------------------------------------------------------------------------
type PrivAccount struct {
Account
PrivKey []byte
}
// Generates a new account with private key.
// The Account.Id is empty since it isn't in the blockchain.
func GenPrivAccount() *PrivAccount {
privKey := CRandBytes(32)
pubKey := ed25519.MakePubKey(privKey)
return &PrivAccount{
Account: Account{
Id: uint64(0),
PubKey: pubKey,
},
PrivKey: privKey,
}
}
// The Account.Id is empty since it isn't in the blockchain.
func PrivAccountFromJSON(jsonBlob []byte) (privAccount *PrivAccount) {
err := json.Unmarshal(jsonBlob, &privAccount)
if err != nil {
Panicf("Couldn't read PrivAccount: %v", err)
}
return
}
// The Account.Id is empty since it isn't in the blockchain.
func PrivAccountFromFile(file string) *PrivAccount {
jsonBlob, err := ioutil.ReadFile(file)
if err != nil {
Panicf("Couldn't read PrivAccount from file: %v", err)
}
return PrivAccountFromJSON(jsonBlob)
}
func (pa *PrivAccount) SignBytes(msg []byte) Signature {
signature := ed25519.SignMessage(msg, pa.PrivKey, pa.PubKey)
sig := Signature{
SignerId: pa.Id,
Bytes: signature,
}
return sig
}
func (pa *PrivAccount) Sign(o Signable) {
if !o.GetSignature().IsZero() {
panic("Cannot sign: already signed")
}
msg := BinaryBytes(o)
sig := pa.SignBytes(msg)
o.SetSignature(sig)
}