cli/wallet: allow to cosign with a contract

Contracts have empty verification script and their hash is
calculated differently.
This commit is contained in:
Evgeniy Stratonikov 2021-03-04 14:14:25 +03:00
parent 8a4b97171a
commit 106c27782e
4 changed files with 28 additions and 14 deletions

View file

@ -6,6 +6,7 @@ import (
"io/ioutil"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
"github.com/nspcc-dev/neo-go/pkg/wallet"
)
@ -22,7 +23,11 @@ func InitAndSave(tx *transaction.Transaction, acc *wallet.Account, filename stri
pub := priv.PublicKey()
sign := priv.Sign(tx.GetSignedPart())
scCtx := context.NewParameterContext("Neo.Core.ContractTransaction", tx)
if err := scCtx.AddSignature(acc.Contract, pub, sign); err != nil {
h, err := address.StringToUint160(acc.Address)
if err != nil {
return fmt.Errorf("invalid address: %s", acc.Address)
}
if err := scCtx.AddSignature(h, acc.Contract, pub, sign); err != nil {
return fmt.Errorf("can't add signature: %w", err)
}
return Save(scCtx, filename)

View file

@ -36,9 +36,13 @@ func signStoredTransaction(ctx *cli.Context) error {
return cli.NewExitError("verifiable item is not a transaction", 1)
}
ch, err := address.StringToUint160(acc.Address)
if err != nil {
return cli.NewExitError(fmt.Errorf("wallet contains invalid account: %s", acc.Address), 1)
}
signerFound := false
for i := range tx.Signers {
if tx.Signers[i].Account == acc.Contract.ScriptHash() {
if tx.Signers[i].Account == ch {
signerFound = true
break
}
@ -49,7 +53,7 @@ func signStoredTransaction(ctx *cli.Context) error {
priv := acc.PrivateKey()
sign := priv.Sign(tx.GetSignedPart())
if err := c.AddSignature(acc.Contract, priv.PublicKey(), sign); err != nil {
if err := c.AddSignature(ch, acc.Contract, priv.PublicKey(), sign); err != nil {
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
}
if out := ctx.String("out"); out != "" {

View file

@ -72,8 +72,8 @@ func (c *ParameterContext) GetWitness(h util.Uint160) (*transaction.Witness, err
}
// AddSignature adds a signature for the specified contract and public key.
func (c *ParameterContext) AddSignature(ctr *wallet.Contract, pub *keys.PublicKey, sig []byte) error {
item := c.getItemForContract(ctr.ScriptHash(), ctr)
func (c *ParameterContext) AddSignature(h util.Uint160, ctr *wallet.Contract, pub *keys.PublicKey, sig []byte) error {
item := c.getItemForContract(h, ctr)
if _, pubs, ok := vm.ParseMultiSigContract(ctr.Script); ok {
if item.GetSignature(pub) != nil {
return errors.New("signature is already added")
@ -121,10 +121,11 @@ func (c *ParameterContext) AddSignature(ctr *wallet.Contract, pub *keys.PublicKe
index = i
}
}
if index == -1 {
if index != -1 {
item.Parameters[index].Value = sig
} else if !ctr.Deployed {
return errors.New("missing signature parameter")
}
item.Parameters[index].Value = sig
return nil
}
@ -137,8 +138,12 @@ func (c *ParameterContext) getItemForContract(h util.Uint160, ctr *wallet.Contra
for i := range params {
params[i].Type = ctr.Parameters[i].Type
}
script := ctr.Script
if ctr.Deployed {
script = nil
}
item = &Item{
Script: ctr.Script,
Script: script,
Parameters: params,
Signatures: make(map[string][]byte),
}

View file

@ -35,13 +35,13 @@ func TestParameterContext_AddSignatureSimpleContract(t *testing.T) {
newParam(smartcontract.SignatureType, "parameter1"),
},
}
require.Error(t, c.AddSignature(ctr, pub, sig))
require.Error(t, c.AddSignature(ctr.ScriptHash(), ctr, pub, sig))
if item := c.Items[ctr.ScriptHash()]; item != nil {
require.Nil(t, item.Parameters[0].Value)
}
ctr.Parameters = ctr.Parameters[:0]
require.Error(t, c.AddSignature(ctr, pub, sig))
require.Error(t, c.AddSignature(ctr.ScriptHash(), ctr, pub, sig))
if item := c.Items[ctr.ScriptHash()]; item != nil {
require.Nil(t, item.Parameters[0].Value)
}
@ -52,7 +52,7 @@ func TestParameterContext_AddSignatureSimpleContract(t *testing.T) {
Script: pub.GetVerificationScript(),
Parameters: []wallet.ContractParam{newParam(smartcontract.SignatureType, "parameter0")},
}
require.NoError(t, c.AddSignature(ctr, pub, sig))
require.NoError(t, c.AddSignature(ctr.ScriptHash(), ctr, pub, sig))
item := c.Items[ctr.ScriptHash()]
require.NotNil(t, item)
require.Equal(t, sig, item.Parameters[0].Value)
@ -95,13 +95,13 @@ func TestParameterContext_AddSignatureMultisig(t *testing.T) {
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
sig := priv.Sign(data)
require.Error(t, c.AddSignature(ctr, priv.PublicKey(), sig))
require.Error(t, c.AddSignature(ctr.ScriptHash(), ctr, priv.PublicKey(), sig))
indices := []int{2, 3, 0} // random order
for _, i := range indices {
sig := privs[i].Sign(data)
require.NoError(t, c.AddSignature(ctr, pubs[i], sig))
require.Error(t, c.AddSignature(ctr, pubs[i], sig))
require.NoError(t, c.AddSignature(ctr.ScriptHash(), ctr, pubs[i], sig))
require.Error(t, c.AddSignature(ctr.ScriptHash(), ctr, pubs[i], sig))
item := c.Items[ctr.ScriptHash()]
require.NotNil(t, item)