package block import ( "errors" "io" "reflect" . "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/binary" . "github.com/tendermint/tendermint/common" ) var ( ErrTxInvalidAddress = errors.New("Error invalid address") ErrTxDuplicateAddress = errors.New("Error duplicate address") ErrTxInvalidAmount = errors.New("Error invalid amount") ErrTxInsufficientFunds = errors.New("Error insufficient funds") ErrTxUnknownPubKey = errors.New("Error unknown pubkey") ErrTxInvalidPubKey = errors.New("Error invalid pubkey") ErrTxRedeclaredPubKey = errors.New("Error redeclared pubkey") ErrTxInvalidSignature = errors.New("Error invalid signature") ErrTxInvalidSequence = errors.New("Error invalid sequence") ) /* Tx (Transaction) is an atomic operation on the ledger state. Account Txs: - SendTx Send coins to address Validation Txs: - BondTx New validator posts a bond - UnbondTx Validator leaves - DupeoutTx Validator dupes out (equivocates) */ type Tx interface { WriteSignBytes(w io.Writer, n *int64, err *error) } // Types of Tx implementations const ( // Account transactions TxTypeSend = byte(0x01) // Validation transactions TxTypeBond = byte(0x11) TxTypeUnbond = byte(0x12) TxTypeRebond = byte(0x13) TxTypeDupeout = byte(0x14) ) //------------------------------------- // for binary.readReflect func TxDecoder(r Unreader, n *int64, err *error) interface{} { switch t := PeekByte(r, n, err); t { case TxTypeSend: return ReadBinary(&SendTx{}, r, n, err) case TxTypeBond: return ReadBinary(&BondTx{}, r, n, err) case TxTypeUnbond: return ReadBinary(&UnbondTx{}, r, n, err) case TxTypeRebond: return ReadBinary(&RebondTx{}, r, n, err) case TxTypeDupeout: return ReadBinary(&DupeoutTx{}, r, n, err) default: *err = Errorf("Unknown Tx type %X", t) return nil } } var _ = RegisterType(&TypeInfo{ Type: reflect.TypeOf((*Tx)(nil)).Elem(), Decoder: TxDecoder, }) //----------------------------------------------------------------------------- type TxInput struct { Address []byte // Hash of the PubKey Amount uint64 // Must not exceed account balance Sequence uint // Must be 1 greater than the last committed TxInput Signature Signature // Depends on the PubKey type and the whole Tx PubKey PubKey // Must not be nil, may be PubKeyNil. } func (txIn *TxInput) ValidateBasic() error { if len(txIn.Address) != 20 { return ErrTxInvalidAddress } if txIn.Amount == 0 { return ErrTxInvalidAmount } return nil } func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int64, err *error) { WriteByteSlice(txIn.Address, w, n, err) WriteUint64(txIn.Amount, w, n, err) WriteUvarint(txIn.Sequence, w, n, err) } //----------------------------------------------------------------------------- type TxOutput struct { Address []byte // Hash of the PubKey Amount uint64 // The sum of all outputs must not exceed the inputs. } func (txOut *TxOutput) ValidateBasic() error { if len(txOut.Address) != 20 { return ErrTxInvalidAddress } if txOut.Amount == 0 { return ErrTxInvalidAmount } return nil } func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int64, err *error) { WriteByteSlice(txOut.Address, w, n, err) WriteUint64(txOut.Amount, w, n, err) } //----------------------------------------------------------------------------- type SendTx struct { Inputs []*TxInput Outputs []*TxOutput } func (tx *SendTx) TypeByte() byte { return TxTypeSend } func (tx *SendTx) WriteSignBytes(w io.Writer, n *int64, err *error) { WriteUvarint(uint(len(tx.Inputs)), w, n, err) for _, in := range tx.Inputs { in.WriteSignBytes(w, n, err) } WriteUvarint(uint(len(tx.Outputs)), w, n, err) for _, out := range tx.Outputs { out.WriteSignBytes(w, n, err) } } //----------------------------------------------------------------------------- type BondTx struct { PubKey PubKeyEd25519 Inputs []*TxInput UnbondTo []*TxOutput } func (tx *BondTx) TypeByte() byte { return TxTypeBond } func (tx *BondTx) WriteSignBytes(w io.Writer, n *int64, err *error) { WriteBinary(tx.PubKey, w, n, err) WriteUvarint(uint(len(tx.Inputs)), w, n, err) for _, in := range tx.Inputs { in.WriteSignBytes(w, n, err) } WriteUvarint(uint(len(tx.UnbondTo)), w, n, err) for _, out := range tx.UnbondTo { out.WriteSignBytes(w, n, err) } } //----------------------------------------------------------------------------- type UnbondTx struct { Address []byte Height uint Signature SignatureEd25519 } func (tx *UnbondTx) TypeByte() byte { return TxTypeUnbond } func (tx *UnbondTx) WriteSignBytes(w io.Writer, n *int64, err *error) { WriteByteSlice(tx.Address, w, n, err) WriteUvarint(tx.Height, w, n, err) } //----------------------------------------------------------------------------- type RebondTx struct { Address []byte Height uint Signature SignatureEd25519 } func (tx *RebondTx) TypeByte() byte { return TxTypeRebond } func (tx *RebondTx) WriteSignBytes(w io.Writer, n *int64, err *error) { WriteByteSlice(tx.Address, w, n, err) WriteUvarint(tx.Height, w, n, err) } //----------------------------------------------------------------------------- type DupeoutTx struct { Address []byte VoteA Vote VoteB Vote } func (tx *DupeoutTx) TypeByte() byte { return TxTypeDupeout } func (tx *DupeoutTx) WriteSignBytes(w io.Writer, n *int64, err *error) { panic("DupeoutTx has no sign bytes") }