diff --git a/txs/events.go b/txs/events.go deleted file mode 100644 index 6c634d18386d41b7596b310483fdf9c7acdb6896..0000000000000000000000000000000000000000 --- a/txs/events.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2017 Monax Industries Limited -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package txs - -import ( - "fmt" - "time" - - . "github.com/hyperledger/burrow/word256" - - "github.com/tendermint/go-wire" - tm_types "github.com/tendermint/tendermint/types" // Block -) - -// Functions to generate eventId strings - -func EventStringAccInput(addr []byte) string { return fmt.Sprintf("Acc/%X/Input", addr) } -func EventStringAccOutput(addr []byte) string { return fmt.Sprintf("Acc/%X/Output", addr) } -func EventStringAccCall(addr []byte) string { return fmt.Sprintf("Acc/%X/Call", addr) } -func EventStringLogEvent(addr []byte) string { return fmt.Sprintf("Log/%X", addr) } -func EventStringPermissions(name string) string { return fmt.Sprintf("Permissions/%s", name) } -func EventStringNameReg(name string) string { return fmt.Sprintf("NameReg/%s", name) } -func EventStringBond() string { return "Bond" } -func EventStringUnbond() string { return "Unbond" } -func EventStringRebond() string { return "Rebond" } -func EventStringDupeout() string { return "Dupeout" } -func EventStringNewBlock() string { return "NewBlock" } -func EventStringFork() string { return "Fork" } - -func EventStringNewRound() string { return fmt.Sprintf("NewRound") } -func EventStringTimeoutPropose() string { return fmt.Sprintf("TimeoutPropose") } -func EventStringCompleteProposal() string { return fmt.Sprintf("CompleteProposal") } -func EventStringPolka() string { return fmt.Sprintf("Polka") } -func EventStringUnlock() string { return fmt.Sprintf("Unlock") } -func EventStringLock() string { return fmt.Sprintf("Lock") } -func EventStringRelock() string { return fmt.Sprintf("Relock") } -func EventStringTimeoutWait() string { return fmt.Sprintf("TimeoutWait") } -func EventStringVote() string { return fmt.Sprintf("Vote") } - -//---------------------------------------- - -const ( - EventDataTypeNewBlock = byte(0x01) - EventDataTypeFork = byte(0x02) - EventDataTypeTx = byte(0x03) - EventDataTypeCall = byte(0x04) - EventDataTypeLog = byte(0x05) - EventDataTypeNewBlockHeader = byte(0x06) - - EventDataTypeRoundState = byte(0x11) - EventDataTypeVote = byte(0x12) -) - -type EventData interface { - AssertIsEventData() -} - -var _ = wire.RegisterInterface( - struct{ EventData }{}, - wire.ConcreteType{EventDataNewBlockHeader{}, EventDataTypeNewBlockHeader}, - wire.ConcreteType{EventDataNewBlock{}, EventDataTypeNewBlock}, - // wire.ConcreteType{EventDataFork{}, EventDataTypeFork }, - wire.ConcreteType{EventDataTx{}, EventDataTypeTx}, - wire.ConcreteType{EventDataCall{}, EventDataTypeCall}, - wire.ConcreteType{EventDataLog{}, EventDataTypeLog}, - wire.ConcreteType{EventDataRoundState{}, EventDataTypeRoundState}, - wire.ConcreteType{EventDataVote{}, EventDataTypeVote}, -) - -// Most event messages are basic types (a block, a transaction) -// but some (an input to a call tx or a receive) are more exotic - -type EventDataNewBlock struct { - Block *tm_types.Block `json:"block"` -} - -type EventDataNewBlockHeader struct { - Header *tm_types.Header `json:"header"` -} - -// All txs fire EventDataTx, but only CallTx might have Return or Exception -type EventDataTx struct { - Tx Tx `json:"tx"` - Return []byte `json:"return"` - Exception string `json:"exception"` -} - -// EventDataCall fires when we call a contract, and when a contract calls another contract -type EventDataCall struct { - CallData *CallData `json:"call_data"` - Origin []byte `json:"origin"` - TxID []byte `json:"tx_id"` - Return []byte `json:"return"` - Exception string `json:"exception"` -} - -type CallData struct { - Caller []byte `json:"caller"` - Callee []byte `json:"callee"` - Data []byte `json:"data"` - Value int64 `json:"value"` - Gas int64 `json:"gas"` -} - -// EventDataLog fires when a contract executes the LOG opcode -type EventDataLog struct { - Address Word256 `json:"address"` - Topics []Word256 `json:"topics"` - Data []byte `json:"data"` - Height int64 `json:"height"` -} - -// We fire the most recent round state that led to the event -// (ie. NewRound will have the previous rounds state) -type EventDataRoundState struct { - CurrentTime time.Time `json:"current_time"` - - Height int `json:"height"` - Round int `json:"round"` - Step string `json:"step"` - StartTime time.Time `json:"start_time"` - CommitTime time.Time `json:"commit_time"` - Proposal *tm_types.Proposal `json:"proposal"` - ProposalBlock *tm_types.Block `json:"proposal_block"` - LockedRound int `json:"locked_round"` - LockedBlock *tm_types.Block `json:"locked_block"` - POLRound int `json:"pol_round"` -} - -type EventDataVote struct { - Index int - Address []byte - Vote *tm_types.Vote -} - -func (_ EventDataNewBlock) AssertIsEventData() {} -func (_ EventDataNewBlockHeader) AssertIsEventData() {} -func (_ EventDataTx) AssertIsEventData() {} -func (_ EventDataCall) AssertIsEventData() {} -func (_ EventDataLog) AssertIsEventData() {} -func (_ EventDataRoundState) AssertIsEventData() {} -func (_ EventDataVote) AssertIsEventData() {} diff --git a/txs/go_wire_codec.go b/txs/go_wire_codec.go new file mode 100644 index 0000000000000000000000000000000000000000..ebedfcf7bc1d699d4d72a8238f493ccc4eb47de6 --- /dev/null +++ b/txs/go_wire_codec.go @@ -0,0 +1,53 @@ +package txs + +import ( + "bytes" + "sync" + + "github.com/tendermint/go-wire" +) + +type goWireCodec struct { + // Worth it? Possibly not, but we need to instantiate a codec though so... + bufferPool sync.Pool +} + +func NewGoWireCodec() *goWireCodec { + return &goWireCodec{ + bufferPool: sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + }, + } +} + +func (gwc *goWireCodec) EncodeTx(tx Tx) ([]byte, error) { + var n int + var err error + buf := gwc.bufferPool.Get().(*bytes.Buffer) + defer gwc.recycle(buf) + wire.WriteBinary(struct{ Tx }{tx}, buf, &n, &err) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// panic on err +func (gwc *goWireCodec) DecodeTx(txBytes []byte) (Tx, error) { + var n int + var err error + tx := new(Tx) + buf := bytes.NewBuffer(txBytes) + wire.ReadBinaryPtr(tx, buf, len(txBytes), &n, &err) + if err != nil { + return nil, err + } + return *tx, nil +} + +func (gwc *goWireCodec) recycle(buf *bytes.Buffer) { + buf.Reset() + gwc.bufferPool.Put(buf) +} diff --git a/txs/go_wire_codec_test.go b/txs/go_wire_codec_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7e191c19e6d5818b296064b27cda244780ddea9f --- /dev/null +++ b/txs/go_wire_codec_test.go @@ -0,0 +1,59 @@ +package txs + +import ( + "testing" + + acm "github.com/hyperledger/burrow/account" + "github.com/stretchr/testify/assert" +) + +func TestEncodeTxDecodeTx(t *testing.T) { + gwc := NewGoWireCodec() + inputAddress := acm.Address{1, 2, 3, 4, 5} + outputAddress := acm.Address{5, 4, 3, 2, 1} + amount := uint64(2) + sequence := uint64(3) + tx := &SendTx{ + Inputs: []*TxInput{{ + Address: inputAddress, + Amount: amount, + Sequence: sequence, + }}, + Outputs: []*TxOutput{{ + Address: outputAddress, + Amount: amount, + }}, + } + txBytes, err := gwc.EncodeTx(tx) + if err != nil { + t.Fatal(err) + } + txOut, err := gwc.DecodeTx(txBytes) + assert.NoError(t, err, "DecodeTx error") + assert.Equal(t, tx, txOut) +} + +func TestEncodeTxDecodeTx_CallTx(t *testing.T) { + gwc := NewGoWireCodec() + inputAddress := acm.Address{1, 2, 3, 4, 5} + amount := uint64(2) + sequence := uint64(3) + tx := &CallTx{ + Input: &TxInput{ + Address: inputAddress, + Amount: amount, + Sequence: sequence, + }, + GasLimit: 233, + Fee: 2, + Address: nil, + Data: []byte("code"), + } + txBytes, err := gwc.EncodeTx(tx) + if err != nil { + t.Fatal(err) + } + txOut, err := gwc.DecodeTx(txBytes) + assert.NoError(t, err, "DecodeTx error") + assert.Equal(t, tx, txOut) +} diff --git a/txs/names.go b/txs/names.go index 6535bf7656870219e56dafa106cd254a80756e0d..23c693f0a1a8db9a6c6c559f30f601092482db99 100644 --- a/txs/names.go +++ b/txs/names.go @@ -16,20 +16,18 @@ package txs import ( "regexp" - - core_types "github.com/hyperledger/burrow/core/types" ) var ( - MinNameRegistrationPeriod int = 5 + MinNameRegistrationPeriod uint64 = 5 // NOTE: base costs and validity checks are here so clients // can use them without importing state // cost for storing a name for a block is // CostPerBlock*CostPerByte*(len(data) + 32) - NameByteCostMultiplier int64 = 1 - NameBlockCostMultiplier int64 = 1 + NameByteCostMultiplier uint64 = 1 + NameBlockCostMultiplier uint64 = 1 MaxNameLength = 64 MaxDataLength = 1 << 16 @@ -50,16 +48,10 @@ func validateNameRegEntryData(data string) bool { } // base cost is "effective" number of bytes -func NameBaseCost(name, data string) int64 { - return int64(len(data) + 32) +func NameBaseCost(name, data string) uint64 { + return uint64(len(data) + 32) } -func NameCostPerBlock(baseCost int64) int64 { +func NameCostPerBlock(baseCost uint64) uint64 { return NameBlockCostMultiplier * NameByteCostMultiplier * baseCost } - -// XXX: vestige of an older time -type ResultListNames struct { - BlockHeight int `json:"block_height"` - Names []*core_types.NameRegEntry `json:"names"` -} diff --git a/txs/tx.go b/txs/tx.go index 44cd1b1056dadd93225cad00f904d110039d684e..1cb2ea1b40e654562bc09457bfd78ff182edc064 100644 --- a/txs/tx.go +++ b/txs/tx.go @@ -15,32 +15,27 @@ package txs import ( - "bytes" "encoding/json" "errors" + "fmt" "io" - "golang.org/x/crypto/ripemd160" - acm "github.com/hyperledger/burrow/account" - ptypes "github.com/hyperledger/burrow/permission/types" - . "github.com/tendermint/go-common" - "github.com/tendermint/go-wire" - + ptypes "github.com/hyperledger/burrow/permission" "github.com/tendermint/go-crypto" - tendermint_types "github.com/tendermint/tendermint/types" // votes for dupeout .. + "github.com/tendermint/go-wire" + "github.com/tendermint/go-wire/data" + "golang.org/x/crypto/ripemd160" ) 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") - ErrTxInsufficientGasPrice = errors.New("Error insufficient gas price") - ErrTxUnknownPubKey = errors.New("Error unknown pubkey") - ErrTxInvalidPubKey = errors.New("Error invalid pubkey") - ErrTxInvalidSignature = errors.New("Error invalid signature") - ErrTxPermissionDenied = errors.New("Error permission denied") + 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") + ErrTxInvalidSignature = errors.New("error invalid signature") ) type ErrTxInvalidString struct { @@ -52,12 +47,12 @@ func (e ErrTxInvalidString) Error() string { } type ErrTxInvalidSequence struct { - Got int - Expected int + Got uint64 + Expected uint64 } func (e ErrTxInvalidSequence) Error() string { - return Fmt("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected) + return fmt.Sprintf("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected) } /* @@ -71,7 +66,6 @@ Account Txs: Validation Txs: - BondTx New validator posts a bond - UnbondTx Validator leaves - - DupeoutTx Validator dupes out (equivocates) Admin Txs: - PermissionsTx @@ -85,27 +79,22 @@ const ( TxTypeName = byte(0x03) // Validation transactions - TxTypeBond = byte(0x11) - TxTypeUnbond = byte(0x12) - TxTypeRebond = byte(0x13) - TxTypeDupeout = byte(0x14) + TxTypeBond = byte(0x11) + TxTypeUnbond = byte(0x12) + TxTypeRebond = byte(0x13) // Admin transactions - TxTypePermissions = byte(0x20) + TxTypePermissions = byte(0x1f) ) -// for wire.readReflect -var _ = wire.RegisterInterface( - struct{ Tx }{}, - wire.ConcreteType{&SendTx{}, TxTypeSend}, - wire.ConcreteType{&CallTx{}, TxTypeCall}, - wire.ConcreteType{&NameTx{}, TxTypeName}, - wire.ConcreteType{&BondTx{}, TxTypeBond}, - wire.ConcreteType{&UnbondTx{}, TxTypeUnbond}, - wire.ConcreteType{&RebondTx{}, TxTypeRebond}, - wire.ConcreteType{&DupeoutTx{}, TxTypeDupeout}, - wire.ConcreteType{&PermissionsTx{}, TxTypePermissions}, -) +var mapper = data.NewMapper(Wrapper{}). + RegisterImplementation(&SendTx{}, "send_tx", TxTypeSend). + RegisterImplementation(&CallTx{}, "call_tx", TxTypeCall). + RegisterImplementation(&NameTx{}, "name_tx", TxTypeName). + RegisterImplementation(&BondTx{}, "bond_tx", TxTypeBond). + RegisterImplementation(&UnbondTx{}, "unbond_tx", TxTypeUnbond). + RegisterImplementation(&RebondTx{}, "rebond_tx", TxTypeRebond). + RegisterImplementation(&PermissionsTx{}, "permissions_tx", TxTypePermissions) //----------------------------------------------------------------------------- @@ -114,6 +103,18 @@ type ( WriteSignBytes(chainID string, w io.Writer, n *int, err *error) } + Wrapper struct { + Tx `json:"unwrap"` + } + + Encoder interface { + EncodeTx(tx Tx) ([]byte, error) + } + + Decoder interface { + DecodeTx(txBytes []byte) (Tx, error) + } + // UnconfirmedTxs UnconfirmedTxs struct { Txs []Tx `json:"txs"` @@ -126,40 +127,73 @@ type ( // BroadcastTx or Transact Receipt struct { - TxHash []byte `json:"tx_hash"` - CreatesContract uint8 `json:"creates_contract"` - ContractAddr []byte `json:"contract_addr"` + TxHash []byte `json:"tx_hash"` + CreatesContract bool `json:"creates_contract"` + ContractAddr acm.Address `json:"contract_addr"` } NameTx struct { Input *TxInput `json:"input"` Name string `json:"name"` Data string `json:"data"` - Fee int64 `json:"fee"` + Fee uint64 `json:"fee"` } CallTx struct { - Input *TxInput `json:"input"` - Address []byte `json:"address"` - GasLimit int64 `json:"gas_limit"` - Fee int64 `json:"fee"` - Data []byte `json:"data"` + Input *TxInput `json:"input"` + // Pointer since CallTx defines unset 'to' address as inducing account creation + Address *acm.Address `json:"address"` + GasLimit uint64 `json:"gas_limit"` + Fee uint64 `json:"fee"` + Data []byte `json:"data"` } TxInput struct { - Address []byte `json:"address"` // Hash of the PubKey - Amount int64 `json:"amount"` // Must not exceed account balance - Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput - Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx - PubKey crypto.PubKey `json:"pub_key"` // Must not be nil, may be nil + Address acm.Address `json:"address"` // Hash of the PublicKey + Amount uint64 `json:"amount"` // Must not exceed account balance + Sequence uint64 `json:"sequence"` // Must be 1 greater than the last committed TxInput + Signature crypto.Signature `json:"signature"` // Depends on the PublicKey type and the whole Tx + PubKey acm.PublicKey `json:"pub_key"` // Must not be nil, may be nil } TxOutput struct { - Address []byte `json:"address"` // Hash of the PubKey - Amount int64 `json:"amount"` // The sum of all outputs must not exceed the inputs. + Address acm.Address `json:"address"` // Hash of the PublicKey + Amount uint64 `json:"amount"` // The sum of all outputs must not exceed the inputs. } ) +// Wrap the Tx in a struct that allows for go-wire JSON serialisation +func Wrap(tx Tx) Wrapper { + if txWrapped, ok := tx.(Wrapper); ok { + return txWrapped + } + return Wrapper{ + Tx: tx, + } +} + +// A serialisation wrapper that is itself a Tx +func (txw Wrapper) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { + txw.Tx.WriteSignBytes(chainID, w, n, err) +} + +func (txw Wrapper) MarshalJSON() ([]byte, error) { + return mapper.ToJSON(txw.Tx) +} + +func (txw *Wrapper) UnmarshalJSON(data []byte) (err error) { + parsed, err := mapper.FromJSON(data) + if err == nil && parsed != nil { + txw.Tx = parsed.(Tx) + } + return err +} + +// Get the inner Tx that this Wrapper wraps +func (txw *Wrapper) Unwrap() Tx { + return txw.Tx +} + func (txIn *TxInput) ValidateBasic() error { if len(txIn.Address) != 20 { return ErrTxInvalidAddress @@ -171,11 +205,11 @@ func (txIn *TxInput) ValidateBasic() error { } func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err) } func (txIn *TxInput) String() string { - return Fmt("TxInput{%X,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PubKey) + return fmt.Sprintf("TxInput{%s,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PubKey) } //----------------------------------------------------------------------------- @@ -191,18 +225,18 @@ func (txOut *TxOutput) ValidateBasic() error { } func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err) } func (txOut *TxOutput) String() string { - return Fmt("TxOutput{%X,%v}", txOut.Address, txOut.Amount) + return fmt.Sprintf("TxOutput{%s,%v}", txOut.Address, txOut.Amount) } //----------------------------------------------------------------------------- func (tx *SendTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err) for i, in := range tx.Inputs { in.WriteSignBytes(w, n, err) if i != len(tx.Inputs)-1 { @@ -220,40 +254,31 @@ func (tx *SendTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error } func (tx *SendTx) String() string { - return Fmt("SendTx{%v -> %v}", tx.Inputs, tx.Outputs) + return fmt.Sprintf("SendTx{%v -> %v}", tx.Inputs, tx.Outputs) } //----------------------------------------------------------------------------- func (tx *CallTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err) - wire.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err) tx.Input.WriteSignBytes(w, n, err) wire.WriteTo([]byte(`}]}`), w, n, err) } func (tx *CallTx) String() string { - return Fmt("CallTx{%v -> %x: %x}", tx.Input, tx.Address, tx.Data) -} - -func NewContractAddress(caller []byte, nonce int) []byte { - temp := make([]byte, 32+8) - copy(temp, caller) - PutInt64BE(temp[32:], int64(nonce)) - hasher := ripemd160.New() - hasher.Write(temp) // does not error - return hasher.Sum(nil) + return fmt.Sprintf("CallTx{%v -> %s: %X}", tx.Input, tx.Address, tx.Data) } //----------------------------------------------------------------------------- func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err) wire.WriteTo([]byte(`,"input":`), w, n, err) tx.Input.WriteSignBytes(w, n, err) - wire.WriteTo([]byte(Fmt(`,"name":%s`, jsonEscape(tx.Name))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"name":%s`, jsonEscape(tx.Name))), w, n, err) wire.WriteTo([]byte(`}]}`), w, n, err) } @@ -262,46 +287,46 @@ func (tx *NameTx) ValidateStrings() error { return ErrTxInvalidString{"Name must not be empty"} } if len(tx.Name) > MaxNameLength { - return ErrTxInvalidString{Fmt("Name is too long. Max %d bytes", MaxNameLength)} + return ErrTxInvalidString{fmt.Sprintf("Name is too long. Max %d bytes", MaxNameLength)} } if len(tx.Data) > MaxDataLength { - return ErrTxInvalidString{Fmt("Data is too long. Max %d bytes", MaxDataLength)} + return ErrTxInvalidString{fmt.Sprintf("Data is too long. Max %d bytes", MaxDataLength)} } if !validateNameRegEntryName(tx.Name) { - return ErrTxInvalidString{Fmt("Invalid characters found in NameTx.Name (%s). Only alphanumeric, underscores, dashes, forward slashes, and @ are allowed", tx.Name)} + return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Name (%s). Only alphanumeric, underscores, dashes, forward slashes, and @ are allowed", tx.Name)} } if !validateNameRegEntryData(tx.Data) { - return ErrTxInvalidString{Fmt("Invalid characters found in NameTx.Data (%s). Only the kind of things found in a JSON file are allowed", tx.Data)} + return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Data (%s). Only the kind of things found in a JSON file are allowed", tx.Data)} } return nil } func (tx *NameTx) String() string { - return Fmt("NameTx{%v -> %s: %s}", tx.Input, tx.Name, tx.Data) + return fmt.Sprintf("NameTx{%v -> %s: %s}", tx.Input, tx.Name, tx.Data) } //----------------------------------------------------------------------------- type BondTx struct { - PubKey crypto.PubKeyEd25519 `json:"pub_key"` // NOTE: these don't have type byte - Signature crypto.SignatureEd25519 `json:"signature"` - Inputs []*TxInput `json:"inputs"` - UnbondTo []*TxOutput `json:"unbond_to"` + PubKey acm.PublicKey `json:"pub_key"` // NOTE: these don't have type byte + Signature crypto.Signature `json:"signature"` + Inputs []*TxInput `json:"inputs"` + UnbondTo []*TxOutput `json:"unbond_to"` } func (tx *BondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err) for i, in := range tx.Inputs { in.WriteSignBytes(w, n, err) if i != len(tx.Inputs)-1 { wire.WriteTo([]byte(","), w, n, err) } } - wire.WriteTo([]byte(Fmt(`],"pub_key":`)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`],"pub_key":`)), w, n, err) wire.WriteTo(wire.JSONBytes(tx.PubKey), w, n, err) wire.WriteTo([]byte(`,"unbond_to":[`), w, n, err) for i, out := range tx.UnbondTo { @@ -314,71 +339,53 @@ func (tx *BondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error } func (tx *BondTx) String() string { - return Fmt("BondTx{%v: %v -> %v}", tx.PubKey, tx.Inputs, tx.UnbondTo) + return fmt.Sprintf("BondTx{%v: %v -> %v}", tx.PubKey, tx.Inputs, tx.UnbondTo) } //----------------------------------------------------------------------------- type UnbondTx struct { - Address []byte `json:"address"` - Height int `json:"height"` - Signature crypto.SignatureEd25519 `json:"signature"` + Address acm.Address `json:"address"` + Height int `json:"height"` + Signature crypto.Signature `json:"signature"` } func (tx *UnbondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err) } func (tx *UnbondTx) String() string { - return Fmt("UnbondTx{%X,%v,%v}", tx.Address, tx.Height, tx.Signature) + return fmt.Sprintf("UnbondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature) } //----------------------------------------------------------------------------- type RebondTx struct { - Address []byte `json:"address"` - Height int `json:"height"` - Signature crypto.SignatureEd25519 `json:"signature"` + Address acm.Address `json:"address"` + Height int `json:"height"` + Signature crypto.Signature `json:"signature"` } func (tx *RebondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err) } func (tx *RebondTx) String() string { - return Fmt("RebondTx{%X,%v,%v}", tx.Address, tx.Height, tx.Signature) -} - -//----------------------------------------------------------------------------- - -type DupeoutTx struct { - Address []byte `json:"address"` - VoteA tendermint_types.Vote `json:"vote_a"` - VoteB tendermint_types.Vote `json:"vote_b"` -} - -func (tx *DupeoutTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - // PanicSanity("DupeoutTx has no sign bytes") - // TODO - // return -} - -func (tx *DupeoutTx) String() string { - return Fmt("DupeoutTx{%X,%v,%v}", tx.Address, tx.VoteA, tx.VoteB) + return fmt.Sprintf("RebondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature) } //----------------------------------------------------------------------------- type PermissionsTx struct { Input *TxInput `json:"input"` - PermArgs ptypes.PermArgs `json:"args"` + PermArgs *ptypes.PermArgs `json:"args"` } func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { - wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"args":"`, TxTypePermissions)), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"args":"`, TxTypePermissions)), w, n, err) wire.WriteJSON(&tx.PermArgs, w, n, err) wire.WriteTo([]byte(`","input":`), w, n, err) tx.Input.WriteSignBytes(w, n, err) @@ -386,7 +393,7 @@ func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int, err } func (tx *PermissionsTx) String() string { - return Fmt("PermissionsTx{%v -> %v}", tx.Input, tx.PermArgs) + return fmt.Sprintf("PermissionsTx{%v -> %v}", tx.Input, tx.PermArgs) } //----------------------------------------------------------------------------- @@ -401,41 +408,16 @@ func TxHash(chainID string, tx Tx) []byte { //----------------------------------------------------------------------------- -func EncodeTx(tx Tx) ([]byte, error) { - var n int - var err error - buf := new(bytes.Buffer) - wire.WriteBinary(struct{ Tx }{tx}, buf, &n, &err) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// panic on err -func DecodeTx(txBytes []byte) (Tx, error) { - var n int - var err error - tx := new(Tx) - buf := bytes.NewBuffer(txBytes) - wire.ReadBinaryPtr(tx, buf, len(txBytes), &n, &err) - if err != nil { - return nil, err - } - return *tx, nil -} - func GenerateReceipt(chainId string, tx Tx) Receipt { receipt := Receipt{ - TxHash: TxHash(chainId, tx), - CreatesContract: 0, - ContractAddr: nil, + TxHash: TxHash(chainId, tx), } if callTx, ok := tx.(*CallTx); ok { - if len(callTx.Address) == 0 { - receipt.CreatesContract = 1 - receipt.ContractAddr = NewContractAddress(callTx.Input.Address, - callTx.Input.Sequence) + receipt.CreatesContract = callTx.Address == nil + if receipt.CreatesContract { + receipt.ContractAddr = acm.NewContractAddress(callTx.Input.Address, callTx.Input.Sequence) + } else { + receipt.ContractAddr = *callTx.Address } } return receipt @@ -447,7 +429,7 @@ func GenerateReceipt(chainId string, tx Tx) Receipt { func jsonEscape(str string) string { escapedBytes, err := json.Marshal(str) if err != nil { - PanicSanity(Fmt("Error json-escaping a string", str)) + panic(fmt.Sprintf("error json-escaping a string", str)) } return string(escapedBytes) } diff --git a/txs/tx_test.go b/txs/tx_test.go index ca4b2ff0048278efdb71b55170bbd385d6e3af2e..6bc2f110a832ee7073ca335d5fae594dd1b46322 100644 --- a/txs/tx_test.go +++ b/txs/tx_test.go @@ -15,47 +15,53 @@ package txs import ( + "fmt" "testing" - acm "github.com/hyperledger/burrow/account" - ptypes "github.com/hyperledger/burrow/permission/types" + "encoding/json" + acm "github.com/hyperledger/burrow/account" + ptypes "github.com/hyperledger/burrow/permission" "github.com/stretchr/testify/assert" - . "github.com/tendermint/go-common" - "github.com/tendermint/go-crypto" + "github.com/stretchr/testify/require" ) var chainID = "myChainID" +func makeAddress(str string) (address acm.Address) { + copy(address[:], ([]byte)(str)) + return +} + func TestSendTxSignable(t *testing.T) { sendTx := &SendTx{ Inputs: []*TxInput{ - &TxInput{ - Address: []byte("input1"), + { + Address: makeAddress("input1"), Amount: 12345, Sequence: 67890, }, - &TxInput{ - Address: []byte("input2"), + { + Address: makeAddress("input2"), Amount: 111, Sequence: 222, }, }, Outputs: []*TxOutput{ - &TxOutput{ - Address: []byte("output1"), + { + Address: makeAddress("output1"), Amount: 333, }, - &TxOutput{ - Address: []byte("output2"), + { + Address: makeAddress("output2"), Amount: 444, }, }, } signBytes := acm.SignBytes(chainID, sendTx) signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[1,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"outputs":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, - chainID) + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[1,{"inputs":[{"address":"%s","amount":12345,"sequence":67890},{"address":"%s","amount":111,"sequence":222}],"outputs":[{"address":"%s","amount":333},{"address":"%s","amount":444}]}]}`, + chainID, sendTx.Inputs[0].Address.String(), sendTx.Inputs[1].Address.String(), sendTx.Outputs[0].Address.String(), sendTx.Outputs[1].Address.String()) if signStr != expected { t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr) @@ -63,21 +69,22 @@ func TestSendTxSignable(t *testing.T) { } func TestCallTxSignable(t *testing.T) { + toAddress := makeAddress("contract1") callTx := &CallTx{ Input: &TxInput{ - Address: []byte("input1"), + Address: makeAddress("input1"), Amount: 12345, Sequence: 67890, }, - Address: []byte("contract1"), + Address: &toAddress, GasLimit: 111, Fee: 222, Data: []byte("data1"), } signBytes := acm.SignBytes(chainID, callTx) signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[2,{"address":"636F6E747261637431","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"696E70757431","amount":12345,"sequence":67890}}]}`, - chainID) + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[2,{"address":"%s","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"%s","amount":12345,"sequence":67890}}]}`, + chainID, callTx.Address.String(), callTx.Input.Address.String()) if signStr != expected { t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) } @@ -86,7 +93,7 @@ func TestCallTxSignable(t *testing.T) { func TestNameTxSignable(t *testing.T) { nameTx := &NameTx{ Input: &TxInput{ - Address: []byte("input1"), + Address: makeAddress("input1"), Amount: 12345, Sequence: 250, }, @@ -96,8 +103,8 @@ func TestNameTxSignable(t *testing.T) { } signBytes := acm.SignBytes(chainID, nameTx) signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[3,{"data":"secretly.not.google.com","fee":1000,"input":{"address":"696E70757431","amount":12345,"sequence":250},"name":"google.com"}]}`, - chainID) + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[3,{"data":"secretly.not.google.com","fee":1000,"input":{"address":"%s","amount":12345,"sequence":250},"name":"google.com"}]}`, + chainID, nameTx.Input.Address.String()) if signStr != expected { t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) } @@ -105,50 +112,46 @@ func TestNameTxSignable(t *testing.T) { func TestBondTxSignable(t *testing.T) { privKeyBytes := make([]byte, 64) - privAccount := acm.GenPrivAccountFromPrivKeyBytes(privKeyBytes) + privAccount := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKeyBytes) bondTx := &BondTx{ - PubKey: privAccount.PubKey.(crypto.PubKeyEd25519), + PubKey: privAccount.PublicKey(), Inputs: []*TxInput{ - &TxInput{ - Address: []byte("input1"), + { + Address: makeAddress("input1"), Amount: 12345, Sequence: 67890, }, - &TxInput{ - Address: []byte("input2"), + { + Address: makeAddress("input2"), Amount: 111, Sequence: 222, }, }, UnbondTo: []*TxOutput{ - &TxOutput{ - Address: []byte("output1"), + { + Address: makeAddress("output1"), Amount: 333, }, - &TxOutput{ - Address: []byte("output2"), + { + Address: makeAddress("output2"), Amount: 444, }, }, } - signBytes := acm.SignBytes(chainID, bondTx) - signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[17,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"pub_key":"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29","unbond_to":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, - chainID) - if signStr != expected { - t.Errorf("Unexpected sign string for BondTx. \nGot %s\nExpected %s", signStr, expected) - } + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[17,{"inputs":[{"address":"%s","amount":12345,"sequence":67890},{"address":"%s","amount":111,"sequence":222}],"pub_key":[1,"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29"],"unbond_to":[{"address":"%s","amount":333},{"address":"%s","amount":444}]}]}`, + chainID, bondTx.Inputs[0].Address.String(), bondTx.Inputs[1].Address.String(), bondTx.UnbondTo[0].Address.String(), bondTx.UnbondTo[1].Address.String()) + assert.Equal(t, expected, string(acm.SignBytes(chainID, bondTx)), "Unexpected sign string for BondTx") } func TestUnbondTxSignable(t *testing.T) { unbondTx := &UnbondTx{ - Address: []byte("address1"), + Address: makeAddress("address1"), Height: 111, } signBytes := acm.SignBytes(chainID, unbondTx) signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[18,{"address":"6164647265737331","height":111}]}`, - chainID) + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[18,{"address":"%s","height":111}]}`, + chainID, unbondTx.Address.String()) if signStr != expected { t.Errorf("Got unexpected sign string for UnbondTx") } @@ -156,13 +159,13 @@ func TestUnbondTxSignable(t *testing.T) { func TestRebondTxSignable(t *testing.T) { rebondTx := &RebondTx{ - Address: []byte("address1"), + Address: makeAddress("address1"), Height: 111, } signBytes := acm.SignBytes(chainID, rebondTx) signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[19,{"address":"6164647265737331","height":111}]}`, - chainID) + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[19,{"address":"%s","height":111}]}`, + chainID, rebondTx.Address.String()) if signStr != expected { t.Errorf("Got unexpected sign string for RebondTx") } @@ -171,77 +174,84 @@ func TestRebondTxSignable(t *testing.T) { func TestPermissionsTxSignable(t *testing.T) { permsTx := &PermissionsTx{ Input: &TxInput{ - Address: []byte("input1"), + Address: makeAddress("input1"), Amount: 12345, Sequence: 250, }, - PermArgs: &ptypes.SetBaseArgs{ - Address: []byte("address1"), - Permission: 1, - Value: true, - }, + PermArgs: ptypes.SetBaseArgs(makeAddress("address1"), 1, true), } signBytes := acm.SignBytes(chainID, permsTx) signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[32,{"args":"[2,{"address":"6164647265737331","permission":1,"value":true}]","input":{"address":"696E70757431","amount":12345,"sequence":250}}]}`, - chainID) + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[31,{"args":"{"PermFlag":%v,"Address":"%s","Permission":1,"Value":true}","input":{"address":"%s","amount":12345,"sequence":250}}]}`, + chainID, ptypes.SetBase, permsTx.PermArgs.Address.String(), permsTx.Input.Address.String()) if signStr != expected { t.Errorf("Got unexpected sign string for PermsTx. Expected:\n%v\nGot:\n%v", expected, signStr) } } -func TestEncodeTxDecodeTx(t *testing.T) { - inputAddress := []byte{1, 2, 3, 4, 5} - outputAddress := []byte{5, 4, 3, 2, 1} - amount := int64(2) - sequence := 3 - tx := &SendTx{ - Inputs: []*TxInput{{ - Address: inputAddress, - Amount: amount, - Sequence: sequence, - }}, - Outputs: []*TxOutput{{ - Address: outputAddress, - Amount: amount, - }}, - } - txBytes, err := EncodeTx(tx) - if err != nil { - t.Fatal(err) - } - txOut, err := DecodeTx(txBytes) - assert.NoError(t, err, "DecodeTx error") - assert.Equal(t, tx, txOut) +func TestTxWrapper_MarshalJSON(t *testing.T) { + toAddress := makeAddress("contract1") + callTx := &CallTx{ + Input: &TxInput{ + Address: makeAddress("input1"), + Amount: 12345, + Sequence: 67890, + }, + Address: &toAddress, + GasLimit: 111, + Fee: 222, + Data: []byte("data1"), + } + testTxMarshalJSON(t, callTx) +} + +func TestNewPermissionsTxWithNonce(t *testing.T) { + privateKey := acm.PrivateKeyFromSecret("Shhh...") + + args := ptypes.SetBaseArgs(privateKey.PublicKey().Address(), ptypes.HasRole, true) + permTx := NewPermissionsTxWithNonce(privateKey.PublicKey(), args, 1) + testTxMarshalJSON(t, permTx) +} + +func testTxMarshalJSON(t *testing.T, tx Tx) { + txw := &Wrapper{Tx: tx} + bs, err := json.Marshal(txw) + require.NoError(t, err) + txwOut := new(Wrapper) + err = json.Unmarshal(bs, txwOut) + require.NoError(t, err) + bsOut, err := json.Marshal(txwOut) + require.NoError(t, err) + assert.Equal(t, string(bs), string(bsOut)) } /* func TestDupeoutTxSignable(t *testing.T) { - privAcc := acm.GenPrivAccount() - partSetHeader := types.PartSetHeader{Total: 10, Hash: []byte("partsethash")} + privAcc := acm.GeneratePrivateAccount() + partSetHeader := types.PartSetHeader{Total: 10, Hash: makeAddress("partsethash")} voteA := &types.Vote{ Height: 10, Round: 2, Type: types.VoteTypePrevote, - BlockHash: []byte("myblockhash"), + BlockHash: makeAddress("myblockhash"), BlockPartsHeader: partSetHeader, } - sig := privAcc.Sign(chainID, voteA) + sig := privAcc acm.ChainSign(chainID, voteA) voteA.Signature = sig.(crypto.SignatureEd25519) voteB := voteA.Copy() - voteB.BlockHash = []byte("myotherblockhash") - sig = privAcc.Sign(chainID, voteB) + voteB.BlockHash = makeAddress("myotherblockhash") + sig = privAcc acm.ChainSign(chainID, voteB) voteB.Signature = sig.(crypto.SignatureEd25519) dupeoutTx := &DupeoutTx{ - Address: []byte("address1"), + Address: makeAddress("address1"), VoteA: *voteA, VoteB: *voteB, } signBytes := acm.SignBytes(chainID, dupeoutTx) signStr := string(signBytes) - expected := Fmt(`{"chain_id":"%s","tx":[20,{"address":"6164647265737331","vote_a":%v,"vote_b":%v}]}`, + expected := fmt.Sprintf(`{"chain_id":"%s","tx":[20,{"address":"%s","vote_a":%v,"vote_b":%v}]}`, chainID, *voteA, *voteB) if signStr != expected { t.Errorf("Got unexpected sign string for DupeoutTx") diff --git a/txs/tx_utils.go b/txs/tx_utils.go index 6e1519b6850d1594bd7c25497059bd6dcbf80b61..c680a7f478807e2d704242dd7c665d3794524382 100644 --- a/txs/tx_utils.go +++ b/txs/tx_utils.go @@ -18,15 +18,11 @@ import ( "fmt" acm "github.com/hyperledger/burrow/account" - ptypes "github.com/hyperledger/burrow/permission/types" + ptypes "github.com/hyperledger/burrow/permission" "github.com/tendermint/go-crypto" ) -type AccountGetter interface { - GetAccount(addr []byte) *acm.Account -} - //---------------------------------------------------------------------------- // SendTx interface for adding inputs/outputs and adding signatures @@ -37,28 +33,31 @@ func NewSendTx() *SendTx { } } -func (tx *SendTx) AddInput(st AccountGetter, pubkey crypto.PubKey, amt int64) error { +func (tx *SendTx) AddInput(st acm.Getter, pubkey acm.PublicKey, amt uint64) error { addr := pubkey.Address() - acc := st.GetAccount(addr) + acc, err := st.GetAccount(addr) + if err != nil { + return err + } if acc == nil { - return fmt.Errorf("Invalid address %X from pubkey %X", addr, pubkey) + return fmt.Errorf("invalid address %s from pubkey %s", addr, pubkey) } - return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1) + return tx.AddInputWithNonce(pubkey, amt, acc.Sequence()+1) } -func (tx *SendTx) AddInputWithNonce(pubkey crypto.PubKey, amt int64, nonce int) error { +func (tx *SendTx) AddInputWithNonce(pubkey acm.PublicKey, amt uint64, sequence uint64) error { addr := pubkey.Address() tx.Inputs = append(tx.Inputs, &TxInput{ Address: addr, Amount: amt, - Sequence: nonce, - Signature: crypto.SignatureEd25519{}, + Sequence: sequence, + Signature: crypto.SignatureEd25519{}.Wrap(), PubKey: pubkey, }) return nil } -func (tx *SendTx) AddOutput(addr []byte, amt int64) error { +func (tx *SendTx) AddOutput(addr acm.Address, amt uint64) error { tx.Outputs = append(tx.Outputs, &TxOutput{ Address: addr, Amount: amt, @@ -66,36 +65,41 @@ func (tx *SendTx) AddOutput(addr []byte, amt int64) error { return nil } -func (tx *SendTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error { +func (tx *SendTx) SignInput(chainID string, i int, privAccount acm.PrivateAccount) 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) + tx.Inputs[i].PubKey = privAccount.PublicKey() + tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx) return nil } //---------------------------------------------------------------------------- // CallTx interface for creating tx -func NewCallTx(st AccountGetter, from crypto.PubKey, to, data []byte, amt, gasLimit, fee int64) (*CallTx, error) { +func NewCallTx(st acm.Getter, from acm.PublicKey, to *acm.Address, data []byte, + amt, gasLimit, fee uint64) (*CallTx, error) { + addr := from.Address() - acc := st.GetAccount(addr) + acc, err := st.GetAccount(addr) + if err != nil { + return nil, err + } if acc == nil { - return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from) + return nil, fmt.Errorf("invalid address %s from pubkey %s", addr, from) } - nonce := acc.Sequence + 1 + nonce := acc.Sequence() + 1 return NewCallTxWithNonce(from, to, data, amt, gasLimit, fee, nonce), nil } -func NewCallTxWithNonce(from crypto.PubKey, to, data []byte, amt, gasLimit, fee int64, nonce int) *CallTx { - addr := from.Address() +func NewCallTxWithNonce(from acm.PublicKey, to *acm.Address, data []byte, + amt, gasLimit, fee, sequence uint64) *CallTx { input := &TxInput{ - Address: addr, + Address: from.Address(), Amount: amt, - Sequence: nonce, - Signature: crypto.SignatureEd25519{}, + Sequence: sequence, + Signature: crypto.SignatureEd25519{}.Wrap(), PubKey: from, } @@ -108,32 +112,34 @@ func NewCallTxWithNonce(from crypto.PubKey, to, data []byte, amt, gasLimit, fee } } -func (tx *CallTx) Sign(chainID string, privAccount *acm.PrivAccount) { - tx.Input.PubKey = privAccount.PubKey - tx.Input.Signature = privAccount.Sign(chainID, tx) +func (tx *CallTx) Sign(chainID string, privAccount acm.PrivateAccount) { + tx.Input.PubKey = privAccount.PublicKey() + tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx) } //---------------------------------------------------------------------------- // NameTx interface for creating tx -func NewNameTx(st AccountGetter, from crypto.PubKey, name, data string, amt, fee int64) (*NameTx, error) { +func NewNameTx(st acm.Getter, from acm.PublicKey, name, data string, amt, fee uint64) (*NameTx, error) { addr := from.Address() - acc := st.GetAccount(addr) + acc, err := st.GetAccount(addr) + if err != nil { + return nil, err + } if acc == nil { - return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from) + return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from) } - nonce := acc.Sequence + 1 + nonce := acc.Sequence() + 1 return NewNameTxWithNonce(from, name, data, amt, fee, nonce), nil } -func NewNameTxWithNonce(from crypto.PubKey, name, data string, amt, fee int64, nonce int) *NameTx { - addr := from.Address() +func NewNameTxWithNonce(from acm.PublicKey, name, data string, amt, fee, sequence uint64) *NameTx { input := &TxInput{ - Address: addr, + Address: from.Address(), Amount: amt, - Sequence: nonce, - Signature: crypto.SignatureEd25519{}, + Sequence: sequence, + Signature: crypto.SignatureEd25519{}.Wrap(), PubKey: from, } @@ -145,48 +151,46 @@ func NewNameTxWithNonce(from crypto.PubKey, name, data string, amt, fee int64, n } } -func (tx *NameTx) Sign(chainID string, privAccount *acm.PrivAccount) { - tx.Input.PubKey = privAccount.PubKey - tx.Input.Signature = privAccount.Sign(chainID, tx) +func (tx *NameTx) Sign(chainID string, privAccount acm.PrivateAccount) { + tx.Input.PubKey = privAccount.PublicKey() + tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx) } //---------------------------------------------------------------------------- // BondTx interface for adding inputs/outputs and adding signatures -func NewBondTx(pubkey crypto.PubKey) (*BondTx, error) { - pubkeyEd, ok := pubkey.(crypto.PubKeyEd25519) - if !ok { - return nil, fmt.Errorf("Pubkey must be ed25519") - } +func NewBondTx(pubkey acm.PublicKey) (*BondTx, error) { return &BondTx{ - PubKey: pubkeyEd, + PubKey: pubkey, Inputs: []*TxInput{}, UnbondTo: []*TxOutput{}, }, nil } -func (tx *BondTx) AddInput(st AccountGetter, pubkey crypto.PubKey, amt int64) error { +func (tx *BondTx) AddInput(st acm.Getter, pubkey acm.PublicKey, amt uint64) error { addr := pubkey.Address() - acc := st.GetAccount(addr) + acc, err := st.GetAccount(addr) + if err != nil { + return err + } if acc == nil { - return fmt.Errorf("Invalid address %X from pubkey %X", addr, pubkey) + return fmt.Errorf("Invalid address %s from pubkey %s", addr, pubkey) } - return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1) + return tx.AddInputWithNonce(pubkey, amt, acc.Sequence()+uint64(1)) } -func (tx *BondTx) AddInputWithNonce(pubkey crypto.PubKey, amt int64, nonce int) error { - addr := pubkey.Address() +func (tx *BondTx) AddInputWithNonce(pubkey acm.PublicKey, amt uint64, sequence uint64) error { tx.Inputs = append(tx.Inputs, &TxInput{ - Address: addr, + Address: pubkey.Address(), Amount: amt, - Sequence: nonce, - Signature: crypto.SignatureEd25519{}, + Sequence: sequence, + Signature: crypto.SignatureEd25519{}.Wrap(), PubKey: pubkey, }) return nil } -func (tx *BondTx) AddOutput(addr []byte, amt int64) error { +func (tx *BondTx) AddOutput(addr acm.Address, amt uint64) error { tx.UnbondTo = append(tx.UnbondTo, &TxOutput{ Address: addr, Amount: amt, @@ -194,74 +198,71 @@ func (tx *BondTx) AddOutput(addr []byte, amt int64) error { return nil } -func (tx *BondTx) SignBond(chainID string, privAccount *acm.PrivAccount) error { - sig := privAccount.Sign(chainID, tx) - sigEd, ok := sig.(crypto.SignatureEd25519) - if !ok { - return fmt.Errorf("Bond signer must be ED25519") - } - tx.Signature = sigEd +func (tx *BondTx) SignBond(chainID string, privAccount acm.PrivateAccount) error { + tx.Signature = acm.ChainSign(privAccount, chainID, tx) return nil } -func (tx *BondTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error { +func (tx *BondTx) SignInput(chainID string, i int, privAccount acm.PrivateAccount) 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) + tx.Inputs[i].PubKey = privAccount.PublicKey() + tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx) return nil } //---------------------------------------------------------------------- // UnbondTx interface for creating tx -func NewUnbondTx(addr []byte, height int) *UnbondTx { +func NewUnbondTx(addr acm.Address, height int) *UnbondTx { return &UnbondTx{ Address: addr, Height: height, } } -func (tx *UnbondTx) Sign(chainID string, privAccount *acm.PrivAccount) { - tx.Signature = privAccount.Sign(chainID, tx).(crypto.SignatureEd25519) +func (tx *UnbondTx) Sign(chainID string, privAccount acm.PrivateAccount) { + tx.Signature = acm.ChainSign(privAccount, chainID, tx) } //---------------------------------------------------------------------- // RebondTx interface for creating tx -func NewRebondTx(addr []byte, height int) *RebondTx { +func NewRebondTx(addr acm.Address, height int) *RebondTx { return &RebondTx{ Address: addr, Height: height, } } -func (tx *RebondTx) Sign(chainID string, privAccount *acm.PrivAccount) { - tx.Signature = privAccount.Sign(chainID, tx).(crypto.SignatureEd25519) +func (tx *RebondTx) Sign(chainID string, privAccount acm.PrivateAccount) { + tx.Signature = acm.ChainSign(privAccount, chainID, tx) } //---------------------------------------------------------------------------- // PermissionsTx interface for creating tx -func NewPermissionsTx(st AccountGetter, from crypto.PubKey, args ptypes.PermArgs) (*PermissionsTx, error) { +func NewPermissionsTx(st acm.Getter, from acm.PublicKey, args *ptypes.PermArgs) (*PermissionsTx, error) { addr := from.Address() - acc := st.GetAccount(addr) + acc, err := st.GetAccount(addr) + if err != nil { + return nil, err + } if acc == nil { - return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from) + return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from) } - nonce := acc.Sequence + 1 + nonce := acc.Sequence() + 1 return NewPermissionsTxWithNonce(from, args, nonce), nil } -func NewPermissionsTxWithNonce(from crypto.PubKey, args ptypes.PermArgs, nonce int) *PermissionsTx { - addr := from.Address() +func NewPermissionsTxWithNonce(from acm.PublicKey, args *ptypes.PermArgs, sequence uint64) *PermissionsTx { input := &TxInput{ - Address: addr, + Address: from.Address(), Amount: 1, // NOTE: amounts can't be 0 ... - Sequence: nonce, - Signature: crypto.SignatureEd25519{}, + Sequence: sequence, + Signature: crypto.SignatureEd25519{}.Wrap(), PubKey: from, } @@ -271,7 +272,7 @@ func NewPermissionsTxWithNonce(from crypto.PubKey, args ptypes.PermArgs, nonce i } } -func (tx *PermissionsTx) Sign(chainID string, privAccount *acm.PrivAccount) { - tx.Input.PubKey = privAccount.PubKey - tx.Input.Signature = privAccount.Sign(chainID, tx) +func (tx *PermissionsTx) Sign(chainID string, privAccount acm.PrivateAccount) { + tx.Input.PubKey = privAccount.PublicKey() + tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx) }