Contract factories and bytecode introspection (#305)

* Support for CREATE, CLONE and BYTECODE_HASH

* Add missing files

* Pushed the clone example through the typechecker

* CLONE compiles

* Fix dependent type in CLONE

* Bytecode hash fixes

* Refactor

* Refactor 2

* move some logic away

* Fixed some error messages. Type inference of child contract still does some random shit\n(mistakes arguments with result type)

* CREATE sometimes compiles and sometimes not

* Fix some scoping/constraint issues

* works, needs cleanup

* cleanup

* Fix some tests. Remove optimization of singleton tuples

* Fix default argument for clone

* Cleanup

* CHANGELOG

* Mention void type

* Address review, fix some dialyzer errors

* Please dialyzer

* Fix failing tests

* Write negative tests

* Docs

* TOC

* missing 'the'

* missing 'the'

* missing 'the'

* missing 'the'

* mention pre-fund

* format

* pre-fund clarification

* format

* Grammar in docs
This commit is contained in:
Radosław Rowicki
2021-05-18 12:21:57 +02:00
committed by GitHub
parent d82b42518e
commit 1d9f59fec3
68 changed files with 1113 additions and 494 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
contract Identity =
function main (x:int) = x
function main_fun (x:int) = x
function __call() = 12
+2 -2
View File
@@ -1,5 +1,5 @@
contract Remote =
entrypoint main : (int) => unit
contract interface Remote =
entrypoint main_fun : (int) => unit
contract AddrChain =
type o_type = oracle(string, map(string, int))
+1 -1
View File
@@ -1,5 +1,5 @@
contract Remote =
contract interface Remote =
entrypoint foo : () => unit
contract AddressLiterals =
+5
View File
@@ -0,0 +1,5 @@
contract C =
entrypoint f() = 123
contract D =
entrypoint f() = 123
+1 -1
View File
@@ -1,5 +1,5 @@
contract Remote =
contract interface Remote =
entrypoint foo : () => unit
contract AddressLiterals =
+1 -1
View File
@@ -1,4 +1,4 @@
contract Remote =
contract interface Remote =
entrypoint id : int => int
contract ProtectedCall =
+1 -1
View File
@@ -1,3 +1,3 @@
function square(x) = x ^ 2
contract Main =
entrypoint main() = square(10)
entrypoint main_fun() = square(10)
+28
View File
@@ -0,0 +1,28 @@
contract interface HigherOrderState =
entrypoint init : () => void
entrypoint apply : int => int
stateful entrypoint inc : int => unit
contract interface LowerDisorderAnarchy =
entrypoint init : (int) => void
main contract C =
// both `s` and `l` should be of type `HigherOrderState` in this test
stateful entrypoint run_clone(s : HigherOrderState, l : LowerDisorderAnarchy) : HigherOrderState =
let s1 = Chain.clone(ref=s)
let Some(s2) = Chain.clone(ref=s, protected=true)
let None = Chain.clone(ref=s, protected=true, gas=1)
let None = Chain.clone(ref=l, protected=true, 123) // since it should be HigherOrderState underneath
let s3 = Chain.clone(ref=s1)
require(s1.apply(2137) == 2137, "APPLY_S1_0")
require(s2.apply(2137) == 2137, "APPLY_S2_0")
require(s3.apply(2137) == 2137, "APPLY_S3_0")
s1.inc(1)
s2.inc(1)
s1.inc(1)
require(s1.apply(2137) == 2139, "APPLY_S1_2")
require(s2.apply(2137) == 2138, "APPLY_S2_1")
require(s3.apply(2137) == 2137, "APPLY_S3_0")
s1
+7
View File
@@ -0,0 +1,7 @@
contract interface I =
entrypoint init : () => void
contract C =
stateful entrypoint f(i : I) =
let Some(c1) = Chain.clone(ref=i, protected = true)
2
@@ -5,5 +5,5 @@ contract BadAENSresolve =
function fail() : t(int) =
AENS.resolve("foo.aet", "whatever")
entrypoint main() = ()
entrypoint main_fun() = ()
@@ -0,0 +1,5 @@
contract C =
entrypoint f : () => unit
main contract M =
entrypoint f() = 123
@@ -3,4 +3,4 @@ contract MapAsMapKey =
function foo(m) : t(int => int) = {[m] = 0}
entrypoint main() = ()
entrypoint main_fun() = ()
@@ -2,4 +2,4 @@ contract HigherOrderQueryType =
stateful function foo(o) : oracle_query(_, string ) =
Oracle.query(o, (x) => x + 1, 100, RelativeTTL(100), RelativeTTL(100))
entrypoint main() = ()
entrypoint main_fun() = ()
@@ -2,4 +2,4 @@ contract HigherOrderResponseType =
stateful function foo(o, q : oracle_query(string, _)) =
Oracle.respond(o, q, (x) => x + 1)
entrypoint main() = ()
entrypoint main_fun() = ()
@@ -1,2 +0,0 @@
namespace LastDeclarationIsNotAContract =
function add(x, y) = x + y
@@ -1,3 +1,3 @@
contract MissingDefinition =
entrypoint foo : int => int
entrypoint main() = foo(0)
entrypoint main_fun() = foo(0)
@@ -3,5 +3,5 @@ contract PolymorphicAENSresolve =
function fail() : option('a) =
AENS.resolve("foo.aet", "whatever")
entrypoint main() = ()
entrypoint main_fun() = ()
@@ -3,4 +3,4 @@ contract MapAsMapKey =
function foo(m) : t('a) = {[m] = 0}
entrypoint main() = ()
entrypoint main_fun() = ()
@@ -2,4 +2,4 @@ contract PolymorphicQueryType =
stateful function is_oracle(o) =
Oracle.check(o)
entrypoint main() = ()
entrypoint main_fun() = ()
@@ -2,4 +2,4 @@ contract PolymorphicResponseType =
function is_oracle(o : oracle(string, 'r)) =
Oracle.check(o)
entrypoint main(o : oracle(string, int)) = is_oracle(o)
entrypoint main_fun(o : oracle(string, int)) = is_oracle(o)
@@ -1,4 +1,4 @@
contract Remote =
contract interface Remote =
entrypoint foo : int => int
contract UnappliedContractCall =
@@ -1,5 +1,5 @@
contract UnappliedNamedArgBuiltin =
// Allowed in FATE, but not AEVM
stateful entrypoint main(s) =
stateful entrypoint main_fun(s) =
let reg = Oracle.register
reg(signature = s, Contract.address, 100, RelativeTTL(100)) : oracle(int, int)
+1 -1
View File
@@ -1,5 +1,5 @@
contract Remote =
contract interface Remote =
entrypoint up_to : (int) => list(int)
entrypoint sum : (list(int)) => int
entrypoint some_string : () => string
+1 -1
View File
@@ -1,4 +1,4 @@
contract Foo =
contract interface Foo =
entrypoint foo : () => int
contract Fail =
+28
View File
@@ -0,0 +1,28 @@
contract IntegerAdder =
entrypoint init() = ()
entrypoint addIntegers(x, y) = x + y
contract IntegerAdderHolder =
type state = IntegerAdder
stateful entrypoint init() = Chain.create() : IntegerAdder
entrypoint get() = state
contract IntegerAdderFactory =
entrypoint init() = ()
stateful entrypoint new() =
let i = Chain.create() : IntegerAdderHolder
i.get()
payable contract ValueAdder =
entrypoint init() = ()
stateful entrypoint addValue(x) =
let integerAdderFactory = Chain.create()
let adder = integerAdderFactory.new()
adder.addIntegers(x, Contract.balance)
main contract EnterpriseContract =
entrypoint init() = ()
stateful payable entrypoint increaseByThree(x) =
require(Call.value >= 3, "Price for addition = 3AEtto, insufficient funds")
let threeAdder = Chain.create(value = 3)
threeAdder.addValue(x)
+1 -1
View File
@@ -1,6 +1,6 @@
// Testing primitives for accessing the block chain environment
contract Interface =
contract interface Interface =
entrypoint contract_address : () => address
entrypoint call_origin : () => address
entrypoint call_caller : () => address
+1 -1
View File
@@ -1,4 +1,4 @@
contract Remote =
contract interface Remote =
entrypoint dummy : () => unit
contract Events =
+1 -1
View File
@@ -1,6 +1,6 @@
// An implementation of the factorial function where each recursive
// call is to another contract. Not the cheapest way to compute factorial.
contract FactorialServer =
contract interface FactorialServer =
entrypoint fac : (int) => int
contract Factorial =
+24
View File
@@ -0,0 +1,24 @@
contract interface Kaboom =
entrypoint init : () => void
contract Bakoom =
type state = int
entrypoint init(x, b) = if(b) x else 0
main contract Test =
stateful entrypoint test(k : Kaboom) =
let k_bad1 = Chain.clone() : Kaboom
let k_bad2 = Chain.clone(ref=k, 123, true)
let k_bad3 = Chain.clone(ref=k, gas=true)
let k_bad4 = Chain.create() : Kaboom
let k_gud1 = Chain.clone(ref=k)
let Some(k_gud2) = Chain.clone(ref=k, protected=true)
let Some(k_gud3) = Chain.clone(ref=k, value=10, protected=true, gas=123)
let b_bad1 = Chain.create() : Bakoom
let b_bad2 = Chain.create(123, true, protected=true) : Bakoom
let b_bad3 = Chain.create(123, true, value=true) : Bakoom
let b_gud1 = Chain.create(123, true) : Bakoom
let b_gud2 = Chain.create(123, true, value=100) : Bakoom
b_gud1
+2 -3
View File
@@ -1,3 +1,2 @@
contract Identity =
entrypoint main (x:int) = x
main contract Identity =
entrypoint main_fun (x:int) = x
+5
View File
@@ -0,0 +1,5 @@
contract interface ContractOne =
entrypoint foo() = "foo"
contract ContractTwo =
entrypoint bar() = "bar"
+1 -1
View File
@@ -16,7 +16,7 @@ contract LHSMatching =
let null(_ :: _) = false
!null(xs)
entrypoint main() =
entrypoint main_fun() =
from_some(Some([0]))
++ append([length([true]), 2, 3], [4, 5, 6])
++ [7 | if (local_match([false]))]
+1 -1
View File
@@ -1,3 +1,3 @@
contract MissingEventType =
entrypoint main() =
entrypoint main_fun() =
Chain.event("MAIN")
+6 -4
View File
@@ -1,5 +1,7 @@
contract ContractOne =
entrypoint foo() = "foo"
contract Child =
entrypoint
add2 : int => int
add2(x) = x + 2
contract ContractTwo =
entrypoint bar() = "bar"
main contract Main =
entrypoint add4(x, c : Child) = c.add2(x) + 2
@@ -0,0 +1,5 @@
main contract C =
entrypoint f() = 123
main contract D =
entrypoint f() = 123
+2
View File
@@ -0,0 +1,2 @@
contract interface C =
entrypoint f : () => unit
+1 -1
View File
@@ -1,4 +1,4 @@
contract C1 =
contract interface C1 =
entrypoint f : int
contract C =
+1 -1
View File
@@ -1,4 +1,4 @@
contract Remote =
contract interface Remote =
entrypoint id : int => int
contract ProtectedCall =
+5 -5
View File
@@ -1,18 +1,18 @@
contract Remote1 =
entrypoint main : (int) => int
contract interface Remote1 =
entrypoint main_fun : (int) => int
contract Remote2 =
contract interface Remote2 =
entrypoint call : (Remote1, int) => int
contract Remote3 =
contract interface Remote3 =
entrypoint get : () => int
entrypoint tick : () => unit
contract RemoteCall =
stateful entrypoint call(r : Remote1, x : int) : int =
r.main(gas = 10000, value = 10, x)
r.main_fun(gas = 10000, value = 10, x)
entrypoint staged_call(r1 : Remote1, r2 : Remote2, x : int) =
r2.call(r1, x)
+1 -1
View File
@@ -1,5 +1,5 @@
contract SpendContract =
contract interface SpendContract =
entrypoint withdraw : (int) => int
contract SpendTest =
+1 -1
View File
@@ -1,5 +1,5 @@
include "String.aes"
contract Remote =
contract interface Remote =
record rstate = { i : int, s : string, m : map(int, int) }
entrypoint look_at : (rstate) => unit
+1 -1
View File
@@ -1,5 +1,5 @@
contract Remote =
contract interface Remote =
stateful entrypoint remote_spend : (address, int) => unit
entrypoint remote_pure : int => int
+9 -99
View File
@@ -1,102 +1,12 @@
// This is a custom test file if you need to run a compiler without
// changing aeso_compiler_tests.erl
contract Identity =
// type xy = {x:int, y:int}
// type xz = {x:int, z:int}
// type yz = {y:int, z:int}
record point = {x:int,y:int}
record cp('a) = {color: string, p:'a}
//type intpoint = point(int)
// //if (x==42) 1 else (x*x)
// }
//let baz() = {age:3, name:(4:int)}
//let foo(a,b,c) = c
// let rec fac(n) = if((n:int)==0) 1 else (n*fac(n-1))
// and main(x) = x::[x+1]
// let lentr(l) = lent(0,l)
// let rec len(l) =
// switch(l) {
// | [] => 0
// | x::xs => 1+len(xs)
// }
// let lent(n,l) =
// switch (l) {
// | [] => n
// | (x::xs) => lent(n+1,xs)
// }
// let rec app(a,b) =
// switch(a) {
// | [] => b
// | (x::xs) => x::app(xs,b)
// }
// let rec revt(l,r) =
// switch(l) {
// | [] => r
// | x::xs => revt(xs,x::r)
// }
// let rev(l) = revt(l,[])
// let main(x:int) = {
// switch(rev([1,2,3])) {
// | h::_ => h
// }
// }
//let fac(n:int) = {
// if (n==0) 1 else (n*fac(n-1))
//}
//let main(x) = switch((12,34)) {
//| (13,_) => x
//| (_,a) => x+a
// | y => y+1
// }
//let main(x) = ({y:0>1, x:x==0}:point(bool))
//let main(x) = x
//let main(x) = len(1::2::[])
//let main(x) = ((x,x):list('a))
// let main(x) = switch("a") {
// | "b" => 0
// | "a" => 1
// | "c" => 2
// }
//let main(x) = x.color+1
//let main(x) = switch(({x:x, y:x+1}:cp(int))) {
// | {y:xx} => xx
// }
//let main(x) = {x:0, y:1, z:2}
// let id(x) = x
// let double(x) = x+x
// let pair(x) = (1,2)
// let unit(x) = ()
// let tuples(x) = ((1,x),(2,3,4))
// let singleton(x) = [x]
// let rec seq(n) = if (n==0) [] else (app(seq(n-1),[n]))
// let idString(s:string) = s
// let pairString(s:string) = (s,s)
// let revStrings(ss:list(string))=rev(ss)
// let makePoint(x,y) = {x:x, y:y}
// let getx(x) = x.x
// let updatex(p,x) = p{x:x}
// let quad(x) = {let y=x+x; let z=y+y; z;}
// let noblock(x) = {x; x}
// let unit(x) = ()
// let foo(x) = switch (x) {
// | y => y+1
// }
// let p(x) = {color:"blue", p:{x:x, y:x+1}}
//let twice(f,x) = f(f(x))
// let twice(f,x) = f(f(x))
// let double(x) = x+x
// let main(x) = twice((y=>y+y),x)
// let rec map(f,xs) = switch(xs) {
// | [] => []
// | (x::ys) => f(x)::map(f,ys)
// }
// let id(x) = x
// let main(xs) = map(double,xs)
function z(f,x) = x
function s(n) = (f,x)=>f(n(f,x))
function add(m,n) = (f,x)=>m(f,n(f,x))
include "List.aes"
entrypoint main() =
let three=s(s(s(z)))
add(three,three)
(((i)=>i+1),0)
contract IntegerHolder =
type state = int
entrypoint init(x) = x
entrypoint get() = state
main contract Test =
stateful entrypoint f(c) = Chain.clone(ref=c, 123)
+1 -1
View File
@@ -1,5 +1,5 @@
contract Remote =
contract interface Remote =
type themap = map(int, string)
entrypoint foo : () => themap
+1 -1
View File
@@ -9,7 +9,7 @@
// Oracle.extend
include "String.aes"
contract UnappliedBuiltins =
entrypoint main() = ()
entrypoint main_fun() = ()
type o = oracle(int, int)
type t = list(int * string)
type m = map(int, int)