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" "io/ioutil"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "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/smartcontract/context"
"github.com/nspcc-dev/neo-go/pkg/wallet" "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() pub := priv.PublicKey()
sign := priv.Sign(tx.GetSignedPart()) sign := priv.Sign(tx.GetSignedPart())
scCtx := context.NewParameterContext("Neo.Core.ContractTransaction", tx) 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 fmt.Errorf("can't add signature: %w", err)
} }
return Save(scCtx, filename) 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) 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 signerFound := false
for i := range tx.Signers { for i := range tx.Signers {
if tx.Signers[i].Account == acc.Contract.ScriptHash() { if tx.Signers[i].Account == ch {
signerFound = true signerFound = true
break break
} }
@ -49,7 +53,7 @@ func signStoredTransaction(ctx *cli.Context) error {
priv := acc.PrivateKey() priv := acc.PrivateKey()
sign := priv.Sign(tx.GetSignedPart()) 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) return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
} }
if out := ctx.String("out"); out != "" { 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. // AddSignature adds a signature for the specified contract and public key.
func (c *ParameterContext) AddSignature(ctr *wallet.Contract, pub *keys.PublicKey, sig []byte) error { func (c *ParameterContext) AddSignature(h util.Uint160, ctr *wallet.Contract, pub *keys.PublicKey, sig []byte) error {
item := c.getItemForContract(ctr.ScriptHash(), ctr) item := c.getItemForContract(h, ctr)
if _, pubs, ok := vm.ParseMultiSigContract(ctr.Script); ok { if _, pubs, ok := vm.ParseMultiSigContract(ctr.Script); ok {
if item.GetSignature(pub) != nil { if item.GetSignature(pub) != nil {
return errors.New("signature is already added") return errors.New("signature is already added")
@ -121,10 +121,11 @@ func (c *ParameterContext) AddSignature(ctr *wallet.Contract, pub *keys.PublicKe
index = i index = i
} }
} }
if index == -1 { if index != -1 {
item.Parameters[index].Value = sig
} else if !ctr.Deployed {
return errors.New("missing signature parameter") return errors.New("missing signature parameter")
} }
item.Parameters[index].Value = sig
return nil return nil
} }
@ -137,8 +138,12 @@ func (c *ParameterContext) getItemForContract(h util.Uint160, ctr *wallet.Contra
for i := range params { for i := range params {
params[i].Type = ctr.Parameters[i].Type params[i].Type = ctr.Parameters[i].Type
} }
script := ctr.Script
if ctr.Deployed {
script = nil
}
item = &Item{ item = &Item{
Script: ctr.Script, Script: script,
Parameters: params, Parameters: params,
Signatures: make(map[string][]byte), Signatures: make(map[string][]byte),
} }

View file

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