瀏覽代碼

Primitive tests

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 5 年之前
父節點
當前提交
b85ab5e78f

+ 1 - 1
.github/workflows/test.yml

@@ -87,7 +87,7 @@ jobs:
     container: hyperledgerlabs/solang:ci
     services:
       solana:
-        image: solanalabs/solana:v1.4.2
+        image: solanalabs/solana:edge
         ports:
           - 8899
           - 8900

+ 0 - 28
integration/solana/flipper.spec.ts

@@ -1,28 +0,0 @@
-import expect from 'expect';
-import { establishConnection } from './index';
-
-describe('Deploy solang contract and test', () => {
-    it('flipper', async function () {
-        this.timeout(10000);
-
-        let conn = await establishConnection();
-
-        let prog = await conn.loadProgram("flipper.so", "flipper.abi");
-
-        // call the constructor
-        await prog.call_constructor(conn, ["true"]);
-
-        let res = await prog.call_function(conn, "get", []);
-
-        expect(res["__length__"]).toBe(1);
-        expect(res["0"]).toBe(true);
-
-        await prog.call_function(conn, "flip", []);
-
-        res = await prog.call_function(conn, "get", []);
-
-        expect(res["__length__"]).toBe(1);
-        expect(res["0"]).toBe(false);
-
-    });
-});

+ 8 - 6
integration/solana/index.ts

@@ -11,7 +11,7 @@ import {
     sendAndConfirmTransaction,
 } from '@solana/web3.js';
 import fs from 'fs';
-import { AbiItem } from 'web3-utils';
+import { AbiItem, AbiInput } from 'web3-utils';
 const Web3EthAbi = require('web3-eth-abi');
 
 const default_url: string = "http://localhost:8899";
