有些合约在调用时需要多个签名,其中一个是交易的发起者对支持手续费的签名,其余的都是附加签名。
在合约编写时,我们通常使用Runtime.CheckWitness(owner)来鉴权调用者地址,其中owner是允许调用的地址,参数类型为ByteArray,未指定的地址调用合约将失败。比如在进行合约升级时,这里的owner是合约管理员。在进行转账时,这里的owner是转出人(付款人)。
当合约中写了Runtime.CheckWitness(owner)时,调用合约时就要传入owner的签名。这个签名就是附加签名了。
在Neo-CLI中,我们可以通过invoke命令附加签名。
invoke<scriptHash><operation>contractParameters=nullsignerAccounts=null
在Neo-GUI中,在调用合约时,可以点击下方的附加签名,选择公钥然后点击签名来进行附加签名。
在通过转账命令调用NEP-17合约的transfer方法时,钱包会自动对from字段进行附加签名。此时不需要手动添加。
合约之间的互相调用
在Neo N3中,所有的合约都可以动态调用,且合约编写更加简单。
public class Contract1:SmartContract
{
delegate object Dyncall(string method,object[]args);
//如果是小端序,使用ByteArray格式
//[InitialValue("694425c17f1ebb7c65de3026c831eb4c49d6d7be",ContractParameterType.ByteArray)]
//private static readonly UInt160 ScriptHash;
//如果是大端序,使用Hash160格式
[InitialValue("0xbed7d6494ceb31c82630de657cbb1e7fc1254469",ContractParameterType.Hash160)]
public static UInt160 ScriptHash;
public static object Main(string operation,object[]args)
{
if(operation=="name")
{
return Contract.Call(ScriptHash,"name",CallFlags.ReadOnly,new object[0]);
}
if(operation=="totalSupply")
{
return Contract.Call(ScriptHash,"totalSupply",CallFlags.ReadOnly,new object[0]);
}
return true;
}
}
关键语句Contract.Call(scriptHash,method,flags,params)。
scriptHash:被调用合约的脚本散列,ByteArray类型,小端序。
method:被调用合约的方法,如name、balanceOf、transfer等,字符串类型。
flags:调用合约方法时允许的权限,参考(CallFlags枚举)。
params:被调用合约的方法的参数列表,数组类型。
权限相关字段
在合约的Manifest文件中定义了三个与权限相关的字段,参见下表。通过Groups和Trusts字段,钱包会根据合约之间是否可信,或者合约是否在同一组中来决定是否给用户安全警告。而Permissions和签名作用域决定了合约之间能否互相调用。关于签名作用域,请参考invokefunction方法的参数说明。
字段类型说明
Groups ContractGroup[]定义一组相互信任的合约,由公钥和对合约Hash的签名组成。
Permissions ContractPermission[]该字段是一个包含一个权限对象的数组,定义了该合约想要调用的其它合约及其方法。其中合约可以是ScriptHash,Group,或通配符。方法是方法名或通配符。没有在manifest中声明的合约或方法将无法被合约调用。
Trusts WildcardContainer<UInt160>定义该合约信任的其它合约,合约可以是ScriptHash,Group,或通配符*。如果一个合约是可信的,当合约调用时,用户界面将不会给出任何警告。