package types import ( "fmt" acm "github.com/tendermint/tendermint/account" ptypes "github.com/tendermint/tendermint/permission/types" ) type AccountGetter interface { GetAccount(addr []byte) *acm.Account } //---------------------------------------------------------------------------- // SendTx interface for adding inputs/outputs and adding signatures func NewSendTx() *SendTx { return &SendTx{ Inputs: []*TxInput{}, Outputs: []*TxOutput{}, } } func (tx *SendTx) AddInput(st AccountGetter, pubkey acm.PubKey, amt int64) error { addr := pubkey.Address() acc := st.GetAccount(addr) if acc == nil { return fmt.Errorf("Invalid address %X from pubkey %X", addr, pubkey) } return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1) } func (tx *SendTx) AddInputWithNonce(pubkey acm.PubKey, amt int64, nonce int) error { addr := pubkey.Address() tx.Inputs = append(tx.Inputs, &TxInput{ Address: addr, Amount: amt, Sequence: nonce, Signature: acm.SignatureEd25519{}, PubKey: pubkey, }) return nil } func (tx *SendTx) AddOutput(addr []byte, amt int64) error { tx.Outputs = append(tx.Outputs, &TxOutput{ Address: addr, Amount: amt, }) return nil } func (tx *SendTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error { if i >= len(tx.Inputs) { return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs)) } tx.Inputs[i].PubKey = privAccount.PubKey tx.Inputs[i].Signature = privAccount.Sign(chainID, tx) return nil } //---------------------------------------------------------------------------- // CallTx interface for creating tx func NewCallTx(st AccountGetter, from acm.PubKey, to, data []byte, amt, gasLimit, fee int64) (*CallTx, error) { addr := from.Address() acc := st.GetAccount(addr) if acc == nil { return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from) } nonce := acc.Sequence + 1 return NewCallTxWithNonce(from, to, data, amt, gasLimit, fee, nonce), nil } func NewCallTxWithNonce(from acm.PubKey, to, data []byte, amt, gasLimit, fee int64, nonce int) *CallTx { addr := from.Address() input := &TxInput{ Address: addr, Amount: amt, Sequence: nonce, Signature: acm.SignatureEd25519{}, PubKey: from, } return &CallTx{ Input: input, Address: to, GasLimit: gasLimit, Fee: fee, Data: data, } } func (tx *CallTx) Sign(chainID string, privAccount *acm.PrivAccount) { tx.Input.PubKey = privAccount.PubKey tx.Input.Signature = privAccount.Sign(chainID, tx) } //---------------------------------------------------------------------------- // NameTx interface for creating tx func NewNameTx(st AccountGetter, from acm.PubKey, name, data string, amt, fee int64) (*NameTx, error) { addr := from.Address() acc := st.GetAccount(addr) if acc == nil { return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from) } nonce := acc.Sequence + 1 return NewNameTxWithNonce(from, name, data, amt, fee, nonce), nil } func NewNameTxWithNonce(from acm.PubKey, name, data string, amt, fee int64, nonce int) *NameTx { addr := from.Address() input := &TxInput{ Address: addr, Amount: amt, Sequence: nonce, Signature: acm.SignatureEd25519{}, PubKey: from, } return &NameTx{ Input: input, Name: name, Data: data, Fee: fee, } } func (tx *NameTx) Sign(chainID string, privAccount *acm.PrivAccount) { tx.Input.PubKey = privAccount.PubKey tx.Input.Signature = privAccount.Sign(chainID, tx) } //---------------------------------------------------------------------------- // BondTx interface for adding inputs/outputs and adding signatures func NewBondTx(pubkey acm.PubKey) (*BondTx, error) { pubkeyEd, ok := pubkey.(acm.PubKeyEd25519) if !ok { return nil, fmt.Errorf("Pubkey must be ed25519") } return &BondTx{ PubKey: pubkeyEd, Inputs: []*TxInput{}, UnbondTo: []*TxOutput{}, }, nil } func (tx *BondTx) AddInput(st AccountGetter, pubkey acm.PubKey, amt int64) error { addr := pubkey.Address() acc := st.GetAccount(addr) if acc == nil { return fmt.Errorf("Invalid address %X from pubkey %X", addr, pubkey) } return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1) } func (tx *BondTx) AddInputWithNonce(pubkey acm.PubKey, amt int64, nonce int) error { addr := pubkey.Address() tx.Inputs = append(tx.Inputs, &TxInput{ Address: addr, Amount: amt, Sequence: nonce, Signature: acm.SignatureEd25519{}, PubKey: pubkey, }) return nil } func (tx *BondTx) AddOutput(addr []byte, amt int64) error { tx.UnbondTo = append(tx.UnbondTo, &TxOutput{ Address: addr, Amount: amt, }) return nil } func (tx *BondTx) SignBond(chainID string, privAccount *acm.PrivAccount) error { sig := privAccount.Sign(chainID, tx) sigEd, ok := sig.(acm.SignatureEd25519) if !ok { return fmt.Errorf("Bond signer must be ED25519") } tx.Signature = sigEd return nil } func (tx *BondTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error { if i >= len(tx.Inputs) { return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs)) } tx.Inputs[i].PubKey = privAccount.PubKey tx.Inputs[i].Signature = privAccount.Sign(chainID, tx) return nil } //---------------------------------------------------------------------- // UnbondTx interface for creating tx func NewUnbondTx(addr []byte, height int) *UnbondTx { return &UnbondTx{ Address: addr, Height: height, } } func (tx *UnbondTx) Sign(chainID string, privAccount *acm.PrivAccount) { tx.Signature = privAccount.Sign(chainID, tx).(acm.SignatureEd25519) } //---------------------------------------------------------------------- // RebondTx interface for creating tx func NewRebondTx(addr []byte, height int) *RebondTx { return &RebondTx{ Address: addr, Height: height, } } func (tx *RebondTx) Sign(chainID string, privAccount *acm.PrivAccount) { tx.Signature = privAccount.Sign(chainID, tx).(acm.SignatureEd25519) } //---------------------------------------------------------------------------- // PermissionsTx interface for creating tx func NewPermissionsTx(st AccountGetter, from acm.PubKey, args ptypes.PermArgs) (*PermissionsTx, error) { addr := from.Address() acc := st.GetAccount(addr) if acc == nil { return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from) } nonce := acc.Sequence + 1 return NewPermissionsTxWithNonce(from, args, nonce), nil } func NewPermissionsTxWithNonce(from acm.PubKey, args ptypes.PermArgs, nonce int) *PermissionsTx { addr := from.Address() input := &TxInput{ Address: addr, Amount: 1, // NOTE: amounts can't be 0 ... Sequence: nonce, Signature: acm.SignatureEd25519{}, PubKey: from, } return &PermissionsTx{ Input: input, PermArgs: args, } } func (tx *PermissionsTx) Sign(chainID string, privAccount *acm.PrivAccount) { tx.Input.PubKey = privAccount.PubKey tx.Input.Signature = privAccount.Sign(chainID, tx) }