Skip to content

Commit

Permalink
core: move transaction's sender to cosigners
Browse files Browse the repository at this point in the history
Closes #1184

Ported changes from neo-project/neo#1752
  • Loading branch information
AnnaShaleva committed Aug 4, 2020
1 parent 72e8d58 commit dae7eef
Show file tree
Hide file tree
Showing 33 changed files with 265 additions and 222 deletions.
63 changes: 35 additions & 28 deletions cli/smartcontract/smart_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,26 +148,29 @@ func NewCommands() []cli.Command {
{
Name: "invokefunction",
Usage: "invoke deployed contract on the blockchain",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] scripthash [method] [arguments...] [--] [cosigners...]",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] scripthash [method] [arguments...] [--] [signers...]",
Description: `Executes given (as a script hash) deployed script with the given method,
arguments and cosigners. See testinvokefunction documentation for the details
about parameters. It differs from testinvokefunction in that this command
sends an invocation transaction to the network.
arguments and signers. Sender is included in the list of signers by default
with FeeOnly witness scope. If you'd like to change default sender's scope,
specify it via signers parameter. See testinvokefunction documentation for
the details about parameters. It differs from testinvokefunction in that this
command sends an invocation transaction to the network.
`,
Action: invokeFunction,
Flags: invokeFunctionFlags,
},
{
Name: "testinvokefunction",
Usage: "invoke deployed contract on the blockchain (test mode)",
UsageText: "neo-go contract testinvokefunction -r endpoint scripthash [method] [arguments...] [--] [cosigners...]",
UsageText: "neo-go contract testinvokefunction -r endpoint scripthash [method] [arguments...] [--] [signers...]",
Description: `Executes given (as a script hash) deployed script with the given method,
arguments and cosigners. If no method is given "" is passed to the script, if
no arguments are given, an empty array is passed, if no cosigners are given,
no array will be passed. All of the given arguments are encapsulated into
array before invoking the script. The script thus should follow the regular
convention of smart contract arguments (method string and an array of other
arguments).
arguments and signers (sender is not included by default). If no method is given
"" is passed to the script, if no arguments are given, an empty array is
passed, if no signers are given no array is passed. If signers are specified,
the first one of them is treated as a sender. All of the given arguments are
encapsulated into array before invoking the script. The script thus should
follow the regular convention of smart contract arguments (method string and
an array of other arguments).
Arguments always do have regular Neo smart contract parameter types, either
specified explicitly or being inferred from the value. To specify the type
Expand Down Expand Up @@ -224,12 +227,15 @@ func NewCommands() []cli.Command {
* '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c' is a
key with a value of '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c'
Cosigners represent a set of Uint160 hashes with witness scopes and are used
to verify hashes in System.Runtime.CheckWitness syscall. To specify cosigners
use cosigner[:scope] syntax where
* 'cosigner' is hex-encoded 160 bit (20 byte) LE value of cosigner's address,
Signers represent a set of Uint160 hashes with witness scopes and are used
to verify hashes in System.Runtime.CheckWitness syscall. First signer is treated
as a sender. To specify signers use signer[:scope] syntax where
* 'signer' is hex-encoded 160 bit (20 byte) LE value of signer's address,
which could have '0x' prefix.
* 'scope' is a comma-separated set of cosigner's scopes, which could be:
- 'FeeOnly' - marks transaction's sender and can be used only for the
sender. Signer with this scope can't be used during the
script execution and only pays fees for the transaction.
- 'Global' - allows this witness in all contexts. This cannot be combined
with other flags.
- 'CalledByEntry' - means that this condition must hold: EntryScriptHash
Expand All @@ -240,8 +246,8 @@ func NewCommands() []cli.Command {
- 'CustomContracts' - define valid custom contract hashes for witness check.
- 'CustomGroups' - define custom pubkey for group members.
If no scopes were specified, 'Global' used as default. If no cosigners were
specified, no array will be passed. Note that scopes are properly handled by
If no scopes were specified, 'Global' used as default. If no signers were
specified, no array is passed. Note that scopes are properly handled by
neo-go RPC server only. C# implementation does not support scopes capability.
Examples:
Expand All @@ -256,9 +262,10 @@ func NewCommands() []cli.Command {
{
Name: "testinvokescript",
Usage: "Invoke compiled AVM code in NEF format on the blockchain (test mode, not creating a transaction for it)",
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [cosigners...]",
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [signers...]",
Description: `Executes given compiled AVM instructions in NEF format with the given set of
cosigners. See testinvokefunction documentation for the details about parameters.
signers not included sender by default. See testinvokefunction documentation
for the details about parameters.
`,
Action: testInvokeScript,
Flags: testInvokeScriptFlags,
Expand Down Expand Up @@ -389,7 +396,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
operation string
params = make([]smartcontract.Parameter, 0)
paramsStart = 1
cosigners []transaction.Cosigner
cosigners []transaction.Signer
cosignersStart = 0
resp *result.Invoke
acc *wallet.Account
Expand Down Expand Up @@ -493,14 +500,14 @@ func testInvokeScript(ctx *cli.Context) error {
}

args := ctx.Args()
var cosigners []transaction.Cosigner
var signers []transaction.Signer
if args.Present() {
for i, c := range args[:] {
cosigner, err := parseCosigner(c)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to parse cosigner #%d: %v", i+1, err), 1)
return cli.NewExitError(fmt.Errorf("failed to parse signer #%d: %v", i+1, err), 1)
}
cosigners = append(cosigners, cosigner)
signers = append(signers, cosigner)
}
}

Expand All @@ -512,7 +519,7 @@ func testInvokeScript(ctx *cli.Context) error {
return err
}

resp, err := c.InvokeScript(nefFile.Script, cosigners)
resp, err := c.InvokeScript(nefFile.Script, signers)
if err != nil {
return cli.NewExitError(err, 1)
}
Expand Down Expand Up @@ -659,7 +666,7 @@ func contractDeploy(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create deployment script: %v", err), 1)
}
// It doesn't require any cosigners.
// It doesn't require any signers.
invRes, err := c.InvokeScript(txScript, nil)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to test-invoke deployment script: %v", err), 1)
Expand Down Expand Up @@ -687,10 +694,10 @@ func parseContractConfig(confFile string) (ProjectConfig, error) {
return conf, nil
}

func parseCosigner(c string) (transaction.Cosigner, error) {
func parseCosigner(c string) (transaction.Signer, error) {
var (
err error
res = transaction.Cosigner{
res = transaction.Signer{
Scopes: transaction.Global,
}
)
Expand All @@ -706,7 +713,7 @@ func parseCosigner(c string) (transaction.Cosigner, error) {
if len(data) > 1 {
res.Scopes, err = transaction.ScopesFromString(data[1])
if err != nil {
return transaction.Cosigner{}, err
return transaction.Signer{}, err
}
}
return res, nil
Expand Down
7 changes: 6 additions & 1 deletion integration/performance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ func getTX(t *testing.B, wif *keys.WIF) *transaction.Transaction {

tx := transaction.New(netmode.UnitTestNet, []byte{0x51}, 1)
tx.Version = 0
tx.Sender = fromAddressHash
tx.Signers = []transaction.Signer{
{
Account: fromAddressHash,
Scopes: transaction.FeeOnly,
},
}
tx.Attributes = append(tx.Attributes,
transaction.Attribute{
Usage: transaction.DescriptionURL,
Expand Down
6 changes: 5 additions & 1 deletion pkg/consensus/consensus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,11 @@ var neoOwner = testchain.MultisigScriptHash()

func addSender(t *testing.T, txs ...*transaction.Transaction) {
for _, tx := range txs {
tx.Sender = neoOwner
tx.Signers = []transaction.Signer{
{
Account: neoOwner,
},
}
}
}

Expand Down
14 changes: 4 additions & 10 deletions pkg/core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
return errors.Errorf("policy check failed")
}
}
balance := bc.GetUtilityTokenBalance(t.Sender)
balance := bc.GetUtilityTokenBalance(t.Sender())
need := t.SystemFee + t.NetworkFee
if balance.Cmp(big.NewInt(need)) < 0 {
return errors.Errorf("insufficient funds: balance is %v, need: %v", balance, need)
Expand Down Expand Up @@ -1259,15 +1259,9 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
// to verify whether the transaction is bonafide or not.
// Golang implementation of GetScriptHashesForVerifying method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L190)
func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([]util.Uint160, error) {
hashes := make(map[util.Uint160]bool)
hashes[t.Sender] = true
for _, c := range t.Cosigners {
hashes[c.Account] = true
}
// convert hashes to []util.Uint160
hashesResult := make([]util.Uint160, 0, len(hashes))
for h := range hashes {
hashesResult = append(hashesResult, h)
hashesResult := make([]util.Uint160, len(t.Signers))
for i, s := range t.Signers {
hashesResult[i] = s.Account
}

return hashesResult, nil
Expand Down
8 changes: 4 additions & 4 deletions pkg/core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func TestGetHeader(t *testing.T) {
bc := newTestChain(t)
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.ValidUntilBlock = bc.BlockHeight() + 1
assert.Nil(t, addSender(tx))
addSigners(tx)
assert.Nil(t, signTx(bc, tx))
block := bc.newBlock(tx)
err := bc.AddBlock(block)
Expand Down Expand Up @@ -276,7 +276,7 @@ func TestSubscriptions(t *testing.T) {
emit.Syscall(script.BinWriter, "System.Runtime.Notify")
require.NoError(t, script.Err)
txGood1 := transaction.New(netmode.UnitTestNet, script.Bytes(), 0)
txGood1.Sender = neoOwner
txGood1.Signers = []transaction.Signer{{Account: neoOwner}}
txGood1.Nonce = 1
txGood1.ValidUntilBlock = 100500
require.NoError(t, signTx(bc, txGood1))
Expand All @@ -288,7 +288,7 @@ func TestSubscriptions(t *testing.T) {
emit.Opcode(script.BinWriter, opcode.THROW)
require.NoError(t, script.Err)
txBad := transaction.New(netmode.UnitTestNet, script.Bytes(), 0)
txBad.Sender = neoOwner
txBad.Signers = []transaction.Signer{{Account: neoOwner}}
txBad.Nonce = 2
txBad.ValidUntilBlock = 100500
require.NoError(t, signTx(bc, txBad))
Expand All @@ -298,7 +298,7 @@ func TestSubscriptions(t *testing.T) {
emit.Syscall(script.BinWriter, "System.Runtime.Notify")
require.NoError(t, script.Err)
txGood2 := transaction.New(netmode.UnitTestNet, script.Bytes(), 0)
txGood2.Sender = neoOwner
txGood2.Signers = []transaction.Signer{{Account: neoOwner}}
txGood2.Nonce = 3
txGood2.ValidUntilBlock = 100500
require.NoError(t, signTx(bc, txGood2))
Expand Down
50 changes: 22 additions & 28 deletions pkg/core/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,7 @@ func TestCreateBasicChain(t *testing.T) {
txMoveNeo := newNEP5Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount)
txMoveNeo.ValidUntilBlock = validUntilBlock
txMoveNeo.Nonce = getNextNonce()
txMoveNeo.Sender = neoOwner
txMoveNeo.Cosigners = []transaction.Cosigner{{
txMoveNeo.Signers = []transaction.Signer{{
Account: neoOwner,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
Expand All @@ -202,8 +201,7 @@ func TestCreateBasicChain(t *testing.T) {
txMoveGas := newNEP5Transfer(gasHash, neoOwner, priv0ScriptHash, int64(util.Fixed8FromInt64(1000)))
txMoveGas.ValidUntilBlock = validUntilBlock
txMoveGas.Nonce = getNextNonce()
txMoveGas.Sender = neoOwner
txMoveGas.Cosigners = []transaction.Cosigner{{
txMoveGas.Signers = []transaction.Signer{{
Account: neoOwner,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
Expand All @@ -212,8 +210,14 @@ func TestCreateBasicChain(t *testing.T) {
require.NoError(t, signTx(bc, txMoveGas))
b := bc.newBlock(txMoveNeo, txMoveGas)
require.NoError(t, bc.AddBlock(b))
t.Logf("txMoveNeo: %s", txMoveNeo.Hash().StringLE())
t.Logf("txMoveGas: %s", txMoveGas.Hash().StringLE())
t.Logf("Block1 hash: %s", b.Hash().StringLE())
bw := io.NewBufBinWriter()
b.EncodeBinary(bw.BinWriter)
require.NoError(t, bw.Err)
t.Logf("Block1 hex: %s", bw.Bytes())
t.Logf("txMoveNeo hash: %s", txMoveNeo.Hash().StringLE())
t.Logf("txMoveNeo hex: %s", hex.EncodeToString(txMoveNeo.Bytes()))
t.Logf("txMoveGas hash: %s", txMoveGas.Hash().StringLE())

require.True(t, bc.GetUtilityTokenBalance(priv0ScriptHash).Cmp(big.NewInt(1000*native.GASFactor)) >= 0)
// info for getblockheader rpc tests
Expand Down Expand Up @@ -245,12 +249,13 @@ func TestCreateBasicChain(t *testing.T) {
txDeploy := transaction.New(testchain.Network(), txScript, 100*native.GASFactor)
txDeploy.Nonce = getNextNonce()
txDeploy.ValidUntilBlock = validUntilBlock
txDeploy.Sender = priv0ScriptHash
txDeploy.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
require.NoError(t, addNetworkFee(bc, txDeploy, acc0))
require.NoError(t, acc0.SignTx(txDeploy))
b = bc.newBlock(txDeploy)
require.NoError(t, bc.AddBlock(b))
t.Logf("txDeploy: %s", txDeploy.Hash().StringLE())
t.Logf("Block2 hash: %s", b.Hash().StringLE())

// Now invoke this contract.
script = io.NewBufBinWriter()
Expand All @@ -259,7 +264,7 @@ func TestCreateBasicChain(t *testing.T) {
txInv := transaction.New(testchain.Network(), script.Bytes(), 1*native.GASFactor)
txInv.Nonce = getNextNonce()
txInv.ValidUntilBlock = validUntilBlock
txInv.Sender = priv0ScriptHash
txInv.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
require.NoError(t, addNetworkFee(bc, txInv, acc0))
require.NoError(t, acc0.SignTx(txInv))
b = bc.newBlock(txInv)
Expand All @@ -270,8 +275,7 @@ func TestCreateBasicChain(t *testing.T) {
txNeo0to1 := newNEP5Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), 1000)
txNeo0to1.Nonce = getNextNonce()
txNeo0to1.ValidUntilBlock = validUntilBlock
txNeo0to1.Sender = priv0ScriptHash
txNeo0to1.Cosigners = []transaction.Cosigner{
txNeo0to1.Signers = []transaction.Signer{
{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
Expand All @@ -290,14 +294,13 @@ func TestCreateBasicChain(t *testing.T) {
initTx := transaction.New(testchain.Network(), w.Bytes(), 1*native.GASFactor)
initTx.Nonce = getNextNonce()
initTx.ValidUntilBlock = validUntilBlock
initTx.Sender = priv0ScriptHash
initTx.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
require.NoError(t, addNetworkFee(bc, initTx, acc0))
require.NoError(t, acc0.SignTx(initTx))
transferTx := newNEP5Transfer(sh, sh, priv0.GetScriptHash(), 1000)
transferTx.Nonce = getNextNonce()
transferTx.ValidUntilBlock = validUntilBlock
transferTx.Sender = priv0ScriptHash
transferTx.Cosigners = []transaction.Cosigner{
transferTx.Signers = []transaction.Signer{
{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
Expand All @@ -315,8 +318,7 @@ func TestCreateBasicChain(t *testing.T) {
transferTx = newNEP5Transfer(sh, priv0.GetScriptHash(), priv1.GetScriptHash(), 123)
transferTx.Nonce = getNextNonce()
transferTx.ValidUntilBlock = validUntilBlock
transferTx.Sender = priv0ScriptHash
transferTx.Cosigners = []transaction.Cosigner{
transferTx.Signers = []transaction.Signer{
{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
Expand Down Expand Up @@ -357,16 +359,15 @@ func TestCreateBasicChain(t *testing.T) {
txSendRaw := newNEP5Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), int64(util.Fixed8FromInt64(1000)))
txSendRaw.ValidUntilBlock = validUntilBlock
txSendRaw.Nonce = getNextNonce()
txSendRaw.Sender = priv0ScriptHash
txSendRaw.Cosigners = []transaction.Cosigner{{
txSendRaw.Signers = []transaction.Signer{{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
AllowedGroups: nil,
}}
require.NoError(t, addNetworkFee(bc, txSendRaw, acc0))
require.NoError(t, acc0.SignTx(txSendRaw))
bw := io.NewBufBinWriter()
bw = io.NewBufBinWriter()
txSendRaw.EncodeBinary(bw.BinWriter)
t.Logf("sendrawtransaction: %s", hex.EncodeToString(bw.Bytes()))
}
Expand All @@ -380,16 +381,9 @@ func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Trans
return transaction.New(testchain.Network(), script, 10000000)
}

func addSender(txs ...*transaction.Transaction) error {
for _, tx := range txs {
tx.Sender = neoOwner
}
return nil
}

func addCosigners(txs ...*transaction.Transaction) {
func addSigners(txs ...*transaction.Transaction) {
for _, tx := range txs {
tx.Cosigners = []transaction.Cosigner{{
tx.Signers = []transaction.Signer{{
Account: neoOwner,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
Expand Down Expand Up @@ -424,7 +418,7 @@ func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.A
netFee, sizeDelta := CalculateNetworkFee(sender.Contract.Script)
tx.NetworkFee += netFee
size += sizeDelta
for _, cosigner := range tx.Cosigners {
for _, cosigner := range tx.Signers {
contract := bc.GetContractState(cosigner.Account)
if contract != nil {
netFee, sizeDelta = CalculateNetworkFee(contract.Script)
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/interop/runtime/witness.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) {
}

func checkScope(d dao.DAO, tx *transaction.Transaction, v vm.ScriptHashGetter, hash util.Uint160) (bool, error) {
for _, c := range tx.Cosigners {
for _, c := range tx.Signers {
if c.Account == hash {
if c.Scopes == transaction.Global {
return true, nil
Expand Down
Loading

0 comments on commit dae7eef

Please sign in to comment.