Tx::is_signed_by can't check for staking key signatures
Closed this issue ยท 6 comments
There are cases where we require transactions to be signed by staking keys instead of, or aside from, spending keys. But Tx::is_signed_by()
right now only allows checking for signatures matching PubKeyHash
es.
If we try checking for a staking key signature like for example:
spending myValidator
struct Datum {
acct: StakeKeyHash
}
func main(datum: Datum, _, ctx: ScriptContext) -> Bool {
ctx.tx.is_signed_by(datum.acct).trace("signed by holder: ")
}
...an error like the following is thrown:
...node_modules/@hyperionbt/helios/helios.js:1587
return new UserError(msg, src, startPos, endPos);
^
UserError: TypeError on line 25: expected 'PubKeyHash' for arg 1, got 'StakeKeyHash'
at Function.new (...node_modules/@hyperionbt/helios/helios.js:1587:10)
at Function.typeError (...node_modules/@hyperionbt/helios/helios.js:1633:30)
at Site.typeError (...node_modules/@hyperionbt/helios/helios.js:1508:20)
at FuncType.checkCall (...node_modules/@hyperionbt/helios/helios.js:18592:10)
at FuncEntity.call (...node_modules/@hyperionbt/helios/helios.js:19590:28)
at CallExpr.evalInternal (...node_modules/@hyperionbt/helios/helios.js:32561:24)
at CallExpr.eval (...node_modules/@hyperionbt/helios/helios.js:29831:23)
at MemberExpr.evalInternal (...node_modules/@hyperionbt/helios/helios.js:32839:33)
at MemberExpr.eval (...node_modules/@hyperionbt/helios/helios.js:29831:23)
at CallExpr.evalInternal (...node_modules/@hyperionbt/helios/helios.js:32492:30)
Tx::signatories
and Tx.addSigner
in the api should probably be updated also..
https://www.hyperion-bt.org/helios-book/lang/builtins/tx.html#signatories
https://www.hyperion-bt.org/helios-book/api/reference/classes/Tx.html#addsigner
I just saw this now, and responded in discord. Here are my comments below.
I think the trick is to add the staking key hash as a signer to the tx in the offchain code, and then onchain you can check the staking key as if it were a public key hash. Both staking key and public key are just opaque types around a bytestring hash. So from a cryptographic perspective, it is simply a matter of confirming that the hash matches the signature.
And in your example, instead of using StakeKeyHash in the datum, use a bytestring to pass the hash, and then create a PubKeyHash in the onchain code.
struct Datum {
acct: ByteArray
}
... inside main somewhere...
stakingHash: PubKeyHash = PubKeyHash::new(datum.acct);
instead of using StakeKeyHash in the datum, use a bytestring to pass the hash, and then create a PubKeyHash in the onchain code.
Thanks for this! Definitely a work-around for now.
Still, it'd be better if we can just do tx.is_signed_by(stakeKeyHash)
in future versions; makes code intent more apparent.
I've been giving this some thought, and maybe the best option is to simply get rid of StakeKeyHash and represent it with a PubKeyHash instead?
reposting here my comment on discord:
I can't say I know much about the low-level stuff, but if StakeKeyHash
has the same structure as PubKeyHash
, then it makes sense to just use PubKeyHash
and get rid of StakeKeyHash
entirely.
Then perhaps it's just the docs that will need updating to make it clear, especially to newcomers, that these two types are treated the same by Helios.
v0.15.11 removes all occurences of StakeKeyHash
in favor of PubKeyHash