Solidity++

Solidity++ 和 Solidity 的语法基本上相同,他们之间的差异主要是因为 Solidity++ 是异步的而 Solidity 是同步的

Solidity++ 删除的语法

tx.gasprice;
block.coinbase;
block.difficulty;
block.gaslimit;
blockhash(param);
gasleft();
msg.gas;
selfdestruct(_owner);
suicide(_addr);
address(_addr).send(_amount);

以上示例的语法在 Solidity++ 中全部失效

所有与 ecrecover,ripemd160 相关的语法全部失效

delegatecall 方法暂时不提供

Solidity 中内联汇编的语法暂时不提供

Solidity++ 新增和修改的语法

Solidity++ 新增的语法如下:

bytes32 b1 = fromhash();
uint height = accountheight();
bytes32 b2 = prevhash();
uint64 random = random64();
uint64 newRandom = nextrandom();

"fromhash ()" 返回请求交易的哈希值

"accountheight ()" 获取账户链上最新块的高度

"prevhash ()" 获取账户链上最新块的哈希

"random64 ()" 获取一个 uint64 的随机数,在一次合约运行过程中返回同一个值

"nextrandom ()" 获取一个 uint64 的随机数,在一次合约运行过程中返回不同的值

Solidity++ 的 address 和 tokenId 定义的语法如下:

tokenId token01 = tokenId("tti_2445f6e5cde8c2c70e446c83");
tokenId token02 = "tti_2445f6e5cde8c2c70e446c83";
address addr01 = address("vite_0102030405060708090807060504030201020304eddd83748e");
address addr02 = "vite_0102030405060708090807060504030201020304eddd83748e";

获取交易中的转账在 Solidity 中的语法如下:

msg.value

Solidity++ 中获取转账金额的语法做了修改 (由 value 变成 amount),并新增了获取交易中的转账 tokenId 的语法:

msg.amount;
msg.tokenid;

获取当前账户某个 tokenId 的余额或者获取其他账户某个 tokenId 的余额,

Solidity 中的语法是如下

address.balance

直接获取某个账户的余额,因为现在一个账户可以拥有多种代币,因此在 Solidity++ 中获取代币余额的时候需要指定 tokenId,另外现在只能读取自己的余额

balance(_tokenId)

在 Solidity 中发送以太币到一个地址可以使用 transfer 方法

address(_addr).transfer(_amount);

因为在 vite 中新增了 tokenId 的概念,所以在 Solidity++ 中进行交易的时候需要加上需要交易的 tokenId

address(_addr).transfer(_tokenId, _amount);

Solidity 中以太币的单位为:wei/szabo/finney/ether

1 ether = 1000 finney, 1 finney = 1000 szabo, 1 szabo = 1000000000000 wei

在 Solidity++ 中 vite 币的单位为:attov/vite

1 vite = 1000000000000000000 attov

在 Solidity++ 中,所有与 sha256,sha3 相关的语法都替换为 blake2b

Solidity++ 异步语法

在 Solidity++ 中,合约之间不可以通过方法调用来进行交互,只能进行消息传递

也就是说,在 Solidity++ 中 public 类型的方法不再对外提供访问接口,并且 function 不可以被定义为 external 类型,function 只可以是 public,private 和 internal 类型

同时,合约内 public 类型的静态变量也无法被合约外部访问

示例

pragma soliditypp ^0.4.3;
contract A {
   message sum(uint result);
   onMessage add(uint a, uint b) {
        uint result = a + b;
        address sender = msg.sender;
        send(sender, sum(result));
   }
}
contract B {
    uint total;
    message add(uint a, uint b);
    onMessage invoker(address addr, uint a, uint b) {
       send(addr, add(a, b));
    }
    onMessage sum(uint result) {
        if (result > 10) {
           total += result;
       }
    }
}

message: 关键字,定义一条消息,包括消息的名称,和传递的参数,"message sum (uint result)" 就定义了一条 sum 消息,其中需要传递一个 uint 类型的参数

onMessage: 关键字,定义一种消息的监听器,包括消息的名字,和接收的参数,以及对消息的处理逻辑,"onMessage add (uint a, uint b)" 就定义了一个消息的监听器,监听的是名字为 add,接收的是两个 uint 类型的参数

