From b82b6f0346a5c0990260d932cec0b17968cf1793 Mon Sep 17 00:00:00 2001 From: Silas Davis <silas@monax.io> Date: Tue, 3 Apr 2018 22:47:05 +0100 Subject: [PATCH] Remove panic from ChainSign and return error. Unify transactioning signing under a single interface method. Signed-off-by: Silas Davis <silas@monax.io> --- account/private_account.go | 6 +-- blockchain/blockchain.go | 19 +++----- execution/execution_test.go | 77 +++++++++++++++---------------- execution/transactor.go | 38 ++------------- rpc/tm/integration/client_test.go | 5 +- rpc/tm/integration/shared.go | 8 ++-- txs/bond_tx.go | 26 +++++++---- txs/call_tx.go | 15 ++++-- txs/name_tx.go | 15 ++++-- txs/permission_tx.go | 16 +++++-- txs/rebond_tx.go | 13 +++++- txs/send_tx.go | 17 +++++-- txs/tx.go | 1 + txs/unbond_tx.go | 13 +++++- 14 files changed, 144 insertions(+), 125 deletions(-) diff --git a/account/private_account.go b/account/private_account.go index 120adf54..0ef0bed6 100644 --- a/account/private_account.go +++ b/account/private_account.go @@ -86,12 +86,12 @@ func (pa ConcretePrivateAccount) Sign(msg []byte) (Signature, error) { return pa.PrivateKey.Sign(msg) } -func ChainSign(signer Signer, chainID string, o Signable) Signature { +func ChainSign(signer Signer, chainID string, o Signable) (Signature, error) { sig, err := signer.Sign(SignBytes(chainID, o)) if err != nil { - panic(err) + return Signature{}, err } - return sig + return sig, nil } func (pa *ConcretePrivateAccount) String() string { diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 26e3eb5b..c81f4524 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -132,12 +132,9 @@ func NewBlockchain(db dbm.DB, genesisDoc *genesis.GenesisDoc) *blockchain { } root := NewRoot(genesisDoc) return &blockchain{ - db: db, - root: root, - tip: &tip{ - lastBlockTime: root.genesisDoc.GenesisTime, - appHashAfterLastBlock: root.genesisHash, - }, + db: db, + root: root, + tip: NewTip(genesisDoc.ChainID(), root.genesisDoc.GenesisTime, root.genesisHash), validators: validators, } } @@ -164,14 +161,12 @@ func NewRoot(genesisDoc *genesis.GenesisDoc) *root { } } -// Create -func NewTip(chainID string, lastBlockHeight uint64, lastBlockTime time.Time, lastBlockHash []byte, appHashAfterLastBlock []byte) *tip { +// Create genesis Tip +func NewTip(chainID string, genesisTime time.Time, genesisHash []byte) *tip { return &tip{ chainID: chainID, - lastBlockHeight: lastBlockHeight, - lastBlockTime: lastBlockTime, - lastBlockHash: lastBlockHash, - appHashAfterLastBlock: appHashAfterLastBlock, + lastBlockTime: genesisTime, + appHashAfterLastBlock: genesisHash, } } diff --git a/execution/execution_test.go b/execution/execution_test.go index 9e20db6b..6401c8fc 100644 --- a/execution/execution_test.go +++ b/execution/execution_test.go @@ -192,7 +192,7 @@ func TestSendFails(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[1].Address(), 5) - tx.SignInput(testChainID, 0, users[0]) + require.NoError(t, tx.Sign(testChainID, users[0])) if err := batchCommitter.Execute(tx); err == nil { t.Fatal("Expected error") } else { @@ -205,7 +205,7 @@ func TestSendFails(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[4].Address(), 5) - tx.SignInput(testChainID, 0, users[2]) + require.NoError(t, tx.Sign(testChainID, users[2])) if err := batchCommitter.Execute(tx); err == nil { t.Fatal("Expected error") } else { @@ -218,7 +218,7 @@ func TestSendFails(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[4].Address(), 5) - tx.SignInput(testChainID, 0, users[3]) + require.NoError(t, tx.Sign(testChainID, users[3])) if err := batchCommitter.Execute(tx); err == nil { t.Fatal("Expected error") } else { @@ -234,7 +234,7 @@ func TestSendFails(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[6].Address(), 5) - tx.SignInput(testChainID, 0, users[3]) + require.NoError(t, tx.Sign(testChainID, users[3])) if err := batchCommitter.Execute(tx); err == nil { t.Fatal("Expected error") } else { @@ -366,7 +366,7 @@ func TestSendPermission(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[1].Address(), 5) - tx.SignInput(testChainID, 0, users[0]) + require.NoError(t, tx.Sign(testChainID, users[0])) if err := batchCommitter.Execute(tx); err != nil { t.Fatal("Transaction failed", err) } @@ -380,8 +380,7 @@ func TestSendPermission(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[2].Address(), 10) - tx.SignInput(testChainID, 0, users[0]) - tx.SignInput(testChainID, 1, users[1]) + require.NoError(t, tx.Sign(testChainID, users[:2]...)) if err := batchCommitter.Execute(tx); err == nil { t.Fatal("Expected error") } else { @@ -651,7 +650,7 @@ func TestCreateAccountPermission(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[6].Address(), 5) - tx.SignInput(testChainID, 0, users[0]) + require.NoError(t, tx.Sign(testChainID, users[0])) if err := batchCommitter.Execute(tx); err != nil { t.Fatal("Transaction failed", err) } @@ -665,8 +664,7 @@ func TestCreateAccountPermission(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[7].Address(), 10) - tx.SignInput(testChainID, 0, users[0]) - tx.SignInput(testChainID, 1, users[1]) + require.NoError(t, tx.Sign(testChainID, users[:2]...)) if err := batchCommitter.Execute(tx); err == nil { t.Fatal("Expected error") } else { @@ -683,8 +681,7 @@ func TestCreateAccountPermission(t *testing.T) { } tx.AddOutput(users[7].Address(), 4) tx.AddOutput(users[4].Address(), 6) - tx.SignInput(testChainID, 0, users[0]) - tx.SignInput(testChainID, 1, users[1]) + require.NoError(t, tx.Sign(testChainID, users[:2]...)) if err := batchCommitter.Execute(tx); err == nil { t.Fatal("Expected error") } else { @@ -703,8 +700,7 @@ func TestCreateAccountPermission(t *testing.T) { t.Fatal(err) } tx.AddOutput(users[7].Address(), 10) - tx.SignInput(testChainID, 0, users[0]) - tx.SignInput(testChainID, 1, users[1]) + require.NoError(t, tx.Sign(testChainID, users[:2]...)) if err := batchCommitter.Execute(tx); err != nil { t.Fatal("Unexpected error", err) } @@ -719,8 +715,7 @@ func TestCreateAccountPermission(t *testing.T) { } tx.AddOutput(users[7].Address(), 7) tx.AddOutput(users[4].Address(), 3) - tx.SignInput(testChainID, 0, users[0]) - tx.SignInput(testChainID, 1, users[1]) + require.NoError(t, tx.Sign(testChainID, users[:2]...)) if err := batchCommitter.Execute(tx); err != nil { t.Fatal("Unexpected error", err) } @@ -1002,7 +997,7 @@ func TestTxSequence(t *testing.T) { tx := txs.NewSendTx() tx.AddInputWithSequence(acc0PubKey, 1, sequence) tx.AddOutput(acc1.Address(), 1) - tx.Inputs[0].Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) stateCopy := state.Copy(dbm.NewMemDB()) err := execTxWithState(stateCopy, tx) if i == 1 { @@ -1216,19 +1211,19 @@ func TestNameTxs(t *testing.T) { // Test creating a contract from futher down the call stack /* contract Factory { - address a; - function create() returns (address){ - a = new PreFactory(); - return a; - } + address a; + function create() returns (address){ + a = new PreFactory(); + return a; + } } contract PreFactory{ - address a; - function create(Factory c) returns (address) { - a = c.create(); - return a; - } + address a; + function create(Factory c) returns (address) { + a = c.create(); + return a; + } } */ @@ -1270,7 +1265,7 @@ func TestCreates(t *testing.T) { Data: createData, } - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err := execTxWithState(state, tx) if err != nil { t.Errorf("Got error in executing call transaction, %v", err) @@ -1294,7 +1289,7 @@ func TestCreates(t *testing.T) { Data: createData, } - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err = execTxWithState(state, tx) if err != nil { t.Errorf("Got error in executing call transaction, %v", err) @@ -1311,9 +1306,9 @@ func TestCreates(t *testing.T) { /* contract Caller { - function send(address x){ - x.send(msg.value); - } + function send(address x){ + x.send(msg.value); + } } */ var callerCode, _ = hex.DecodeString("60606040526000357c0100000000000000000000000000000000000000000000000000000000900480633e58c58c146037576035565b005b604b6004808035906020019091905050604d565b005b8073ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f19350505050505b5056") @@ -1349,7 +1344,7 @@ func TestContractSend(t *testing.T) { Data: sendData, } - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err := execTxWithState(state, tx) if err != nil { t.Errorf("Got error in executing call transaction, %v", err) @@ -1391,7 +1386,7 @@ func TestMerklePanic(t *testing.T) { }, } - tx.Inputs[0].Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err := execTxWithState(stateSendTx, tx) if err != nil { t.Errorf("Got error in executing send transaction, %v", err) @@ -1417,7 +1412,7 @@ func TestMerklePanic(t *testing.T) { GasLimit: 10, } - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err := execTxWithState(stateCallTx, tx) if err != nil { t.Errorf("Got error in executing call transaction, %v", err) @@ -1458,7 +1453,7 @@ func TestTxs(t *testing.T) { }, } - tx.Inputs[0].Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err := execTxWithState(stateSendTx, tx) if err != nil { t.Errorf("Got error in executing send transaction, %v", err) @@ -1492,7 +1487,7 @@ func TestTxs(t *testing.T) { GasLimit: 10, } - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err := execTxWithState(stateCallTx, tx) if err != nil { t.Errorf("Got error in executing call transaction, %v", err) @@ -1543,7 +1538,7 @@ proof-of-work chain as proof of what happened while they were gone ` Data: entryData, } - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err := execTxWithState(stateNameTx, tx) if err != nil { @@ -1566,7 +1561,7 @@ proof-of-work chain as proof of what happened while they were gone ` // test a bad string tx.Data = string([]byte{0, 1, 2, 3, 127, 128, 129, 200, 251}) tx.Input.Sequence += 1 - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) err = execTxWithState(stateNameTx, tx) if _, ok := err.(txs.ErrTxInvalidString); !ok { t.Errorf("Expected invalid string error. Got: %s", err.Error()) @@ -1648,7 +1643,7 @@ func TestSelfDestruct(t *testing.T) { // send call tx with no data, cause self-destruct tx := txs.NewCallTxWithSequence(acc0PubKey, addressPtr(acc1), nil, sendingAmount, 1000, 0, acc0.Sequence()+1) - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) // we use cache instead of execTxWithState so we can run the tx twice exe := NewBatchCommitter(state, testChainID, bcm.NewBlockchain(nil, testGenesisDoc), event.NewNoOpPublisher(), logger) @@ -1659,7 +1654,7 @@ func TestSelfDestruct(t *testing.T) { // if we do it again, we won't get an error, but the self-destruct // shouldn't happen twice and the caller should lose fee tx.Input.Sequence += 1 - tx.Input.Signature = acm.ChainSign(privAccounts[0], testChainID, tx) + require.NoError(t, tx.Sign(testChainID, privAccounts[0])) if err := exe.Execute(tx); err != nil { t.Errorf("Got error in executing call transaction, %v", err) } diff --git a/execution/transactor.go b/execution/transactor.go index 952aaab0..a875fe6b 100644 --- a/execution/transactor.go +++ b/execution/transactor.go @@ -346,7 +346,6 @@ func (trans *Transactor) SendAndHold(privKey []byte, toAddress acm.Address, amou } func (trans *Transactor) TransactNameReg(privKey []byte, name, data string, amount, fee uint64) (*txs.Receipt, error) { - if len(privKey) != 64 { return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey)) } @@ -377,40 +376,9 @@ func (trans *Transactor) TransactNameReg(privKey []byte, name, data string, amou // Sign a transaction func (trans *Transactor) SignTx(tx txs.Tx, signingAccounts []acm.SigningAccount) (txs.Tx, error) { // more checks? - - chainID := trans.tip.ChainID() - switch tx.(type) { - case *txs.NameTx: - nameTx := tx.(*txs.NameTx) - nameTx.Input.PublicKey = signingAccounts[0].PublicKey() - nameTx.Input.Signature = acm.ChainSign(signingAccounts[0], chainID, nameTx) - case *txs.SendTx: - sendTx := tx.(*txs.SendTx) - for i, input := range sendTx.Inputs { - input.PublicKey = signingAccounts[i].PublicKey() - input.Signature = acm.ChainSign(signingAccounts[i], chainID, sendTx) - } - case *txs.CallTx: - callTx := tx.(*txs.CallTx) - callTx.Input.PublicKey = signingAccounts[0].PublicKey() - callTx.Input.Signature = acm.ChainSign(signingAccounts[0], chainID, callTx) - case *txs.BondTx: - bondTx := tx.(*txs.BondTx) - // the first privaccount corresponds to the BondTx pub key. - // the rest to the inputs - bondTx.Signature = acm.ChainSign(signingAccounts[0], chainID, bondTx) - for i, input := range bondTx.Inputs { - input.PublicKey = signingAccounts[i+1].PublicKey() - input.Signature = acm.ChainSign(signingAccounts[i+1], chainID, bondTx) - } - case *txs.UnbondTx: - unbondTx := tx.(*txs.UnbondTx) - unbondTx.Signature = acm.ChainSign(signingAccounts[0], chainID, unbondTx) - case *txs.RebondTx: - rebondTx := tx.(*txs.RebondTx) - rebondTx.Signature = acm.ChainSign(signingAccounts[0], chainID, rebondTx) - default: - return nil, fmt.Errorf("Object is not a proper transaction: %v\n", tx) + err := tx.Sign(trans.tip.ChainID(), signingAccounts...) + if err != nil { + return nil, err } return tx, nil } diff --git a/rpc/tm/integration/client_test.go b/rpc/tm/integration/client_test.go index a827524f..268953bc 100644 --- a/rpc/tm/integration/client_test.go +++ b/rpc/tm/integration/client_test.go @@ -59,14 +59,15 @@ func TestBroadcastTx(t *testing.T) { require.NoError(t, err) assert.False(t, receipt.CreatesContract, "This tx should not create a contract") assert.NotEmpty(t, receipt.TxHash, "Failed to compute tx hash") - n, errp := new(int), new(error) - buf := new(bytes.Buffer) + + buf, n, errp := new(bytes.Buffer), new(int), new(error) hasher := ripemd160.New() tx.WriteSignBytes(genesisDoc.ChainID(), buf, n, errp) assert.NoError(t, *errp) txSignBytes := buf.Bytes() hasher.Write(txSignBytes) txHashExpected := hasher.Sum(nil) + if bytes.Compare(receipt.TxHash, txHashExpected) != 0 { t.Fatalf("The receipt hash '%x' does not equal the ripemd160 hash of the "+ "transaction signed bytes calculated in the test: '%x'", diff --git a/rpc/tm/integration/shared.go b/rpc/tm/integration/shared.go index 0844aa2b..bd7fb72e 100644 --- a/rpc/tm/integration/shared.go +++ b/rpc/tm/integration/shared.go @@ -56,7 +56,7 @@ const ( ) // Enable logger output during tests -var debugLogging = true +var debugLogging = false // global variables for use across all tests var ( @@ -165,7 +165,7 @@ func makeDefaultSendTx(t *testing.T, client tm_client.RPCClient, addr acm.Addres func makeDefaultSendTxSigned(t *testing.T, client tm_client.RPCClient, addr acm.Address, amt uint64) *txs.SendTx { tx := makeDefaultSendTx(t, client, addr, amt) - tx.SignInput(genesisDoc.ChainID(), 0, privateAccounts[0]) + require.NoError(t, tx.Sign(genesisDoc.ChainID(), privateAccounts[0])) return tx } @@ -174,14 +174,14 @@ func makeDefaultCallTx(t *testing.T, client tm_client.RPCClient, addr *acm.Addre sequence := getSequence(t, client, privateAccounts[0].Address()) tx := txs.NewCallTxWithSequence(privateAccounts[0].PublicKey(), addr, code, amt, gasLim, fee, sequence+1) - tx.Sign(genesisDoc.ChainID(), privateAccounts[0]) + require.NoError(t, tx.Sign(genesisDoc.ChainID(), privateAccounts[0])) return tx } func makeDefaultNameTx(t *testing.T, client tm_client.RPCClient, name, value string, amt, fee uint64) *txs.NameTx { sequence := getSequence(t, client, privateAccounts[0].Address()) tx := txs.NewNameTxWithSequence(privateAccounts[0].PublicKey(), name, value, amt, fee, sequence+1) - tx.Sign(genesisDoc.ChainID(), privateAccounts[0]) + require.NoError(t, tx.Sign(genesisDoc.ChainID(), privateAccounts[0])) return tx } diff --git a/txs/bond_tx.go b/txs/bond_tx.go index cbb4bf8a..b6537092 100644 --- a/txs/bond_tx.go +++ b/txs/bond_tx.go @@ -90,16 +90,22 @@ func (tx *BondTx) AddOutput(addr acm.Address, amt uint64) error { return nil } -func (tx *BondTx) SignBond(chainID string, privAccount acm.SigningAccount) error { - tx.Signature = acm.ChainSign(privAccount, chainID, tx) - return nil -} - -func (tx *BondTx) SignInput(chainID string, i int, privAccount acm.SigningAccount) error { - if i >= len(tx.Inputs) { - return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs)) +func (tx *BondTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error { + if len(signingAccounts) != len(tx.Inputs)+1 { + return fmt.Errorf("BondTx expects %v SigningAccounts but got %v", len(tx.Inputs)+1, + len(signingAccounts)) + } + var err error + tx.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx) + if err != nil { + return fmt.Errorf("could not sign %v: %v", tx, err) + } + for i := 1; i <= len(signingAccounts); i++ { + tx.Inputs[i].PublicKey = signingAccounts[i].PublicKey() + tx.Inputs[i].Signature, err = acm.ChainSign(signingAccounts[i], chainID, tx) + if err != nil { + return fmt.Errorf("could not sign tx %v input %v: %v", tx, tx.Inputs[i], err) + } } - tx.Inputs[i].PublicKey = privAccount.PublicKey() - tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx) return nil } diff --git a/txs/call_tx.go b/txs/call_tx.go index ff568aef..234972cd 100644 --- a/txs/call_tx.go +++ b/txs/call_tx.go @@ -55,9 +55,18 @@ func NewCallTxWithSequence(from acm.PublicKey, to *acm.Address, data []byte, } } -func (tx *CallTx) Sign(chainID string, privAccount acm.SigningAccount) { - tx.Input.PublicKey = privAccount.PublicKey() - tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx) +func (tx *CallTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error { + if len(signingAccounts) != 1 { + return fmt.Errorf("CallTx expects a single SigningAccount for its single Input but %v were provieded", + len(signingAccounts)) + } + var err error + tx.Input.PublicKey = signingAccounts[0].PublicKey() + tx.Input.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx) + if err != nil { + return fmt.Errorf("could not sign %v: %v", tx, err) + } + return nil } func (tx *CallTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { diff --git a/txs/name_tx.go b/txs/name_tx.go index c00b6839..a9143ab3 100644 --- a/txs/name_tx.go +++ b/txs/name_tx.go @@ -56,9 +56,18 @@ func NewNameTxWithSequence(from acm.PublicKey, name, data string, amt, fee, sequ } } -func (tx *NameTx) Sign(chainID string, signingAccount acm.SigningAccount) { - tx.Input.PublicKey = signingAccount.PublicKey() - tx.Input.Signature = acm.ChainSign(signingAccount, chainID, tx) +func (tx *NameTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error { + if len(signingAccounts) != 1 { + return fmt.Errorf("NameTx expects a single SigningAccount for its single Input but %v were provieded", + len(signingAccounts)) + } + var err error + tx.Input.PublicKey = signingAccounts[0].PublicKey() + tx.Input.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx) + if err != nil { + return fmt.Errorf("could not sign %v: %v", tx, err) + } + return nil } func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { diff --git a/txs/permission_tx.go b/txs/permission_tx.go index 755dbfe3..a1ed4969 100644 --- a/txs/permission_tx.go +++ b/txs/permission_tx.go @@ -46,10 +46,20 @@ func NewPermissionsTxWithSequence(from acm.PublicKey, args snatives.PermArgs, se } } -func (tx *PermissionsTx) Sign(chainID string, privAccount acm.SigningAccount) { - tx.Input.PublicKey = privAccount.PublicKey() - tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx) +func (tx *PermissionsTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error { + if len(signingAccounts) != 1 { + return fmt.Errorf("PermissionsTx expects a single SigningAccount for its single Input but %v were provieded", + len(signingAccounts)) + } + var err error + tx.Input.PublicKey = signingAccounts[0].PublicKey() + tx.Input.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx) + if err != nil { + return fmt.Errorf("could not sign %v: %v", tx, err) + } + return nil } + func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { 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) diff --git a/txs/rebond_tx.go b/txs/rebond_tx.go index ec13498b..93b95898 100644 --- a/txs/rebond_tx.go +++ b/txs/rebond_tx.go @@ -24,8 +24,17 @@ func NewRebondTx(addr acm.Address, height int) *RebondTx { } } -func (tx *RebondTx) Sign(chainID string, privAccount acm.SigningAccount) { - tx.Signature = acm.ChainSign(privAccount, chainID, tx) +func (tx *RebondTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error { + if len(signingAccounts) != 1 { + return fmt.Errorf("RebondTx expects a single SigningAccount for its signature but %v were provieded", + len(signingAccounts)) + } + var err error + tx.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx) + if err != nil { + return fmt.Errorf("could not sign %v: %v", tx, err) + } + return nil } func (tx *RebondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { diff --git a/txs/send_tx.go b/txs/send_tx.go index 06c651a3..02c7039c 100644 --- a/txs/send_tx.go +++ b/txs/send_tx.go @@ -86,11 +86,18 @@ func (tx *SendTx) AddOutput(addr acm.Address, amt uint64) error { return nil } -func (tx *SendTx) SignInput(chainID string, i int, privAccount acm.SigningAccount) error { - if i >= len(tx.Inputs) { - return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs)) +func (tx *SendTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error { + if len(signingAccounts) != len(tx.Inputs) { + return fmt.Errorf("SendTx has %v Inputs but was provided with %v SigningAccounts", len(tx.Inputs), + len(signingAccounts)) + } + var err error + for i, signingAccount := range signingAccounts { + tx.Inputs[i].PublicKey = signingAccount.PublicKey() + tx.Inputs[i].Signature, err = acm.ChainSign(signingAccount, chainID, tx) + if err != nil { + return fmt.Errorf("could not sign tx %v input %v: %v", tx, tx.Inputs[i], err) + } } - tx.Inputs[i].PublicKey = privAccount.PublicKey() - tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx) return nil } diff --git a/txs/tx.go b/txs/tx.go index bfcf3ac1..3e7f0419 100644 --- a/txs/tx.go +++ b/txs/tx.go @@ -84,6 +84,7 @@ type Tx interface { String() string GetInputs() []TxInput Hash(chainID string) []byte + Sign(chainID string, signingAccounts ...acm.SigningAccount) error } type Encoder interface { diff --git a/txs/unbond_tx.go b/txs/unbond_tx.go index 2411eaf9..ab016a0d 100644 --- a/txs/unbond_tx.go +++ b/txs/unbond_tx.go @@ -24,8 +24,17 @@ func NewUnbondTx(addr acm.Address, height int) *UnbondTx { } } -func (tx *UnbondTx) Sign(chainID string, privAccount acm.SigningAccount) { - tx.Signature = acm.ChainSign(privAccount, chainID, tx) +func (tx *UnbondTx) Sign(chainID string, signingAccounts ...acm.SigningAccount) error { + if len(signingAccounts) != 1 { + return fmt.Errorf("UnbondTx expects a single SigningAccount for its signature but %v were provieded", + len(signingAccounts)) + } + var err error + tx.Signature, err = acm.ChainSign(signingAccounts[0], chainID, tx) + if err != nil { + return fmt.Errorf("could not sign %v: %v", tx, err) + } + return nil } func (tx *UnbondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) { -- GitLab