From ec6317d6433bd75bd4659d3fd22ba9272f5fa4cc Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Fri, 22 Jan 2021 15:11:57 +0300 Subject: [PATCH] core: allow to sign with arbitrary signer Related #1677. --- pkg/core/helper_test.go | 74 +++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index e85d8112a..0fff13650 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -433,8 +433,10 @@ func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.A return nil } +// Signer can be either bool or *wallet.Account. +// In the first case `true` means sign by committee, `false` means sign by validators. func prepareContractMethodInvokeGeneric(chain *Blockchain, sysfee int64, - hash util.Uint160, method string, isCommittee bool, args ...interface{}) (*transaction.Transaction, error) { + hash util.Uint160, method string, signer interface{}, args ...interface{}) (*transaction.Transaction, error) { w := io.NewBufBinWriter() emit.AppCall(w.BinWriter, hash, method, callflag.All, args...) if w.Err != nil { @@ -444,12 +446,21 @@ func prepareContractMethodInvokeGeneric(chain *Blockchain, sysfee int64, tx := transaction.New(chain.GetConfig().Magic, script, sysfee) tx.ValidUntilBlock = chain.blockHeight + 1 var err error - if isCommittee { - addSigners(testchain.CommitteeScriptHash(), tx) - err = testchain.SignTxCommittee(chain, tx) - } else { - addSigners(neoOwner, tx) - err = testchain.SignTx(chain, tx) + switch s := signer.(type) { + case bool: + if s { + addSigners(testchain.CommitteeScriptHash(), tx) + err = testchain.SignTxCommittee(chain, tx) + } else { + addSigners(neoOwner, tx) + err = testchain.SignTx(chain, tx) + } + case *wallet.Account: + signTxWithAccounts(chain, tx, s) + case []*wallet.Account: + signTxWithAccounts(chain, tx, s...) + default: + panic("invalid signer") } if err != nil { return nil, err @@ -457,6 +468,30 @@ func prepareContractMethodInvokeGeneric(chain *Blockchain, sysfee int64, return tx, nil } +func signTxWithAccounts(chain *Blockchain, tx *transaction.Transaction, accs ...*wallet.Account) { + scope := transaction.CalledByEntry + for _, acc := range accs { + tx.Signers = append(tx.Signers, transaction.Signer{ + Account: acc.PrivateKey().GetScriptHash(), + Scopes: scope, + }) + scope = transaction.Global + } + size := io.GetVarSize(tx) + for _, acc := range accs { + netFee, sizeDelta := fee.Calculate(chain.GetBaseExecFee(), acc.Contract.Script) + size += sizeDelta + tx.NetworkFee += netFee + } + tx.NetworkFee += int64(size) * chain.FeePerByte() + + for _, acc := range accs { + if err := acc.SignTx(tx); err != nil { + panic(err) + } + } +} + func prepareContractMethodInvoke(chain *Blockchain, sysfee int64, hash util.Uint160, method string, args ...interface{}) (*transaction.Transaction, error) { return prepareContractMethodInvokeGeneric(chain, sysfee, hash, @@ -486,9 +521,9 @@ func invokeContractMethod(chain *Blockchain, sysfee int64, hash util.Uint160, me } func invokeContractMethodGeneric(chain *Blockchain, sysfee int64, hash util.Uint160, method string, - isCommittee bool, args ...interface{}) (*state.AppExecResult, error) { + signer interface{}, args ...interface{}) (*state.AppExecResult, error) { tx, err := prepareContractMethodInvokeGeneric(chain, sysfee, hash, - method, isCommittee, args...) + method, signer, args...) if err != nil { return nil, err } @@ -509,26 +544,7 @@ func invokeContractMethodBy(t *testing.T, chain *Blockchain, signer *wallet.Acco require.NoError(t, err) require.Equal(t, vm.HaltState, res[0].VMState) require.Equal(t, 0, len(res[0].Stack)) - - w := io.NewBufBinWriter() - emit.AppCall(w.BinWriter, hash, method, callflag.All, args...) - if w.Err != nil { - return nil, w.Err - } - script := w.Bytes() - tx := transaction.New(chain.GetConfig().Magic, script, sysfee) - tx.ValidUntilBlock = chain.blockHeight + 1 - tx.Signers = []transaction.Signer{ - {Account: signer.PrivateKey().PublicKey().GetScriptHash()}, - } - tx.NetworkFee = netfee - err = signer.SignTx(tx) - require.NoError(t, err) - require.NoError(t, chain.AddBlock(chain.newBlock(tx))) - - res, err = chain.GetAppExecResults(tx.Hash(), trigger.Application) - require.NoError(t, err) - return &res[0], nil + return invokeContractMethodGeneric(chain, sysfee, hash, method, signer, args...) } func transferTokenFromMultisigAccount(t *testing.T, chain *Blockchain, to, tokenHash util.Uint160, amount int64, additionalArgs ...interface{}) *transaction.Transaction {