@@ -41,7 +41,7 @@ const sleep = (ms: number) => new Promise(res => setTimeout(res, ms));
 
 async function newAccountWithLamports(
     connection: Connection,
-    lamports: number = 100000000,
+    lamports: number = 1000000000,
 ): Promise<Account> {
     const account = new Account();
 
@@ -125,11 +125,13 @@ class Program {
     constructor(private programId: PublicKey, private returnDataAccount: Account, private contractStorageAccount: Account, private abi: string) { }
 
     async call_constructor(test: TestConnection, params: string[]): Promise<void> {
-        let abi: AbiItem = JSON.parse(this.abi).find((e: AbiItem) => e.type == "constructor");
+        let abi: AbiItem | undefined = JSON.parse(this.abi).find((e: AbiItem) => e.type == "constructor");
 
-        const input = Web3EthAbi.encodeParameters(abi.inputs!, params);
+        let inputs = abi?.inputs! || [];
 
-        console.log('calling constructor ' + params);
+        const input = Web3EthAbi.encodeParameters(inputs, params);
+
+        console.log('calling constructor [' + params + ']');
 
         const instruction = new TransactionInstruction({
             keys: [
@@ -156,7 +158,7 @@ class Program {
 
         const input: string = Web3EthAbi.encodeFunctionCall(abi, params);
 
-        let debug = 'calling function ' + name + params;
+        let debug = 'calling function ' + name + ' [' + params + ']';
 
         const instruction = new TransactionInstruction({
             keys: [

+ 148 - 0
integration/solana/primitives.sol

@@ -0,0 +1,148 @@
+
+contract primitives {
+	enum oper { add, sub, mul, div, mod, pow, shl, shr, or, and, xor }
+
+	function is_mul(oper op) pure public returns (bool) {
+		return op == oper.mul;
+	}
+
+	function return_div() pure public returns (oper) {
+		return oper.div;
+	}
+
+	function op_i64(oper op, int64 a, int64 b) pure public returns (int64) {
+		if (op == oper.add) {
+			return a + b;
+		} else if (op == oper.sub) {
+			return a - b;
+		} else if (op == oper.mul) {
+			return a * b;
+		} else if (op == oper.div) {
+			return a / b;
+		} else if (op == oper.mod) {
+			return a % b;
+		} else if (op == oper.shl) {
+			return a << b;
+		} else if (op == oper.shr) {
+			return a >> b;
+		} else {
+			revert();
+		}
+	}
+
+	function op_u64(oper op, uint64 a, uint64 b) pure public returns (uint64) {
+		if (op == oper.add) {
+			return a + b;
+		} else if (op == oper.sub) {
+			return a - b;
+		} else if (op == oper.mul) {
+			return a * b;
+		} else if (op == oper.div) {
+			return a / b;
+		} else if (op == oper.mod) {
+			return a % b;
+		} else if (op == oper.pow) {
+			return a ** b;
+		} else if (op == oper.shl) {
+			return a << b;
+		} else if (op == oper.shr) {
+			return a >> b;
+		} else {
+			revert();
+		}
+	}
+
+	function op_u256(oper op, uint256 a, uint256 b) pure public returns (uint256) {
+		if (op == oper.add) {
+			return a + b;
+		} else if (op == oper.sub) {
+			return a - b;
+		} else if (op == oper.mul) {
+			return a * b;
+		} else if (op == oper.div) {
+			return a / b;
+		} else if (op == oper.mod) {
+			return a % b;
+		} else if (op == oper.pow) {
+			return a ** uint256(b);
+		} else if (op == oper.shl) {
+			return a << b;
+		} else if (op == oper.shr) {
+			return a >> b;
+		} else {
+			revert();
+		}
+	}
+
+	function op_i256(oper op, int256 a, int256 b) pure public returns (int256) {
+		if (op == oper.add) {
+			return a + b;
+		} else if (op == oper.sub) {
+			return a - b;
+		} else if (op == oper.mul) {
+			return a * b;
+		} else if (op == oper.div) {
+			return a / b;
+		} else if (op == oper.mod) {
+			return a % b;
+		} else if (op == oper.shl) {
+			return a << b;
+		} else if (op == oper.shr) {
+			return a >> b;
+		} else {
+			revert();
+		}
+	}
+
+	function return_u8_6() public pure returns (bytes6) {
+		return "ABCDEF";
+	}
+
+	function op_u8_5_shift(oper op, bytes5 a, uint64 r) pure public returns (bytes5) {
+		if (op == oper.shl) {
+			return a << r;
+		} else if (op == oper.shr) {
+			return a >> r;
+		} else {
+			revert();
+		}
+	}
+
+	function op_u8_5(oper op, bytes5 a, bytes5 b) pure public returns (bytes5) {
+		if (op == oper.or) {
+			return a | b;
+		} else if (op == oper.and) {
+			return a & b;
+		} else if (op == oper.xor) {
+			return a ^ b;
+		} else {
+			revert();
+		}
+	}
+
+	function op_u8_14_shift(oper op, bytes14 a, uint64 r) pure public returns (bytes14) {
+		if (op == oper.shl) {
+			return a << r;
+		} else if (op == oper.shr) {
+			return a >> r;
+		} else {
+			revert();
+		}
+	}
+
+	function op_u8_14(oper op, bytes14 a, bytes14 b) pure public returns (bytes14) {
+		if (op == oper.or) {
+			return a | b;
+		} else if (op == oper.and) {
+			return a & b;
+		} else if (op == oper.xor) {
+			return a ^ b;
+		} else {
+			revert();
+		}
+	}
+
+	function address_passthrough(address a) pure public returns (address) {
+		return a;
+	}
+}

+ 150 - 0
integration/solana/simple.spec.ts

@@ -0,0 +1,150 @@
+import expect from 'expect';
+import { establishConnection } from './index';
+
+describe('Deploy solang contract and test', () => {
+    it('flipper', async function () {
+        this.timeout(50000);
+
+        let conn = await establishConnection();
+
+        let prog = await conn.loadProgram("flipper.so", "flipper.abi");
+
+        // call the constructor
+        await prog.call_constructor(conn, ["true"]);
+
+        let res = await prog.call_function(conn, "get", []);
+
+        expect(res["__length__"]).toBe(1);
+        expect(res["0"]).toBe(true);
+
+        await prog.call_function(conn, "flip", []);
+
+        res = await prog.call_function(conn, "get", []);
+
+        expect(res["__length__"]).toBe(1);
+        expect(res["0"]).toBe(false);
+    });
+
+    it('primitives', async function () {
+        this.timeout(50000);
+
+        let conn = await establishConnection();
+
+        let prog = await conn.loadProgram("primitives.so", "primitives.abi");
+
+        // call the constructor
+        await prog.call_constructor(conn, []);
+
+        // TEST Basic enums
+        // in ethereum, an enum is described as an uint8 so can't use the enum
+        // names programmatically. 0 = add, 1 = sub, 2 = mul, 3 = div, 4 = mod, 5 = pow, 6 = shl, 7 = shr
+        let res = await prog.call_function(conn, "is_mul", ["2"]);
+        expect(res["0"]).toBe(true);
+
+        res = await prog.call_function(conn, "return_div", []);
+        expect(res["0"]).toBe("3");
+
+        // TEST uint and int types, and arithmetic/bitwise ops
+        res = await prog.call_function(conn, "op_i64", ["0", "1000", "4100"]);
+        expect(res["0"]).toBe("5100");
+        res = await prog.call_function(conn, "op_i64", ["1", "1000", "4100"]);
+        expect(res["0"]).toBe("-3100");
+        res = await prog.call_function(conn, "op_i64", ["2", "1000", "4100"]);
+        expect(res["0"]).toBe("4100000");
+        res = await prog.call_function(conn, "op_i64", ["3", "1000", "10"]);
+        expect(res["0"]).toBe("100");
+        res = await prog.call_function(conn, "op_i64", ["4", "1000", "99"]);
+        expect(res["0"]).toBe("10");
+        res = await prog.call_function(conn, "op_i64", ["6", "-1000", "8"]);
+        expect(res["0"]).toBe("-256000");
+        res = await prog.call_function(conn, "op_i64", ["7", "-1000", "8"]);
+        expect(res["0"]).toBe("-4");
+
+
+        res = await prog.call_function(conn, "op_u64", ["0", "1000", "4100"]);
+        expect(res["0"]).toBe("5100");
+        res = await prog.call_function(conn, "op_u64", ["1", "1000", "4100"]);
+        expect(res["0"]).toBe("18446744073709548516"); // (2^64)-18446744073709548516 = 3100
+        res = await prog.call_function(conn, "op_u64", ["2", "123456789", "123456789"]);
+        expect(res["0"]).toBe("15241578750190521");
+        res = await prog.call_function(conn, "op_u64", ["3", "123456789", "100"]);
+        expect(res["0"]).toBe("1234567");
+        res = await prog.call_function(conn, "op_u64", ["4", "123456789", "100"]);
+        expect(res["0"]).toBe("89");
+        res = await prog.call_function(conn, "op_u64", ["5", "3", "7"]);
+        expect(res["0"]).toBe("2187");
+        res = await prog.call_function(conn, "op_i64", ["6", "1000", "8"]);
+        expect(res["0"]).toBe("256000");
+        res = await prog.call_function(conn, "op_i64", ["7", "1000", "8"]);
+        expect(res["0"]).toBe("3");
+
+        // now for 256 bit operations
+        res = await prog.call_function(conn, "op_i256", ["0", "1000", "4100"]);
+        expect(res["0"]).toBe("5100");
+        res = await prog.call_function(conn, "op_i256", ["1", "1000", "4100"]);
+        expect(res["0"]).toBe("-3100");
+        res = await prog.call_function(conn, "op_i256", ["2", "1000", "4100"]);
+        expect(res["0"]).toBe("4100000");
+        res = await prog.call_function(conn, "op_i256", ["3", "1000", "10"]);
+        expect(res["0"]).toBe("100");
+        res = await prog.call_function(conn, "op_i256", ["4", "1000", "99"]);
+        expect(res["0"]).toBe("10");
+        res = await prog.call_function(conn, "op_i256", ["6", "-10000000000000", "8"]);
+        expect(res["0"]).toBe("-2560000000000000");
+        res = await prog.call_function(conn, "op_i256", ["7", "-10000000000000", "8"]);
+        expect(res["0"]).toBe("-39062500000");
+
+        res = await prog.call_function(conn, "op_u256", ["0", "1000", "4100"]);
+        expect(res["0"]).toBe("5100");
+        res = await prog.call_function(conn, "op_u256", ["1", "1000", "4100"]);
+        expect(res["0"]).toBe("115792089237316195423570985008687907853269984665640564039457584007913129636836"); // (2^64)-18446744073709548516 = 3100
+        res = await prog.call_function(conn, "op_u256", ["2", "123456789", "123456789"]);
+        expect(res["0"]).toBe("15241578750190521");
+        res = await prog.call_function(conn, "op_u256", ["3", "123456789", "100"]);
+        expect(res["0"]).toBe("1234567");
+        res = await prog.call_function(conn, "op_u256", ["4", "123456789", "100"]);
+        expect(res["0"]).toBe("89");
+        res = await prog.call_function(conn, "op_u256", ["5", "123456789", "9"]);
+        expect(res["0"]).toBe("6662462759719942007440037531362779472290810125440036903063319585255179509");
+        res = await prog.call_function(conn, "op_i256", ["6", "10000000000000", "8"]);
+        expect(res["0"]).toBe("2560000000000000");
+        res = await prog.call_function(conn, "op_i256", ["7", "10000000000000", "8"]);
+        expect(res["0"]).toBe("39062500000");
+
+
+        // TEST bytesN
+        res = await prog.call_function(conn, "return_u8_6", []);
+        expect(res["0"]).toBe("0x414243444546");
+
+        // TEST bytes5
+        res = await prog.call_function(conn, "op_u8_5_shift", ["6", "0xdeadcafe59", "8"]);
+        expect(res["0"]).toBe("0xadcafe5900");
+        res = await prog.call_function(conn, "op_u8_5_shift", ["7", "0xdeadcafe59", "8"]);
+        expect(res["0"]).toBe("0x00deadcafe");
+        res = await prog.call_function(conn, "op_u8_5", ["8", "0xdeadcafe59", "0x0000000006"]);
+        expect(res["0"]).toBe("0xdeadcafe5f");
+        res = await prog.call_function(conn, "op_u8_5", ["9", "0xdeadcafe59", "0x00000000ff"]);
+        expect(res["0"]).toBe("0x0000000059");
+        res = await prog.call_function(conn, "op_u8_5", ["10", "0xdeadcafe59", "0x00000000ff"]);
+        expect(res["0"]).toBe("0xdeadcafea6");
+
+        // TEST bytes14
+        res = await prog.call_function(conn, "op_u8_14_shift", ["6", "0xdeadcafe123456789abcdefbeef7", "9"]);
+        expect(res["0"]).toBe("0x5b95fc2468acf13579bdf7ddee00");
+        res = await prog.call_function(conn, "op_u8_14_shift", ["7", "0xdeadcafe123456789abcdefbeef7", "9"]);
+        expect(res["0"]).toBe("0x006f56e57f091a2b3c4d5e6f7df7");
+        res = await prog.call_function(conn, "op_u8_14", ["8", "0xdeadcafe123456789abcdefbeef7", "0x00000600"]);
+        expect(res["0"]).toBe("0xdeadcefe123456789abcdefbeef7");
+        res = await prog.call_function(conn, "op_u8_14", ["9", "0xdeadcafe123456789abcdefbeef7", "0x000000000000000000ff"]);
+        expect(res["0"]).toBe("0x000000000000000000bc00000000");
+        res = await prog.call_function(conn, "op_u8_14", ["10", "0xdeadcafe123456789abcdefbeef7", "0xff"]);
+        expect(res["0"]).toBe("0x21adcafe123456789abcdefbeef7");
+
+        // TEST address type. We need to encoding this has a hex string with the '0x' prefix, since solang maps address
+        // to bytes32 type
+        let address = '0x' + conn.payerAccount.publicKey.toBuffer().toString('hex');
+        console.log(`Using address ${address} for testing`)
+        res = await prog.call_function(conn, "address_passthrough", [address]);
+        expect(res["0"]).toBe(address);
+    });
+});

+ 18 - 21
src/emit/mod.rs

@@ -1163,9 +1163,9 @@ pub trait TargetRuntime<'a> {
                 let bits = left.get_type().get_bit_width();
 
                 if bits > 64 {
-                    let l = contract.builder.build_alloca(left.get_type(), "");
-                    let r = contract.builder.build_alloca(left.get_type(), "");
-                    let o = contract.builder.build_alloca(left.get_type(), "");
+                    let l = contract.build_alloca(function, left.get_type(), "");
+                    let r = contract.build_alloca(function, left.get_type(), "");
+                    let o = contract.build_alloca(function, left.get_type(), "");
 
                     contract.builder.build_store(l, left);
                     contract.builder.build_store(r, right);
@@ -1220,12 +1220,9 @@ pub trait TargetRuntime<'a> {
                 if bits > 64 {
                     let f = self.udivmod(contract, bits);
 
-                    let rem = contract
-                        .builder
-                        .build_alloca(left.into_int_value().get_type(), "");
-                    let quotient = contract
-                        .builder
-                        .build_alloca(left.into_int_value().get_type(), "");
+                    let rem = contract.build_alloca(function, left.into_int_value().get_type(), "");
+                    let quotient =
+                        contract.build_alloca(function, left.into_int_value().get_type(), "");
 
                     let ret = contract
                         .builder
@@ -1269,8 +1266,8 @@ pub trait TargetRuntime<'a> {
                 if bits > 64 {
                     let f = self.sdivmod(contract, bits);
 
-                    let rem = contract.builder.build_alloca(left.get_type(), "");
-                    let quotient = contract.builder.build_alloca(left.get_type(), "");
+                    let rem = contract.build_alloca(function, left.get_type(), "");
+                    let quotient = contract.build_alloca(function, left.get_type(), "");
 
                     let ret = contract
                         .builder
@@ -1363,12 +1360,9 @@ pub trait TargetRuntime<'a> {
                 if bits > 64 {
                     let f = self.udivmod(contract, bits);
 
-                    let rem = contract
-                        .builder
-                        .build_alloca(left.into_int_value().get_type(), "");
-                    let quotient = contract
-                        .builder
-                        .build_alloca(left.into_int_value().get_type(), "");
+                    let rem = contract.build_alloca(function, left.into_int_value().get_type(), "");
+                    let quotient =
+                        contract.build_alloca(function, left.into_int_value().get_type(), "");
 
                     let ret = contract
                         .builder
@@ -1411,8 +1405,8 @@ pub trait TargetRuntime<'a> {
 
                 if bits > 64 {
                     let f = self.sdivmod(contract, bits);
-                    let rem = contract.builder.build_alloca(left.get_type(), "");
-                    let quotient = contract.builder.build_alloca(left.get_type(), "");
+                    let rem = contract.build_alloca(function, left.get_type(), "");
+                    let quotient = contract.build_alloca(function, left.get_type(), "");
 
                     let ret = contract
                         .builder
@@ -5240,8 +5234,11 @@ impl<'a> Contract<'a> {
             .expect("function missing entry block");
         let current = self.builder.get_insert_block().unwrap();
 
-        self.builder
-            .position_before(&entry.get_first_instruction().unwrap());
+        if let Some(instr) = entry.get_first_instruction() {
+            self.builder.position_before(&instr);
+        } else {
+            self.builder.position_at_end(entry);
+        }
 
         let res = self.builder.build_alloca(ty, name);