Closed mrRachar closed 5 years ago
Is there any problem that might arise when skipping verifier?
@SusanEisenbach There shouldn't be, the verifier is skip-able anyway with the command line option. The verifier is unfortunately very built around Ethereum─has Wei built in, etc.─and so we can't just verify programmes for Move IR without a little work, which is not seen as a priority. As variable specific mutates checking has been moved into the semantic analyser, you don't lose the core Flint guarantees, do any useless work, or have to fill things in that aren't used with dummy values as had to be done before when skipping the verifier.
Changes
Move support
Move is the IR language for Facebook's new Libra block-chain. Currently, Libra doesn't have a higher-level language targeting it, and so this is an attempt to make Flint the first high-level language to target Libra. This includes a complete translation for all non-external Flint constructs and external traits, however, LibraCoin support has proven difficult and is yet unimplemented. Doing so has required some changes to the compiler to allow multiple targets; some of the ground work for which has already been included and used upstream, however, most of it will come with this pull request.
Changes to Flint
external trait 0x1337.TraitName { ... }
. This is ignored in the Solidity translation, as it has no meaning there, and may produce a warning in the futureMathematical and logical operations
Basic mathematical and logical operations are converted using the built-in operators in Move. As Move will revert on overflow, there is now no need to differentiate between overflow-safe and overflowing operators, so both are translated to the same raw Move operator. There is, however, no power operator in Move. This is resolved through an iterative power computation over integers provided in the Move runtime, which any power operations
**
end up using.Contract and behaviour declarations
As Move splits up data from actions through its module and resources system, we needed to settle on a standard transformation into Move for Flint's contract construct. The translation involves creating a resource
T
to hold contract properties, inside a module which has the same name as the contract. Then any methods provided in behaviour declarations on the contract take in the resource as the first argument. This means roughly the follow translation occurs:is translated to
Wrapper methods
To allow calls into our Move module, we provide wrapper methods which take in an address and borrows the resource published at that address. That means that the actual translation of
f
above is closer to:These wrapper functions are only used as entry points (and thus only generated for public functions) to the Flint contract from other Move modules.
Automatic reference handling
Move has a complex system of referencing, moving, and copying. Flint on the other hand doesn't have any of these concepts, so the compiler has to infer and generate the necessary code, including releasing references when they're finished. References may also only be used once per statement (due to all references generated being mutable); double reference protection makes sure that if two references are used, they are split into multiple statements. Also, as the function cannot return until the references are released but the return statement might require those references, an intermediary variable must store the return value. Thus the innocent looking
ends up in the Move translation as the slight less clear
Some pre-assigments are also down to limited operations allowed within arguments to functions and only one level deep of
x.y
permitted at a time.Constructors
In Move an object cannot be constructed until all the properties are known. This means that until all variables have been assigned, no other methods may be called from a constructor. To simulate instance variables, every field is accessible initially as a separate variable which can be used and assigned. These are then used to construct the object.
If the constructor does contain further operations, such as re-assignments or function calls, the Move resource is constructed, and then a reference is generated which is used exactly as if you weren't in a constructor. The following translation shows all cases of operations involving self in a constructor:
is translated to
If a programme contains a method call before the instance can be constructed, this will result in a compilation error. This is seen as reasonable as the semantics of undefined properties are questionable at best, especially in Move, and code which does this should be refactored anyway.
Type states and caller protections
Type states and caller protections are implemented through assertions in the external wrapper methods. This means any attempt to call the function externally whilst in the wrong state or without permission will result in the transaction reverting. It was not seen as necessary to add protections in internal methods as Flint's semantic analyser will ensure correctness. The error thrown on an incorrect call is the line number in Flint to allow easier debugging and testing.
Structs, in-out arguments, and local struct variables
Structs are translated similarly to contracts, with methods converted into functions with the receiver as the first argument. The difference is no wrapper methods are generated, and the datatype created is a struct not a resource, named the same as the Flint struct. In-out arguments are translated to a reference type to allow structs to be passed around in the Move in a way which preserves the semantics of Flint.
Local structs however cannot be references, since they must be stored somewhere. Thus these are actually handled in Move as raw structs, and are referenced by the ARH when necessary (as is inevitably the case as Move requires references for operations such as property access, and all Flint functions take in struct references)
External traits
As Move separates behaviour and state, Flint needs two addresses, one of which should be the same for all instances, and is instead related to the type. To allow the module address to be specified, a change to the language has been instituted where an address may proceed an external trait name. This is currently optional throughout all common steps of the compiler, being ignored if present in the Solidity translation and may in the future be disallowed there, but is necessary for targeting Move.
External traits allow Flint-written code to interact with other Move modules, as long as they meet the the same interface as the translation of a Flint contract into Move. This means resources must be published at an address, and methods take this address as their first argument. Unfortunately, this also means structs cannot currently be handled, which is the current barrier to full Libra implementation (although you can access
LibraAccount
s in Move if you provide the interface). This requirement means a Move module that interfaces with Flint for the following external trait:must look something like
In Flint code external traits may be used exactly as expected. The need for this particular interface (functions taking in an address) is not seen as a large problem as a programmer can wrap a different style Move module in a module with this style of interface.
Test suite
To ensure that the Move translation works as expected, and doesn't break as the compiler develops, a test suite has been implemented in Python. This allows Flint files to be tested through compilation (in Move if it compiles it must have been verified), or provided with a
.mvir
file of the same name which will interact with the Flint contract to test its functionality. It also provides two testing directives,//! expect fail <line-number>
and//! provide module
which allow respectively tests to be expected to fail, and external Move modules to be provided. More information is provided in the test runner programme and the tests should provide enough information on how to write further tests. Currently the following tests passBasic standard library
The full complement of the EVM target standard library is not supported as of yet in the Move translation, as money is currently not supported in the translation. However, other functionality is currently supported:
assert(p: Bool)
fatalError()
Future work