Open roman-khimov opened 1 year ago
This can also help for NeoFS withdrawals. As we've said numerous times, in absence of #1573 we have a huge problem with GAS withdrawals from NeoFS mainnet contract. It requires confirmation from all of the alphabet IR nodes, so at the moment this implies collecting votes in the contract itself and consequently leads to a hefty GAS penalty for doing so. Instead a check can be signed in the sidechain and transferred to mainnet contract to withdraw with a single transaction.
Hi @roman-khimov,
perhaps this CheckData
interop is a good direction to go.
Is not the current System.Runtime.LoadScript
able to handle all this if we use specific calls inside it? If we pass a complex script with all rules.
We can pass invocation/verification scripts (most likely a concatenation of those) into LoadScript
now and get a result, but the problem is that Checksig/Checkmultisig calls will check for a signature of script container (transaction) and not some abstract data. Of course we can have arbitrary logic in scripts, but how do we tie this logic to Neo accounts if this logic is not a verification script?
One drawback of this approach is that signature checks are moved to execution phase, so they inherently become sequential (unlike transaction verification that can be performed concurrently). For some applications it's still OK this way, for some performance requirements can be higher.
That is something I personally loved on NEO2, the ability of account abstraction was huge. However, @roman-khimov , as you recently mentioned in your comment, make everything on the execution phase is not a good direction.
The only other way here is moving this into transaction. Make it a container for (an array of)
data to check (or a hash of it) address to check this data against invocation script verification script (can be null for contracts)
Either in version 1 or just via some new attribute. This way the check could be performed as a part of a regular transaction verification and other code (like entry script) could access this data from transaction. Then no interop is needed, but this goes deeper at the same time.
Summary or problem description We've got two basic mechanisms to verify some permissions or action validity in a contract:
System.Runtime.CheckWitness
that checks for scoped witness of the current transactionCryptoLib.VerifyWithECDsa
that can help with signatures of some non-transaction dataThe first one is the standard thing that works for any Neo account. The second one only works with some single keys (but can handle secp256k1 curve). Usually the second one is used to check some auxiliary non-Neo-related data like cross-chain headers or state data, while regular Neo accounts provide witness (usually, signature(s)) for Neo transactions.
Creating a transaction for Neo blockchain implies answering to several questions:
There are cases where we'd like to free the signer from answering to this questions. The first one can be solved with #2577 (and NeoFS sidechain uses it already), but the other two are somewhat more problematic. They assume some knowledge of Neo transaction structure and (!) NeoVM on the signing side. Of course transaction can be prepared elsewhere, but passing some base64 for wallet to sign is not a good idea in general, signer needs to know what exactly he is signing. This problem intersects strongly with neo-project/proposals#68 (and #2835 duplicate of it), but as mentioned there, it's not that easy in Neo context.
So going from an intent of doing something application-specific to transaction requires some effort. Some contracts try dealing with it by using simple signatures they can check with
CryptoLib.VerifyWithECDsa
. The data to sign can be anything application wants (like serialized NeoFS container structure) and this structure can be as app-friendly as it can be (only containing app-relevant data), but the approach itself inherently means that only simple single-key accounts could be used, application can't rely on Neo account system in this case and can't have multisignature, contract-based or non-standard accounts using this scheme.Do you have any solution you want to propose? Neo account witness in general is three things: account hash (address), invocation script and verification script (which is omitted for contracts), so verification requires executing some code which usually calls
System.Crypto.CheckSig
orSystem.Crypto.CheckMultisig
. Both operate with the so-called "script container" (usually a transaction), serialized representation of which should be signed. So to be able to verify something we need to run two VM scripts with some specific script container.We have an ability to run arbitrary read-only scripts in VM since 3.5.0 (
System.Runtime.LoadScript
from neo-project/neo#2756). The only thing left to implement is ability to provide some data to check, overridingScriptContainer
for the execution since bothSystem.Crypto.CheckSig
andSystem.Crypto.CheckMultisig
should work. The proposal is to implement this in aSystem.Crypto.CheckData
interop.It should accept:
And it should return a simple boolean true/false result (as verification scripts usually do).
This allows to implement dApp-specific trust schemes that are easy to sign on clients that have absolutely no idea what's going on in the blockchain.
Example 1 NeoFS currently only allows single-key accounts and that's exactly because of the limitation described above. Creating a container via NeoFS SDK doesn't require managing transactions since we want to provide an API to manage data and not dealing with sidechain. But internally it's a sidechain transaction that calls NeoFS container contract. Going via
System.Crypto.CheckData
would allow to have containers owned by multisignature accounts.Example 2 Consider neo-project/proposals#152 problem. While I understand people there want a very specific compatible solution, let's imagine how the problem of "allowing a spender to spend x amount of funds on behalf of an owner" could be solved with
System.Crypto.CheckData
(but notice that this is just an example, not a proposal for a fancytransferFrom
).It can be done with just a single
transferFrom(spender Hash160, from Hash160, to Hash160, amount Integer, data Any, token String, invocation ByteArray, verification ByteArray)
accepting a JWT-liketoken
:The implementation will:
spender
witnessStdLib.JsonDeserialize()
the tokenasset
is the same asSystem.Runtime.GetExecutingScriptHash
from
is the same asiss
andspender
is the same assub
nbf
(in blocks, of course) and has not yet expired wrtexp
(also in blocks)seq
is the next one for the issuer to use (that's to prevent replays, random IDs can be used, but counter (while adding some limitations) requires less storage)amount
against token'samount
System.Crypto.CheckData(token, from, invocation, verification)
So we have a scheme that only adds a single method, can work with a signature for a very simple and easy to understand structure and doesn't even require any transactions on the
from
side.Neo Version
Where in the software does this update applies to?