Skip to content

Contracts should declare used features, also tests, and never unfault #4382

@igormcoelho

Description

@igormcoelho

Summary or problem description
This strategy ensures that hardforks on contracts become harder to happen, with two strategies: declaring all features that are necessary for the correct contract execution; and following the strategy of never unfaulting.

Do you have any solution you want to propose?
This is complement to issue #4367.

As mentioned in 4367, it already happened that newer features, like VerificationR, became unpractical because existing contracts would become erratic if such newer feature was introduced, thus breaking them... in other hand, the newer feature could be useful to newer contracts. Evolution always happen, but at that time, no practical solution was found to this issue.

So, a proposal is that each contract should declare all features of the ExecutionEngine that are necessary for its correct execution, including possibly Onchain Tests, that would run in a isolated mechanism, not leading to any state change. So, every smart contract should begin with some instructions like "DeclareFeature("Interop.XXX") and list all operations needed for its execution. It could also list WHICH Execution Machine is necessary, like "NeoVM2" or "NeoVM3" (or even "RISK-V"), if in the future there could be some mixed executions or other possible machines to interoperate. This simplifies the declaration of all "smaller" operations, like ADD, SUM, etc, although it could be possible to create some "Packs" of operations, like "ADD, SUM, etc = HASH848349348384", and then enable ONLY these sets of operations during execution, as a form of Versioning of VM, in complement to the versioning of the Interops.

This way, unless an operation changes, contract will keep their execution in a correct way. A common challenge is when a contract uses unexisting features, thus Faulting an execution, and somehow in the future this operation becomes Valid, thus Unfaulting. A solution to this issue is to include in a NEXT BLOCK, a single Bit of information, for each transation, indicating if it has Faulted or Succeeded. This seems to create some sort of 2-block finality, but on practice, finality is kept the same, as long as correct machines execute the trnasactions, and it allows for all nodes that follow the chain to Skip all transactions previously marked as Faulted, reducing attack surface for malevolous agents that intentionally introduce faulted opcodes and invalid interops.

The idea is also to run Unit Tests during contract deployment, ensuring that operations run correctly, and also to scan which opcodes are present in the NEF, thus rejecting the Contract Deploy if "strange" operations exist in bytecode, even if unreachable. Onchain Unit Tests can ensure that contract works as intended, at least for basic operations, although it can be tricky to perform complete Integration Tests with other contracts in the network.
It is also possible to create some Tests to check the Integration with a contract and other dependencies, so that if a dependency contract becames erratic, maybe after an upgrade, the smart contract can automatically Reject the connection with such contract, preventing attacks.

Unused Pre-Post Verifications (see the other proposal) should also lead to FAULT, desincentiving any form of attack or waste of resources on the P2P layer for transaction transmission and processing.

Where in the software does this update applies to?

  • Compiler (perhaps...)
  • Consensus (perhaps, for the block unfault info...)
  • CLI (no)
  • Plugins (no)
  • Ledger (ok, for block header)
  • Network Policy - no
  • P2P (TCP) - (perhaps, to skip faulted tx...)
  • RPC (HTTP) - no
  • SDK (surely!)
  • VM (perhaps, for VM versioning...)
  • Other:

Metadata

Metadata

Assignees

No one assigned

    Labels

    DiscussionInitial issue state - proposed but not yet accepted

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions