diff --git a/app/app_test.go b/app/app_test.go index 31c300b6e6..b4e1200228 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -21,8 +21,8 @@ type appTest struct { t *testing.T chainID string app *Basecoin - accsIn []types.PrivAccount - accsOut []types.PrivAccount + accIn types.PrivAccount + accOut types.PrivAccount } func newAppTest(t *testing.T) *appTest { @@ -34,10 +34,10 @@ func newAppTest(t *testing.T) *appTest { return at } -// make a tx sending 5mycoin from each accsIn to accsOut -func (ap *appTest) getTx(seq int) *types.SendTx { - tx := types.GetTx(seq, ap.accsIn, ap.accsOut) - types.SignTx(ap.chainID, tx, ap.accsIn) +// make a tx sending 5mycoin from each accIn to accOut +func (at *appTest) getTx(seq int) *types.SendTx { + tx := types.GetTx(seq, at.accOut, at.accIn) + types.SignTx(at.chainID, tx, at.accIn) return tx } @@ -51,8 +51,8 @@ func (at *appTest) acc2app(acc types.Account) { // reset the in and out accs to be one account each with 7mycoin func (at *appTest) reset() { - at.accsIn = types.MakeAccs("input0") - at.accsOut = types.MakeAccs("output0") + at.accIn = types.MakeAcc("input0") + at.accOut = types.MakeAcc("output0") eyesCli := eyes.NewLocalClient("", 0) at.app = NewBasecoin(eyesCli) @@ -60,8 +60,8 @@ func (at *appTest) reset() { res := at.app.SetOption("base/chain_id", at.chainID) require.EqualValues(at.t, res, "Success") - at.acc2app(at.accsIn[0].Account) - at.acc2app(at.accsOut[0].Account) + at.acc2app(at.accIn.Account) + at.acc2app(at.accOut.Account) resabci := at.app.Commit() require.True(at.t, resabci.IsOK(), resabci) @@ -70,8 +70,8 @@ func (at *appTest) reset() { // returns the final balance and expected balance for input and output accounts func (at *appTest) exec(tx *types.SendTx, checkTx bool) (res abci.Result, inputGot, inputExp, outputGot, outputExpected types.Coins) { - initBalFoo := at.app.GetState().GetAccount(at.accsIn[0].Account.PubKey.Address()).Balance - initBalBar := at.app.GetState().GetAccount(at.accsOut[0].Account.PubKey.Address()).Balance + initBalFoo := at.app.GetState().GetAccount(at.accIn.Account.PubKey.Address()).Balance + initBalBar := at.app.GetState().GetAccount(at.accOut.Account.PubKey.Address()).Balance txBytes := []byte(wire.BinaryBytes(struct{ types.Tx }{tx})) if checkTx { @@ -80,8 +80,8 @@ func (at *appTest) exec(tx *types.SendTx, checkTx bool) (res abci.Result, inputG res = at.app.DeliverTx(txBytes) } - endBalFoo := at.app.GetState().GetAccount(at.accsIn[0].Account.PubKey.Address()).Balance - endBalBar := at.app.GetState().GetAccount(at.accsOut[0].Account.PubKey.Address()).Balance + endBalFoo := at.app.GetState().GetAccount(at.accIn.Account.PubKey.Address()).Balance + endBalBar := at.app.GetState().GetAccount(at.accOut.Account.PubKey.Address()).Balance decrBalFooExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) return res, endBalFoo, initBalFoo.Minus(decrBalFooExp), endBalBar, initBalBar.Plus(tx.Outputs[0].Coins) } @@ -111,8 +111,8 @@ func TestSetOption(t *testing.T) { assert.EqualValues(app.GetState().GetChainID(), chainID) assert.EqualValues(res, "Success") - accsIn := types.MakeAccs("input0") - accsInBytes, err := json.Marshal(accsIn[0].Account) + accIn := types.MakeAcc("input0") + accsInBytes, err := json.Marshal(accIn.Account) assert.Nil(err) res = app.SetOption("base/account", string(accsInBytes)) assert.EqualValues(res, "Success") @@ -133,8 +133,8 @@ func TestTx(t *testing.T) { at := newAppTest(t) //Bad Balance - at.accsIn[0].Balance = types.Coins{{"mycoin", 2}} - at.acc2app(at.accsIn[0].Account) + at.accIn.Balance = types.Coins{{"mycoin", 2}} + at.acc2app(at.accIn.Account) res, _, _, _, _ := at.exec(at.getTx(1), true) assert.True(res.IsErr(), fmt.Sprintf("ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)) res, inGot, inExp, outGot, outExp := at.exec(at.getTx(1), false) @@ -164,7 +164,7 @@ func TestQuery(t *testing.T) { resQueryPreCommit := at.app.Query(abci.RequestQuery{ Path: "/account", - Data: at.accsIn[0].Account.PubKey.Address(), + Data: at.accIn.Account.PubKey.Address(), }) res = at.app.Commit() @@ -172,7 +172,7 @@ func TestQuery(t *testing.T) { resQueryPostCommit := at.app.Query(abci.RequestQuery{ Path: "/account", - Data: at.accsIn[0].Account.PubKey.Address(), + Data: at.accIn.Account.PubKey.Address(), }) fmt.Println(resQueryPreCommit) fmt.Println(resQueryPostCommit) diff --git a/state/execution_test.go b/state/execution_test.go index 210ff4e2b5..f2a0073956 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -14,13 +14,11 @@ import ( // test environment is a bunch of lists of accountns type execTest struct { - chainID string - store types.KVStore - state *State - accsFoo []types.PrivAccount - accsBar []types.PrivAccount - accsFooBar []types.PrivAccount - accsDup []types.PrivAccount + chainID string + store types.KVStore + state *State + accIn types.PrivAccount + accOut types.PrivAccount } func newExecTest() *execTest { @@ -31,29 +29,29 @@ func newExecTest() *execTest { return et } -func (et *execTest) signTx(tx *types.SendTx, accsIn []types.PrivAccount) { - types.SignTx(et.chainID, tx, accsIn) +func (et *execTest) signTx(tx *types.SendTx, accsIn ...types.PrivAccount) { + types.SignTx(et.chainID, tx, accsIn...) } -// make tx from accsIn to et.accsBar -func (et *execTest) getTx(seq int, accsIn []types.PrivAccount) *types.SendTx { - return types.GetTx(seq, accsIn, et.accsBar) +// make tx from accsIn to et.accOut +func (et *execTest) getTx(seq int, accsIn ...types.PrivAccount) *types.SendTx { + return types.GetTx(seq, et.accOut, accsIn...) } // returns the final balance and expected balance for input and output accounts func (et *execTest) exec(tx *types.SendTx, checkTx bool) (res abci.Result, inGot, inExp, outGot, outExp types.Coins) { - initBalFoo := et.state.GetAccount(et.accsFoo[0].Account.PubKey.Address()).Balance - initBalBar := et.state.GetAccount(et.accsBar[0].Account.PubKey.Address()).Balance + initBalIn := et.state.GetAccount(et.accIn.Account.PubKey.Address()).Balance + initBalOut := et.state.GetAccount(et.accOut.Account.PubKey.Address()).Balance res = ExecTx(et.state, nil, tx, checkTx, nil) - endBalFoo := et.state.GetAccount(et.accsFoo[0].Account.PubKey.Address()).Balance - endBalBar := et.state.GetAccount(et.accsBar[0].Account.PubKey.Address()).Balance - decrBalFooExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) - return res, endBalFoo, initBalFoo.Minus(decrBalFooExp), endBalBar, initBalBar.Plus(tx.Outputs[0].Coins) + endBalIn := et.state.GetAccount(et.accIn.Account.PubKey.Address()).Balance + endBalOut := et.state.GetAccount(et.accOut.Account.PubKey.Address()).Balance + decrBalInExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) //expected decrease in balance In + return res, endBalIn, initBalIn.Minus(decrBalInExp), endBalOut, initBalOut.Plus(tx.Outputs[0].Coins) } -func (et *execTest) acc2State(accs []types.PrivAccount) { +func (et *execTest) acc2State(accs ...types.PrivAccount) { for _, acc := range accs { et.state.SetAccount(acc.Account.PubKey.Address(), &acc.Account) } @@ -61,10 +59,8 @@ func (et *execTest) acc2State(accs []types.PrivAccount) { //reset everything. state is empty func (et *execTest) reset() { - et.accsFoo = types.MakeAccs("foo") - et.accsBar = types.MakeAccs("bar") - et.accsFooBar = types.MakeAccs("foo", "bar") - et.accsDup = types.MakeAccs("foo", "foo", "foo") + et.accIn = types.MakeAcc("foo") + et.accOut = types.MakeAcc("bar") et.store = types.NewMemKVStore() et.state = NewState(et.store) @@ -84,18 +80,18 @@ func TestGetInputs(t *testing.T) { //test getInputs for registered, non-registered account et.reset() - txs := types.Accs2TxInputs(et.accsFoo, 1) + txs := types.Accs2TxInputs(1, et.accIn) acc, res = getInputs(et.state, txs) assert.True(res.IsErr(), "getInputs: expected error when using getInput with non-registered Input") - et.acc2State(et.accsFoo) + et.acc2State(et.accIn) acc, res = getInputs(et.state, txs) assert.True(res.IsOK(), "getInputs: expected to getInput from registered Input") //test sending duplicate accounts et.reset() - et.acc2State(et.accsDup) - txs = types.Accs2TxInputs(et.accsDup, 1) + et.acc2State(et.accIn, et.accIn, et.accIn) + txs = types.Accs2TxInputs(1, et.accIn, et.accIn, et.accIn) acc, res = getInputs(et.state, txs) assert.True(res.IsErr(), "getInputs: expected error when sending duplicate accounts") } @@ -111,16 +107,16 @@ func TestGetOrMakeOutputs(t *testing.T) { //test sending duplicate accounts et.reset() - txs := types.Accs2TxOutputs(et.accsDup) + txs := types.Accs2TxOutputs(et.accIn, et.accIn, et.accIn) _, res = getOrMakeOutputs(et.state, nil, txs) assert.True(res.IsErr(), "getOrMakeOutputs: expected error when sending duplicate accounts") //test sending to existing/new account account et.reset() - txs1 := types.Accs2TxOutputs(et.accsFoo) - txs2 := types.Accs2TxOutputs(et.accsBar) + txs1 := types.Accs2TxOutputs(et.accIn) + txs2 := types.Accs2TxOutputs(et.accOut) - et.acc2State(et.accsFoo) + et.acc2State(et.accIn) _, res = getOrMakeOutputs(et.state, nil, txs1) assert.True(res.IsOK(), "getOrMakeOutputs: error when sending to existing account") @@ -138,7 +134,7 @@ func TestValidateInputsBasic(t *testing.T) { et := newExecTest() //validate input basic - txs := types.Accs2TxInputs(et.accsFoo, 1) + txs := types.Accs2TxInputs(1, et.accIn) res := validateInputsBasic(txs) assert.True(res.IsOK(), fmt.Sprintf("validateInputsBasic: expected no error on good tx input. Error: %v", res.Error())) @@ -153,9 +149,9 @@ func TestValidateInputsAdvanced(t *testing.T) { et := newExecTest() //validate inputs advanced - txs := et.getTx(1, et.accsFooBar) + txs := et.getTx(1, et.accIn, et.accOut) - et.acc2State(et.accsFooBar) + et.acc2State(et.accIn, et.accOut) accMap, res := getInputs(et.state, txs.Inputs) assert.True(res.IsOK(), fmt.Sprintf("validateInputsAdvanced: error retrieving accMap. Error: %v", res.Error())) signBytes := txs.SignBytes(et.chainID) @@ -165,7 +161,7 @@ func TestValidateInputsAdvanced(t *testing.T) { assert.True(res.IsErr(), "validateInputsAdvanced: expected an error on an unsigned tx input") //test good case sgined - et.signTx(txs, et.accsFooBar) + et.signTx(txs, et.accIn, et.accOut) totalCoins, res = validateInputsAdvanced(accMap, signBytes, txs.Inputs) assert.True(res.IsOK(), fmt.Sprintf("validateInputsAdvanced: expected no error on good tx input. Error: %v", res.Error())) assert.True(totalCoins.IsEqual(txs.Inputs[0].Coins.Plus(txs.Inputs[1].Coins)), "ValidateInputsAdvanced: transaction total coins are not equal") @@ -176,31 +172,31 @@ func TestValidateInputAdvanced(t *testing.T) { et := newExecTest() //validate input advanced - txs := et.getTx(1, et.accsFooBar) + txs := et.getTx(1, et.accIn, et.accOut) - et.acc2State(et.accsFooBar) + et.acc2State(et.accIn, et.accOut) signBytes := txs.SignBytes(et.chainID) //unsigned case - res := validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) + res := validateInputAdvanced(&et.accIn.Account, signBytes, txs.Inputs[0]) assert.True(res.IsErr(), "validateInputAdvanced: expected error on tx input without signature") //good signed case - et.signTx(txs, et.accsFooBar) - res = validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) + et.signTx(txs, et.accIn, et.accOut) + res = validateInputAdvanced(&et.accIn.Account, signBytes, txs.Inputs[0]) assert.True(res.IsOK(), fmt.Sprintf("validateInputAdvanced: expected no error on good tx input. Error: %v", res.Error())) //bad sequence case - et.accsFooBar[0].Sequence = 2 - et.signTx(txs, et.accsFooBar) - res = validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) + et.accIn.Sequence = 2 + et.signTx(txs, et.accIn, et.accOut) + res = validateInputAdvanced(&et.accIn.Account, signBytes, txs.Inputs[0]) assert.True(res.IsErr(), "validateInputAdvanced: expected error on tx input with bad sequence") - et.accsFooBar[0].Account.Sequence = 1 //restore sequence + et.accIn.Sequence = 1 //restore sequence //bad balance case - et.accsFooBar[1].Balance = types.Coins{{"mycoin", 2}} - et.signTx(txs, et.accsFooBar) - res = validateInputAdvanced(&et.accsFooBar[0].Account, signBytes, txs.Inputs[0]) + et.accOut.Balance = types.Coins{{"mycoin", 2}} + et.signTx(txs, et.accIn, et.accOut) + res = validateInputAdvanced(&et.accIn.Account, signBytes, txs.Inputs[0]) assert.True(res.IsErr(), "validateInputAdvanced: expected error on tx input with insufficient funds") } @@ -209,7 +205,7 @@ func TestValidateOutputsAdvanced(t *testing.T) { et := newExecTest() //validateOutputsBasic - txs := types.Accs2TxOutputs(et.accsFoo) + txs := types.Accs2TxOutputs(et.accIn) res := validateOutputsBasic(txs) assert.True(res.IsOK(), fmt.Sprintf("validateOutputsBasic: expected no error on good tx input. Error: %v", res.Error())) @@ -223,7 +219,7 @@ func TestSumOutput(t *testing.T) { et := newExecTest() //SumOutput - txs := types.Accs2TxOutputs(et.accsFooBar) + txs := types.Accs2TxOutputs(et.accIn, et.accOut) total := sumOutputs(txs) assert.True(total.IsEqual(txs[0].Coins.Plus(txs[1].Coins)), "sumOutputs: total coins are not equal") } @@ -233,28 +229,28 @@ func TestAdjustBy(t *testing.T) { et := newExecTest() //adjustByInputs/adjustByOutputs - //sending transaction from Foo to Bar - initBalFoo := et.accsFooBar[0].Account.Balance - initBalBar := et.accsFooBar[1].Account.Balance - et.acc2State(et.accsFooBar) + //sending transaction from accIn to accOut + initBalIn := et.accIn.Account.Balance + initBalOut := et.accOut.Account.Balance + et.acc2State(et.accIn, et.accOut) - txIn := types.Accs2TxInputs(et.accsFoo, 1) - txOut := types.Accs2TxOutputs(et.accsBar) + txIn := types.Accs2TxInputs(1, et.accIn) + txOut := types.Accs2TxOutputs(et.accOut) accMap, _ := getInputs(et.state, txIn) accMap, _ = getOrMakeOutputs(et.state, accMap, txOut) adjustByInputs(et.state, accMap, txIn) adjustByOutputs(et.state, accMap, txOut, false) - endBalFoo := accMap[string(et.accsFooBar[0].Account.PubKey.Address())].Balance - endBalBar := accMap[string(et.accsFooBar[1].Account.PubKey.Address())].Balance - decrBalFoo := initBalFoo.Minus(endBalFoo) - incrBalBar := endBalBar.Minus(initBalBar) + endBalIn := accMap[string(et.accIn.Account.PubKey.Address())].Balance + endBalOut := accMap[string(et.accOut.Account.PubKey.Address())].Balance + decrBalIn := initBalIn.Minus(endBalIn) + incrBalOut := endBalOut.Minus(initBalOut) - assert.True(decrBalFoo.IsEqual(txIn[0].Coins), - fmt.Sprintf("adjustByInputs: total coins are not equal. diff: %v, tx: %v", decrBalFoo.String(), txIn[0].Coins.String())) - assert.True(incrBalBar.IsEqual(txOut[0].Coins), - fmt.Sprintf("adjustByInputs: total coins are not equal. diff: %v, tx: %v", incrBalBar.String(), txOut[0].Coins.String())) + assert.True(decrBalIn.IsEqual(txIn[0].Coins), + fmt.Sprintf("adjustByInputs: total coins are not equal. diff: %v, tx: %v", decrBalIn.String(), txIn[0].Coins.String())) + assert.True(incrBalOut.IsEqual(txOut[0].Coins), + fmt.Sprintf("adjustByInputs: total coins are not equal. diff: %v, tx: %v", incrBalOut.String(), txOut[0].Coins.String())) } @@ -263,34 +259,42 @@ func TestExecTx(t *testing.T) { et := newExecTest() //ExecTx - txs := et.getTx(1, et.accsFoo) - et.acc2State(et.accsFoo) - et.acc2State(et.accsBar) - et.signTx(txs, et.accsFoo) + txs := et.getTx(1, et.accIn) + et.acc2State(et.accIn) + et.acc2State(et.accOut) + et.signTx(txs, et.accIn) //Bad Balance - et.accsFoo[0].Balance = types.Coins{{"mycoin", 2}} - et.acc2State(et.accsFoo) + et.accIn.Balance = types.Coins{{"mycoin", 2}} + et.acc2State(et.accIn) res, _, _, _, _ := et.exec(txs, true) - assert.True(res.IsErr(), fmt.Sprintf("ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)) - res, foo, fooexp, bar, barexp := et.exec(txs, false) - assert.True(res.IsErr(), fmt.Sprintf("ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res)) - assert.False(foo.IsEqual(fooexp), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, foo: %v, fooExp: %v", foo, fooexp)) - assert.False(bar.IsEqual(barexp), fmt.Sprintf("ExecTx/Bad DeliverTx: shouldn't be equal, bar: %v, barExp: %v", bar, barexp)) + assert.True(res.IsErr(), + fmt.Sprintf("ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)) + + res, balIn, balInExp, balOut, balOutExp := et.exec(txs, false) + assert.True(res.IsErr(), + fmt.Sprintf("ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res)) + assert.False(balIn.IsEqual(balInExp), + fmt.Sprintf("ExecTx/Bad DeliverTx: balance shouldn't be equal for accIn: got %v, expected: %v", balIn, balInExp)) + assert.False(balOut.IsEqual(balOutExp), + fmt.Sprintf("ExecTx/Bad DeliverTx: balance shouldn't be equal for accOut: got %v, expected: %v", balOut, balOutExp)) //Regular CheckTx et.reset() - et.acc2State(et.accsFoo) - et.acc2State(et.accsBar) + et.acc2State(et.accIn) + et.acc2State(et.accOut) res, _, _, _, _ = et.exec(txs, true) assert.True(res.IsOK(), fmt.Sprintf("ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res)) //Regular DeliverTx et.reset() - et.acc2State(et.accsFoo) - et.acc2State(et.accsBar) - res, foo, fooexp, bar, barexp = et.exec(txs, false) - assert.True(res.IsOK(), fmt.Sprintf("ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res)) - assert.True(foo.IsEqual(fooexp), fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in input coins, foo: %v, fooExp: %v", foo, fooexp)) - assert.True(bar.IsEqual(barexp), fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in output coins, bar: %v, barExp: %v", bar, barexp)) + et.acc2State(et.accIn) + et.acc2State(et.accOut) + res, balIn, balInExp, balOut, balOutExp = et.exec(txs, false) + assert.True(res.IsOK(), + fmt.Sprintf("ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res)) + assert.True(balIn.IsEqual(balInExp), + fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in input balance, got: %v, expected: %v", balIn, balInExp)) + assert.True(balOut.IsEqual(balOutExp), + fmt.Sprintf("ExecTx/good DeliverTx: unexpected change in output balance, got: %v, expected: %v", balOut, balOutExp)) } diff --git a/types/coin.go b/types/coin.go index 05c3111aa6..e34f7d1bdb 100644 --- a/types/coin.go +++ b/types/coin.go @@ -41,6 +41,10 @@ func ParseCoin(str string) (Coin, error) { type Coins []Coin func (coins Coins) String() string { + if len(coins) == 0 { + return "" + } + out := "" for _, coin := range coins { out += fmt.Sprintf("%v,", coin.String()) diff --git a/types/test_helpers.go b/types/test_helpers.go index 070c4b739d..81e639ee10 100644 --- a/types/test_helpers.go +++ b/types/test_helpers.go @@ -46,16 +46,22 @@ func RandAccounts(num int, minAmount int64, maxAmount int64) []PrivAccount { ///////////////////////////////////////////////////////////////// -func MakeAccs(secrets ...string) (accs []PrivAccount) { - for _, secret := range secrets { - privAcc := PrivAccountFromSecret(secret) - privAcc.Account.Balance = Coins{{"mycoin", 7}} - accs = append(accs, privAcc) - } - return +//func MakeAccs(secrets ...string) (accs []PrivAccount) { +// for _, secret := range secrets { +// privAcc := PrivAccountFromSecret(secret) +// privAcc.Account.Balance = Coins{{"mycoin", 7}} +// accs = append(accs, privAcc) +// } +// return +//} + +func MakeAcc(secret string) PrivAccount { + privAcc := PrivAccountFromSecret(secret) + privAcc.Account.Balance = Coins{{"mycoin", 7}} + return privAcc } -func Accs2TxInputs(accs []PrivAccount, seq int) []TxInput { +func Accs2TxInputs(seq int, accs ...PrivAccount) []TxInput { var txs []TxInput for _, acc := range accs { tx := NewTxInput( @@ -68,7 +74,7 @@ func Accs2TxInputs(accs []PrivAccount, seq int) []TxInput { } //turn a list of accounts into basic list of transaction outputs -func Accs2TxOutputs(accs []PrivAccount) []TxOutput { +func Accs2TxOutputs(accs ...PrivAccount) []TxOutput { var txs []TxOutput for _, acc := range accs { tx := TxOutput{ @@ -79,18 +85,18 @@ func Accs2TxOutputs(accs []PrivAccount) []TxOutput { return txs } -func GetTx(seq int, accsIn, accsOut []PrivAccount) *SendTx { +func GetTx(seq int, accOut PrivAccount, accsIn ...PrivAccount) *SendTx { txs := &SendTx{ Gas: 0, Fee: Coin{"mycoin", 1}, - Inputs: Accs2TxInputs(accsIn, seq), - Outputs: Accs2TxOutputs(accsOut), + Inputs: Accs2TxInputs(seq, accsIn...), + Outputs: Accs2TxOutputs(accOut), } return txs } -func SignTx(chainID string, tx *SendTx, accs []PrivAccount) { +func SignTx(chainID string, tx *SendTx, accs ...PrivAccount) { signBytes := tx.SignBytes(chainID) for i, _ := range tx.Inputs { tx.Inputs[i].Signature = crypto.SignatureS{accs[i].Sign(signBytes)}