send: 关键字,是一条 message 的发送操作,需要有两个参数,一个是接收消息的地址 (address),另一个是发送的消息 (message)

一个合约可以定义 message,这个 message 的 send 操作只能在合约内执行,如果定义的消息希望被某一个合约处理,则对于 message 的名称和传递参数,需要根据该合约的消息监听器而定

也就是说,如果合约 A 需要给合约 B 发送一条消息并且希望合约 B 对消息进行处理,那么合约 B 必须有某一种类型消息的监听器,合约 A 需要按照合约 B 的消息监听器的名字和参数来定义消息并进行发送

一个合约可以定义消息监听器,消息监听器规定了这个合约可以接收的消息类型,只有符合该合约定义的消息监听器规范的消息才会被该合约正常接收和处理

注意,消息监听器不能像 function 一样被调用

如上所示:

合约 A 定义了一个 "add (uint a, uint b)" 的消息监听器,合约 B 定义了一个 "sum (uint result)" 的消息监听器,分别表示 A 和 B 会接收这两种类型的消息并进行处理

合约 B 因为要给 A 发送消息,因此合约 B 要按照 A 定义的 add 的消息监听器的规范定义消息,合约 A 在 add 消息的监听器中,要给合约 B 发送消息,因此合约 A 要按照 B 定义的 sum 的消息监听器的规范定义 sum 消息

Solidity++ 中的 getter

在 Solidity++ 中,合约间的交互是通过消息传递的机制进行的,是异步的,因此合约内 public 类型的静态变量无法被合约外部访问,然而对于合约内部的状态,Solidity++ 提供了一种特殊的访问方式

pragma soliditypp ^0.4.3;
contract A {
    uint magic = 0;
    getter getMagic() returns(uint256) {
        return magic;
    }
    getter getMagicAdd(uint256 m) returns(uint256) {
        return calculate(m);
    }
    function calculate(uint256 m) public view returns(uint256) {
        return m + magic;
    }
}

如上例所示,在 Solidity++ 中定义了一个 getter 关键字,该关键字有如下特性:

首先,getter 定义的是一个方法

其次,getter 定义的方法只需要定义方法名和入参,必须有返回值,该方法可以用来获取合约的状态但不能修改状态,仅向外部提供查询的接口

再次,getter 定义的方法经过编译后的代码不会上链,因此 getter 定义的方法不能获取交易的信息,如调用 "msg.amount","msg.tokenid" 等

另外,getter 定义的方法不能和其他链交互,如发交易,发送消息等,不能调用 "require","revert" 方法

最后,getter 定义的方法体内可以调用 function,其调用的 function 应该定义为 view 类型

Solidity++ 合约示例

定义一个合约,合约的主要功能是给一个地址和金额的列表,合约给指定的地址转账指定金额数

// 告诉该合约用的是0.4.3版本的soliditypp编写,并且这些代码具有向上兼容性。保证不会在不同soliditypp编译版本下编译会出现不同的行为。
pragma soliditypp ^0.4.3;
// 定义一个合约A
contract A {
     // 定义一个消息监听器,合约只能通过消息的传递进行交互,因此凡是需要向外部提供的接口都需要定义成监听器
     // 监听器需要定义监听的消息名称和消息所带的参数,不需要定义可见性,监听器没有返回值
     // 在这里监听器的名称是transfer,传的参数是一个uint类型的数组body,数组的第奇数位的元素是地址,偶数位的元素是地址对应的需要转账的金额数
     onMessage transfer(uint[] calldata body) payable {
         // 判断入参的长度是否是偶数,因为地址和金额数是一一对应的
         require(body.length%2==0);
         uint256 totalAmount = 0;
         for(uint i = 0; i < body.length; i=i+2) {
             uint addr = body[i];
             uint amount = body[i+1];
             totalAmount = totalAmount + amount;
             require(totalAmount >= amount);
             if(amount > 0) {
                // 向addr地址转账,金额是amount,转账的tokenId是msg.tokenid
                address(addr).transfer(msg.tokenid, amount);
             }
         }
         require(totalAmount == msg.amount);
     }
}