Neo: [neo3] Abolish VerificationTrigger for deployed contracts

Created on 25 Sep 2019  路  14Comments  路  Source: neo-project/neo

Summary
This is a next step towards Neo 3, into a simpler programming model, and safer/faster for transaction verifications (higher tps).

Do you have any solution you want to propose?
Abolish VerificationTrigger access on deployed contracts. This means that deployed contracts won't be invoked directly for verification on tx, and verification would be performed by a standard method "verify", invoked on ApplicationTrigger expecting a boolean result (this was heavily inspired by an old proposal by Erik, called unified entry points, now in a slightly differnt format).

Impact on TPS:
This will drastically improve TPS, as no deployed contract will be ever seeked/executed on a tx witness, only when inside a valid block. The reason is that usually these contracts are long, containing loops, dyn invokes, and many evil things... since user pays for tx size, this cheats the model by allowing a small transaction contain lots of things (by implicitly invoking the contract).

Behavior changes:
Since deployed contracts won't be able to appear as Tx Witness, how can users withraw assets from it?
Simple. Suppose a NEP-5 contract wants to take assets from 0xdeployed, what will happen is that at some point it will trigger a Runtime.CheckWitness(0xdeployed). Usually, CheckWitness only verifies witness list, but this time, it will require checking (on ApplicationTrigger) if this contract is deployed, and if it's deployed, it will trigger a "verify" method on that contract. If bool passes, this implicit witness passes. So no change to anything else, it just works.

Side-effects/drawbacks:
An important side-effect of this proposal is that deployed contracts won't ever be able to pay fees (network or system). Some time ago I wanted that contracts subsidize user GAS operations, I think it's doable, but not this way. The reason is that, although contracts right now can give GAS on network fee, it's not possible to write a safe code that will ensure your users actually deserve this GAS... the reason is because this transaction can contain virtually any script, and you could use this invocation to do any other jobs (example, a company let's you use WhatsApp for free with no data costs, and you use it as a proxy for internet access as a trick......). I have a much better solution for contract sponsorship, much easier to understand and implement (we will propose this on a governance discussion).

So, this is a important solution in my opinion, after months of thoughts, and I hope this pleases community. With this proposal, no more codes like if (TriggerType == Verification), because a contract will either be executed as Application or Verification, never both.

Where in the software does this update applies to?

  • Ledger
  • Network Policy
  • Other: Smart Contracts
consensus design enhancement ledger

Most helpful comment

An deployed contract can transfer the assets in it without any verification.

https://github.com/neo-project/proposals/blob/master/nep-5.mediawiki#transfer

The function SHOULD check whether the from address equals the caller contract hash. If so, the transfer SHOULD be processed;

All 14 comments

@erikzhang @belane @shargon @vncoelho @lock9 @jsolman This is a serious and well-thought proposal, please consider it with an open heart :) I can guarantee it works, I can explain any details if not clear enough. This will help us resolving network fee calculation issues, in a important step.

I believe that this is also aligned with some ideas of @erikzhang on SVM2.

I think that this current proposed abolishment is good, @igormcoelho. The SC will also look nice with this as a method.

Practical example (on C#):

static byte[] owner = "ownerScriptHash";
object Main(string op, object[] args) {
  // always ApplicationTrigger, if deployed. If you want to check it, just execute Runtime.GetTrigger
   if(op == "op1") {
       // any other common operation
    }
   else if(op == "verify") { // this is called automatically every time a witness of this contract is required
       return CheckWitness(owner); // this implementation of "verify" just requires another owner witness, but could be different..
    }
   else if(op == "op2") {
       // any other common operation
    }
   // ....
}

From a manifest permission perspective, best thing is having verify as readOnly method.

@igormcoelho I think this is very important to simplify the development model. It also relates to #919.

@igormcoelho We need to update the compiler too, right?
Can you create a list of 'sub tasks' you think we need to have this fully implemented?
Thanks

Some time ago I wanted that contracts subsidize user GAS operations, I think it's doable, but not this way. The reason is that, although contracts right now can give GAS on network fee, it's not possible to write a safe code that will ensure your users actually deserve this GAS... the reason is because this transaction can contain virtually any script, and you could use this invocation to do any other jobs (example, a company let's you use WhatsApp for free with no data costs, and you use it as a proxy for internet access as a trick......)

Could you please check #1104 ? I think that we can use native contract methods for that. I would like to work on this 'fee proxy', can you help me?

@lock9 no change on compiler is needed... impact will be minimal on code.

Regarding sys_fee / net_fee, with this PR, it will become impossible to pay fees by a deployed contract. We propose a much better solution on NeoResearch report on novel Consensus/Governance. The general idea is to incentive nodes by giving incentives to their contracts. Free for users and contracts, better for everyone.

An deployed contract can transfer the assets in it without any verification.

https://github.com/neo-project/proposals/blob/master/nep-5.mediawiki#transfer

The function SHOULD check whether the from address equals the caller contract hash. If so, the transfer SHOULD be processed;

Agree Erik, callingscripthash provides verification allowing the contract to invoke NEP5 and transfer,but only if contract knows in advance which tokens it has.
Entry -> ContractX -> NEP5 transfer -> CheckWitness(ContractX) -> Ok

But if contract doesnt know tokens or authentication reason in advance, we still need the regular operation:
Entry -> NEP5 transfer -> CheckWitness(ContractX) -> ?
Right now we can do it using VerificationTrigger, attaching as witness, but without all that, the proposal is:
Entry -> NEP5 "transfer" -> CheckWitness(ContractX) -> ContractX "verify" -> Ok

If "verify" is readonly, no issues will arise from manifest dynamic invoke * wildcard, simplifying code and avoid upfront processing on tx (now tx witness verification should not be able to System.Invoke any other contracts now).

What is the different between

if(op == "verify")
and
if (Runtime.Trigger == TriggerType.Verification)
?

One is a parameter and the other one just callschecksig scope, with pre cached witness.

What is the different between

The difference is that "verify" is a method, and VerificationTrigger is a trigger... users I know easily understand methods, but cannot easily understand triggers (even advanced users...).

Another difference is: since VerificationTrigger has different execution rules than Application (some interops work,others not), and we are possibly making this worse with the "no backward jump" proposal, reaching a single code that has two different execution protocols.
"verify" method would run in Application, so as any other method,which is very simple for users, and good for us too, to drastically reduce upfront tx calculation (at the expense of deployed contracts not being able to directly pay its own fees).

How to prevent certains syscall under verification?

Good point Shargon. We are not abolishing VerificationTrigger in all cases... witnesses will still execute as VT, with constrained syscalls. But Entry script will execute as ApplicationTrigger always, and we will block deployed contracts to be invoked from witnesses.

To be practical here:

  • disable deployed contracts appearing as witness
  • disable System.Invoke from VerificationTrigger

By doing these two things, we completely isolate both triggers. "verify" method will execute as Application, but ReadOnly, meaning that it still cannot change state, while verifying.

Was this page helpful?
0 / 5 - 0 ratings