合约 API与内置类库

本文汇总了 C++ 合约开发过程中合约平台所支持的合约 API,并通过示例对合约开发过程中会用到的内置类库(时间格式化、第三方库)进行介绍。

说明

如果没有特殊说明,则该API在非TEE和TEE版本中都支持。也许您可以看到以下API调用了一些更加基础的库函数,但请您不要擅自使用那些函数,因为如果使用不当可能造成您的合约行为不符合预期。请只使用本文档中列出的API。

合约 API 根据功能主要分为以下 4 类:

区块链交互 API

  • bool CheckAccount(const Identity& id/*in*/);

检查当前状态下,id指定的账号是否存在。

请求参数:

参数

类型

说明

id

Identity

要查询的账号 ID

返回值:

参数

类型

说明

result

bool

账号 ID 存在则返回 true,否则返回 false

  • uint64_t GetBlockNumber();

    获取上一个区块的区块号。

返回值:

参数

类型

说明

result

uint64_t

最新已经形成的区块号

  • int GetBlockHash(uint64_t block_number/*in*/, std::string& block_hash/*out*/);

    获取指定区块的hash。

请求参数:

参数

类型

说明

block_number

uint64_t

要查询的区块号

block_hash

std::string&

获取到的区块hash,原始字节流(注意不是16进制格式); 若查询的区块不存在,则block_hash的值维持原值

返回值:

参数

类型

说明

result

int

如果要查询的区块不存在,则返回1,否则返回0

  • uint64_t GetBlockTimeStamp();

获取上一个区块的时间戳。

返回值:

参数

类型

说明

result

uint64_t

最新已经形成的区块的时间戳,单位:ms

  • Identity GetOrigin();

获取交易的发起者的 ID。

返回值:

参数

类型

说明

result

Identity

出参,本次合约被调用的交易发起者 ID,参考 合约运行的上下文环境

  • int GetAuthMap(const Identity& id/*in*/, std::map<std::string,uint32_t>& auth);

获取账号权限列表。

请求参数:

参数

类型

说明

id

Identity

入参,要查询的账号 ID

auth

std::map<std::string, uint32_t>&

出参,获取到的 <公钥,权重> map,如果返回非 0,auth维持原值。

注意:公钥不是16进制格式。

返回值:

参数

类型

说明

result

int

若 ID 指定的账号不存在或被冻结,返回 1;否则返回 0。

  • int GetBalance(const Identity& id/*in*/, int64_t& value/*out*/);

获取指定账号的余额。

请求参数:

参数

类型

说明

id

const Identity&

账号 ID

value

uint64_t&

该账号的余额。若返回值不为0,value维持原值。

返回值:

参数

类型

说明

result

int

若 ID 对应的账户不存在或该账户被冻结则返回1,否则返回0。

  • int GetCode(const Identity& id/*in*/, std::string& code/*out*/);

获取指定合约的代码。

请求参数:

参数

类型

说明

id

const Identity&

合约 ID

code

std::string&

获取到的合约的代码,若返回值不为0,code维持原值。若得到code值超过1M,则会抛出异常信息

返回值:

参数

类型

说明

result

int

若 ID 对应的账户不存在或该账户被冻结则返回1,否则返回0。

  • int GetCodeHash(const Identity& id/*in*/, std::string& hash/*out*/);

获取指定合约的代码 hash。

请求参数:

参数

类型

说明

id

const Identity&

账号 ID

hash

std::string&

合约的代码hash,原始字节串,非16进制字符串。

返回值:

参数

类型

说明

result

int

若 ID 对应的账户不存在或该账户被冻结则返回1,否则返回0。

  • int GetRecoverKey(const Identity& id/*in*/, std::string& recover_key/*out*/);

获取指定账号的恢复公钥。

请求参数:

参数

类型

说明

id

const Identity&

账号 ID

recover_key

std::string&

账户的恢复公钥,若函数返回非0,参数recover_key维持原值

返回值:

参数

类型

说明

result

int

若 ID 对应的账户不存在或该账户被冻结则返回1,否则返回0。

  • int GetAccountStatus(const Identity& id/*in*/, uint32_t& status/*out*/);

获取指定账号的状态。

请求参数:

参数

类型

说明

id

int

账号 ID

status

uint32_t

账号的状态代码,若函数返回非 0, 则参数 status维持原值。status的定义参见合约平台内置数据类型中的 ACCOUNT_STATUS

返回值:

参数

类型

说明

result

int

若 ID 对应的账号不存在返回 1,否则返回 0。

  • std::string GetTxHash();

获取交易的 hash(触发交易的 hash)。

返回值:

参数

类型

说明

result

std::string

本合约触发交易的hash,原始字节串,非16进制格式。

  • int TransferBalance(const Identity& to/*in*/, int64_t balance/*in*/);

向指定账户转移资产。

请求参数:

参数

类型

说明

to

const Identity&

资产接收者的地址

balance

int64_t

要转移的资产数量

返回值:

参数

类型

说明

result

int

转移成功返回 0,否则返回 1。

  • int Revert(const std::string& exception/*in*/);

立即终止该合约的运行,并给区块链发送信号,附带 exception内容,表明该合约被异常终止。

请求参数:

参数

类型

说明

exception

const std::string&

报出的错误信息,该自动会被存放到交易回执的output字段中

返回值:

参数

类型

说明

result

int

恒为 0

  • int Require(bool condition/*in*/, const std::string& exception/*in*/);

    若条件condition值为false,则调用Revert

    if (!condition) {
      Revert(exception);
    }

    请求参数:

参数

类型

说明

condition

bool

需要判断的条件

exception

const std::string&

报出的错误信息,该自动会被存放到交易回执的output字段中

返回值:

参数

类型

说明

result

int

恒为 0

  • template <class T>int Log(const T& data/*in*/, const std::vector<std::string>& topics/*in*/);

产生通知事件,data字段会做序列化, 每个topic会以十六进制字符串的格式记录在交易回执中。

请求参数:

参数

类型

说明

data

const T&

用户自定义日志内容,仅支持 可序列化数据类型

topics

std::vector

&

事件主题,其序列化后的大小不能大于1MB,否则会返回失败,事件不会记录在交易回执中。

返回值:

参数

类型

说明

result

int

失败返回1,成功返回0

使用示例如下:

std::string topic1 = "good";
std::string topic2 = "morning";
Log("hi"s, {topic1, topic2});
// 上链后对应字段为:
// "data":"026869"
// "topics":["676f6f64","6d6f726e696e67"],
// data字段会先做序列化, "hi"序列化后, 对应"026869"
// 针对topic字段, "good"对应"676f6f64", "morning"对应"6d6f726e696e67"
  • template <typename T, typename... Args> inline decltype(auto) CallContract(const Identity& contract_id/*in*/, const std::string& method/*in*/, uint64_t value/*in*/, uint64_t gas/*in*/, Args... args);

调用另一个合约。

说明

这是Contract类的成员方法,只有继承了Contract的合约才能调用该方法。

请求参数:

参数

类型

说明

contract_id

const Identity&

要调用的合约的Identity

method

const std::string&

被调用的合约方法名称

value

uint64_t

给被调用合约转移的资产数量

gas

uint64_t

给被调用合约的gas数量,填写0表示将本合约所有可用gas给被调用合约使用

args

任意个不定类型数参数

调用合约传入的参数列表,取决于被调用合约方法接收几个参数。

返回值:

参数

类型

说明

返回值

struct{int code; T result; std::string msg;}

返回结构体

code

int

- 0:子合约正常

- 1:子合约不存在或给子合约转账失败

- 10200:子合约gas不足

- 10201:子合约执行过程中出现异常

- 10622:子合约的字节码非法(可能原因子合约不是wasm合约)

result

T

如果code为0, 该值为被调用方法的返回值;否则该值无意义。若T为void,则没有该字段

msg

std::string

- 若code为0,该值无意义

- 若code为10201,该值表示被调用合约的抛出的异常信息

  • int DelegateCall(const Identity& contract_id/*in*/, const std::string& method/*in*/, ...);

代理调用另一个合约。

请求参数:

参数

类型

说明

contract_id

const Identity&

要调用的合约 ID

method

const std::string&

被调用的合约方法名

args

自定义的不定类型参数数量

调用合约传入的参数列表,取决于被调用合约方法接收几个参数。

返回值:

参数

类型

说明

result

int

正常调用返回 0,否则返回 1。

  • uint64_t GetGas();

获取本合约当前剩余的可用gas数量。如果是交易调用某个合约,则 gas 值就是交易中指定的 gas。如果是合约调用另一个合约,则 gas 值是 CallContract()方法中指定的 gas。如果是合约代理调用另一个合约,那么 gas 值与父合约中的GetGas()值相同。

返回值:

参数

类型

说明

result

uint64_t

本合约当前剩余的可用gas数量

  • uint64_t GetValue();

获取本次合约调用本合约接收的资产数量。如果是交易调用合约,value的值就是交易中指定的 value值;如果是合约调用另一个合约,value的值就是 CallContract()方法中指定的 value值。

返回值:

参数

类型

说明

result

uint64_t

获取的 value

  • std::string GetData();

获取触发交易的 data字段值(本次合约调用传入的参数)。

返回值:

参数

类型

说明

result

std::string

交易调用本合约时,传递的inputdata内容,原始字节串,非16进制

  • Identity GetSender();

返回调用者的 ID(账号或合约),合约执行过程中,消耗调用方(sender)的 gas。

返回值:

参数

类型

说明

result

Identity

调用者 ID,参见 合约运行的上下文环境

  • Identity GetSelf();

获取本合约的 ID。

返回值:

参数

类型

说明

result

Identity

本合约的 ID

  • uint32_t GetRelatedTransactionListSize(const Identity& recipient_id,uint64_t deposit_flag,uint64_t& count);

    获取指定账户、指定flag的关联存证交易数量。

请求参数:

参数

类型

说明

recipient_id

const Identity&

要查询的账户,即在关联存证交易中的to账户

deposit_flag

uint64_t

指定的关联存证的flag

count

uint64_t&

查到的结果数量

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10350: 失败,交易不存在

  • uint32_t GetRelatedTransactionList(const Identity& recipient_id,uint64_t deposit_flag,uint64_t start_indexuint32_t number,std::vector<std::string>& tx_list);

    查询指定账户、指定flag的关联存证交易列表。

请求参数:

参数

类型

说明

recipient_id

const Identity&

要查询的账户,即在关联存证交易中的to账户

deposit_flag

uint64_t

指定的关联存证的flag

start_index

uint64_t

指定开始索引

number

uint32_t

指定个数

tx_list

std::vector<std::string>&

获取到的结果

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10350: 失败,start_index或number错误

  • uint32_t GetTransactionSender(const std::string& tx_hash, Identity& sender);

    查询指定交易的发送者。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

sender

Identity&

该交易的发送者

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10316: 失败,交易类型不是存证交易

- 10310: 失败,交易不存在

  • uint32_t GetTransactionReceiver(const std::string& tx_hash Identity& receiver);

    查询指定交易的接收者。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

receiver

Identity&

该交易的接收者

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10316: 失败,交易类型不是存证交易

- 10310: 失败,交易不存在

  • uint32_t GetTransactionTimestamp(const std::string& tx_hash, uint64_t& timestamp);

    查询指定交易的上链时间。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

timestamp

uint64_t&

该交易的上链时间

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10316: 失败,交易类型不是存证交易

- 10310: 失败,交易不存在

  • uint32_t GetTransactionData(const std::string& tx_hash, std::string& data);

    查询指定交易存证数据。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

data

std::string&

该交易的存证数据,其内容是关联性标识和用户数据的组合内容

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10316: 失败,交易类型不是存证交易

- 10310: 失败,交易不存在

  • uint32_t GetTransactionBlockIndex(const std::string& tx_hash, uint64_t& block_number, uint32_t& index);

    查询指定交易的所在区块和在区块中的顺序。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

block_number

uint64_t&

该交易所在区块号

index

uint32_t&

该交易在区块中的顺序

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10310: 失败,交易不存在

  • uint32_t GetTransactionDepositFlag(const std::string& tx_hash, uint64_t& deposit_flag);

    查询指定交易的关联性标识。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

deposit_flag

uint64_t&

该交易的关联性标识

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10316: 失败,交易类型不是存证交易

- 10310: 失败,交易不存在

  • uint32_t GetConfidentialDepositData(const std::string& tx_hash, std::string& data);

    查询指定交易机密存证数据。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

data

std::string&

该交易的存证数据,其内容是关联性标识和用户数据的组合内容

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10316: 失败,交易类型不是存证交易

- 10310: 失败,交易不存在

  • uint32_t GetConfidentialDepositFlag(const std::string& tx_hash, uint64_t& deposit_flag);

    查询指定交易机密存证的关联性标识。

请求参数:

参数

类型

说明

tx_hash

const std::string&

要查询的交易hash,长度32字节,只支持原始格式,不支持16进制格式

deposit_flag

uint64_t&

该交易的关联性标识

返回值:

参数

类型

说明

result

uint32_t

- 0: 成功

- 10315: 失败,交易所在区块超出了查询限制

- 10316: 失败,交易类型不是存证交易

- 10310: 失败,交易不存在

  • int CreateContract(const Identity& src, const Identity& new_id);

    根据合约模版创建新合约。

请求参数:

参数

类型

说明

src

const Identity&

合约模版地址

new_id

const Identity&

所创建的新合约地址

返回值:

参数

类型

说明

result

int

创建成功返回0,否则返回1

如果创建成功,则新合约:

- ID:传入的new_id

- Balance:0

- AuthMap:和合约模版一致

- RecoverKey:和合约模版一致

- EncryptionKey:和合约模版一致

- key,value对为空

  • bool IsLocalTx();

    判断当前交易的执行环境是否是local执行。

请求参数:无

返回值:

参数

类型

说明

result

bool

表示当前交易执行环境是否local环境

  • bool GetTargetAddress(std::string targetName, Identity& id);

    采用平台特定的hash算法计算 targetName字符串的hash值, 平台的hash算法在创世块中配置, 可以是: sha256, SM3, KECCAK256...

请求参数:

参数

类型

说明

targetName

std::string

hash计算的目标字符串

id

Identity&

hash计算结果

返回值:

参数

类型

说明

result

bool

targetName hash计算是否成功, 失败返回 false, 此时 id的内容不变, 成功返回 true, id值有效

工具类 API

  • template <class T> std::string pack(T t);

t序列化为 std::string。

请求参数:

参数

类型

说明

t

T

要序列化的数据,支持的数据类型见 可序列化数据类型

返回值:

参数

类型

说明

result

std::string

序列化结果

  • template <typename T> T unpack(const std::string& b);

将 std::string 反序列化为指定类型的数据。

请求参数:

参数

类型

说明

b

std::string

要解析的数据内容

返回值:

参数

类型

说明

result

T

解析结果,支持的数据类型见 可序列化数据类型

packunpack使用示例:

```C++

std::string buff = pack(“hello”s);std::string str = unpack

(buff);//str的值为hello

std::string buff = pack(1234);int n = unpack

(buff);//n的值为1234

```
  • bool Digest(const std::string& data/*in*/, DigestType type/*in*/, std::string& output/*out*/);

返回 data的 SHA256 散列值。

请求参数:

参数

类型

说明

data

const std::string&

要 hash 的数据

type

DigestType

散列算法,支持的散列算法: SHA256,SM3

output

std::string&

对data进行散列的结果,原始字节串,非16进制格式

返回值:

参数

类型

说明

result

bool

如果输入不支持的type类型,则返回false,如果计算成功则返回true

  • bool VerifyRsa(const std::string &pk/*in*/, const std::string &sig/*in*/, const std::string &msg/*in*/, DigestType hash_type=SHA256);

验证一个 RSA 签名是否有效。

请求参数:

参数

类型

说明

pk

const std::string&

DER格式的公钥

sig

const std::string&

签名,必须是PKCS#1编码的格式

msg

const std::string&

源消息

hash_type

DigestType

散列算法。默认为SHA256,可选值:SHA256, SHA1

返回值:

参数

类型

说明

result

bool

如果验证通过返回 true,否则返回 false。

  • std::string Hex2Bin(const std::string& input/*in*/);

Hex字符串转字节串std::string。

请求参数:

参数

类型

说明

input

const std::string&

16 进制字节串

返回值:

参数

类型

说明

result

std::string

若输入的 input是非法的 16 进制字节串,返回空 std::string,否则返回转换的结果。

  • std::string Bin2Hex(const std::string& input/*in*/, bool uppercase=false/*in*/);

字节串转 16 进制字符串。

请求参数:

参数

类型

说明

input

const std::string&

要转换的字节串。

uppercase

bool

是否是大写,默认 false。

返回值:

参数

类型

说明

result

std::string

转换结果

  • bool Base64Encode(const std::string& input/*in*/, std::string& output/*out*/);

base64编码。

请求参数:

参数

类型

说明

input

const std::string&

进行base64编码的原数据,不允许为空,若为空则返回false。

output

std::string

base64编码结果。若返回值为false,output不会被修改。

返回值:

参数

类型

说明

result

bool

如果编码成功返回true,否则返回false。

  • bool Base64Decode(const std::string& input/*in*/, std::string& output/*out*/);

base64解码。

请求参数:

参数

类型

说明

input

const std::string&

base64编码的字符串

output

std::string

对input进行base64解码的结果,若返回值为false,output不会被修改

返回值:

参数

类型

说明

result

bool

如果input是非法的base64字符串,则返回false,否则返回true

  • bool Ecrecovery(const std::string& hash/*in*/, const std::string signature/*in*/, Identity& id/*out*/);

根据 hash 和签名恢复 ID。

请求参数:

参数

类型

说明

hash

const std::string&

消息的hash

signature

std::string

消息的签名

id

Identity&

要恢复的 ID,如果返回值为false,则Identity不会被修改

返回值:

参数

类型

说明

result

bool

如果 hash 和 signature 非法或不匹配,则返回false,恢复失败。如果恢复成功则返回true。

  • bool VerifyMessageSM2(const std::string& pk, const std::string& sig, const std::string& msg);

    验证SM2国密签名。

请求参数:

参数

类型

说明

pk

const std::string&

asn1 ECC 公钥

sig

const std::string&

(r, s, v) (65 bytes) 或 ASN.1 编码的格式 (<=72 字节)

msg

const std::string&

原始消息

返回值:

参数

类型

说明

result

bool

- 如果验证签名成功,返回true;

- 如果验证签名失败,返回false。

  • bool VerifyMessageECCK1(const std::string& pubkey, const std::string& sig, const std::string& msg, DigestType hash_type);

    验证ECC椭圆曲线K1产生的签名。

请求参数:

参数

类型

说明

pubkey

const std::string&

asn1 ECC pubkey格式或 65 字节长的压缩格式

sig

const std::string&

(r, s, v) (65 bytes) 或 ASN.1 编码的格式 (<=72 字节)

msg

const std::string&

原始消息

hash_type

DigestType

散列的算法,支持的值:

- DigestType::SHA256

- DigestType::SHA1

返回值:

参数

类型

说明

result

bool

- 如果验证签名成功,返回true;

- 如果验证签名失败,返回false。

  • bool VerifyMessageECCR1(const std::string& pubkey, const std::string& sig, const std::string& msg, DigestType hash_type);

    验证ECC椭圆曲线R1产生的签名。

请求参数:

参数

类型

说明

pubkey

const std::string&

asn1 ECC pubkey格式或 65 字节长的压缩格式

sig

const std::string&

(r, s, v) (65 bytes) 或 ASN.1 编码的格式 (<=72 字节)

msg

const std::string&

原始消息

hash_type

DigestType

散列的算法,支持的值:

- DigestType::SHA256

- DigestType::SHA1

返回值:

参数

类型

说明

result

bool

- 如果验证签名成功,返回true;

- 如果验证签名失败,返回false。

  • int BellmanSnarkVerify(const std::string& verification_key, const std::vector<std::string>& inputs, const std::string& proof);

    验证zksnarks的proof是否合法。

请求参数:

参数

类型

说明

verification_key

const std::string&

setup阶段产生的验证key

inputs

const std::vector<std::string>&

公开输入

proof

const std::string&

零知识证明的证据

返回值:

参数

类型

说明

result

int

- 如果验证proof通过,返回0;

- 如果验证签名失败,返回对应的错误码。

Pedersen密码学API

说明

以下Pedersen密码学API仅在非TEE版本中支持。

  • int32_t RangeProofVerify(const std::string& proof, const std::vector<PC>& pc_list);

    Pedersen范围验证。

请求参数:

参数

类型

说明

proof

const std::string&

证据

pc_list

const std::vector<std::string>&

pedersen commitment

返回值:

参数

类型

说明

result

int32_t

- RET_RANGEPROOF_VERIFY_PASS 0X00000100验证通过;

- RET_RANGEPROOF_VERIFY_FAIL 0X00000101验证不通过;

- RET_RANGEPROOF_ERROR_*出错。

  • int AddPedersenCommit(PC& PC_result, const PC& PC_left, const PC& PC_right);

    PC相加,PC即std::string。

请求参数:

参数

类型

说明

PC_result

std::string&

PC相加结果

PC_left

const std::vector<std::string>&

相加的左PC

PC_right

const std::vector<std::string>&

相加的右PC

返回值:

参数

类型

说明

result

int32_t

- RET_RANGEPROOF_SUCCESS 0X00000000成功;

- RET_RANGEPROOF_ERROR_*出错。

  • int SubPedersenCommit(PC& PC_result, const PC& PC_left, const PC& PC_right);

    PC相减,PC即std::string。

请求参数:

参数

类型

说明

PC_result

std::string&

PC相减结果

PC_left

const std::vector<std::string>&

左PC

PC_right

const std::vector<std::string>&

右PC

返回值:

参数

类型

说明

result

int32_t

- RET_RANGEPROOF_SUCCESS 0X00000000成功;

- RET_RANGEPROOF_ERROR_*出错。

  • int32_t CalculatePedersenCommit(PC& dst_pc, const PC& src_pc, const std::vector<PC>& positive, const std::vector<PC>& negative);

    PC计算。

请求参数:

参数

类型

说明

dst_pc

PC&

PC结果

src_pc

const PC&

PC初值

positive

const std::vector<PC>&

正PC列表

negative

const std::vector<PC>&

负PC列表

返回值:

参数

类型

说明

result

int32_t

- RET_RANGEPROOF_SUCCESS 0X00000000成功;

- RET_RANGEPROOF_ERROR_*出错。

  • int PedersenCommitEqualityVerify(const std::vector<PC>& positive, const std::vector<PC>& negative);

    PC等式验证。

请求参数:

参数

类型

说明

positive

const std::vector<PC>&

正PC列表

negative

const std::vector<PC>&

负PC列表

返回值:

参数

类型

说明

result

int32_t

- RET_RANGEPROOF_VERIFY_PASS 0X00000100验证通过;

- RET_RANGEPROOF_VERIFY_FAIL 0X00000101验证不通过;

- RET_RANGEPROOF_ERROR_*出错。

ElGamal隐私保护API(半同态加密)

说明

以下ElGamal隐私保护API采用半同态加密技术,并且仅在非TEE版本中支持。

  • int LiftedElgamalContractHomomorphicAdd( const std::string& first, const std::string& second, std::string& res);

    计算两个密文相加。

请求参数:

参数

类型

说明

first

const std::string&

第一个密文原始字节串,长度要求为68字节,否则返回2000

second

const std::string&

第二个密文原始字节串,长度要求为68字节,否则返回2000

res

std::string&

两个密文相加结果,长度为68字节

返回值:

参数

类型

说明

result

int

- 1:执行成功;

- 0:执行失败,非法的密文;

- 2000:参数格式错误。

  • int LiftedElgamalContractHomomorphicSub(const std::string& first, const std::string& second, std::string& res);

    计算两个密文相减。

请求参数:

参数

类型

说明

first

const std::string&

第一个密文原始字节串,长度要求为68字节,否则返回2000

second

const std::string&

第二个密文原始字节串,长度要求为68字节,否则返回2000

res

std::string&

两个密文相减结果,长度为68字节

返回值:

参数

类型

说明

result

int

- 1:执行成功;

- 0:执行失败,非法的密文;

- 2000:参数格式错误。

  • int LiftedElgamalScalarMultiply(const std::string& src, uint64_t scalar, std::string& res);

    同态相乘。

请求参数:

参数

类型

说明

src

const std::string&

乘法密文原始字节串,长度要求为68字节,否则返回2000

scalar

uint64_t

乘法标量

res

std::string&

乘法结果,长度为68字节

返回值:

参数

类型

说明

result

int

- 1:执行成功;

- 0:执行失败,非法的密文;

- 2000:参数格式错误。

  • int LiftedElgamalContractZeroCheckVerify(const std::string& ciphertext, const std::string& proof, int& verify_result);零值检测。

请求参数:

参数

类型

说明

ciphertext

const std::string&

单个Elgamal密文原始字节串,长度要求68,否则返回10001

proof

const std::string&

证据

verify_result

int&

检测结果:

- 1: 检测通过

- 0: 检测不通过

返回值:

参数

类型

说明

result

int

若返回结果不为1,则verify_result的值没有意义。

- 1:函数执行成功;

- 0:函数执行失败;

- 10001:参数格式错误。

  • int LiftedElgamalContractRangeVerify(const std::vector<std::string>& ciphertext, const int per_value_bit_size, const std::string& public_key, const std::string& proof, int& verify_result);

    范围检测。

请求参数:

参数

类型

说明

ciphertext

const std::vector<std::string>&

密文列表,每个密文要求68字节,否则报错10001

per_value_bit_size

int

验证范围证明时,证明验证的范围

public_key

const std::string&

公钥,长度33字节

proof

const std::string&

范围证明的证据

verify_result

int&

检测结果:

- 1: 检测通过

- 0: 检测不通过

返回值:

参数

类型

说明

result

int

若返回结果不为1,则verify_result的值没有意义。

- 1:函数执行成功;

- 0:函数执行失败;

- 10001:参数格式错误。

调试类 API

  • int print(const char* format, ...);

打印输出函数。

请求参数:

参数

类型

说明

format

const char*

格式与 C99 中 printf相仿,不支持 %f、%F、%g、%e、%E、%G。

返回值:

参数

类型

说明

result

int

恒为 0

内置类库

时间格式化

wasm 合约内无法直接获取系统时间信息,因为区块链不同节点的时间无法保证一致。用户可以通过GetBlockTimeStamp,或者合约调用传参的方式,在合约内获取一个有一致性保证的时间信息。

MYCDT 提供了标准的 C/C++ 时间格式化接口,可以把此类时间信息按照用户需求格式化成一个字符串。

接口定义

  • localtime

    struct tm *localtime (const time_t * t);
    struct tm *localtime64 (const time64_t * t);

    把以秒为单位的时间t分解后转换存入struct tm格式。该接口默认时区是CST北京时区。

    返回值

    参数

    分解后的时间信息结构体tm,后续时间格式化函数strftime需要。返回的tm中会被隐含初始化为CST北京时区。

    分解后的时间信息结构体tm,后续时间格式化函数strftime需要。返回的tm中会被隐含初始化为CST北京时区。

  • strftime

    size_t strftime (char *__restrict, size_t, const char *__restrict, const struct tm *__restrict);

    根据指定的格式符,格式化tm格式的时间,并把结果放入指定的buffer。

    返回值

    参数

    恒为0

    参数1:存放格式后结果字符串的buffer指针

    参数2:buffer长度

    参数3:格式化格式符组合

    参数4:struct tm格式的时间信息

  • gmtime

    struct tm *gmtime (const time_t *);
    struct tm *gmtime64 (const time64_t *);

    把以秒为单位的时间t分解后转换存入struct tm格式。该接口默认时区是GMT。

    返回值

    参数

    分解后的时间信息结构体tm,后续时间格式化函数strftime需要。返回的tm中会被隐含初始化为GMT时区。

    以秒为单位的时间,如果原始时间戳是以毫秒为单位,需要除以1000,转换成秒后再传入。

重要

默认的time_t类型内部使用 32 位整数来表示时间,因此无法表示 2038 年以后的时间。使用time64_t类型和配套的接口可以避免这个问题。

示例一

#include <mychainlib/contract.h>
#include <locale_impl.h>
#include <time.h>
#include <locale.h>

using namespace mychain;

class hello:public Contract {
public:
    INTERFACE void hi(uint64_t x ) {

      //长度26,此处是示例值。请设置为实际格式化后字符串的长度。
      //此处指定长度可以大于实际长度
      //如果小于实际长度,则会发生截断
      char buffer[26];

      struct tm *pt;

      //此处假定1585018706922是调用 GetBlockTimeStamp() 获得的毫秒时间戳
      //其长度是64位整型
      //因此需要先除以1000转换为秒
      time_t mytime = (time_t)(1585018706922 / 1000);

      //CST: 20200324105826
      pt = localtime(&mytime);
      strftime(buffer, 26, "%Y%m%d%H%M%S", pt);
      println("CST: %s\n", buffer);

      //Full: Tue Mar 24 10:58:26 2020
      strftime(buffer, 26, "%c", pt);
      println("Full: %s\n", buffer);

      //GMT: 20200324025826
      pt = gmtime(&mytime);
      strftime(buffer, 26, "%Y%m%d%H%M%S", pt);
      println("GMT: %s\n", buffer);
    }
};
INTERFACE_EXPORT(hello, (hi))

示例二

以下给出使用std::put_time接口来格式化时间戳的例子。

重要

由于该接口引入了stringstream,可能会导致合约体积显著增大。优点是不用显式的管理格式化后的字符串buffer了。

#include <mychainlib/contract.h>
#include<iomanip>
#include<ctime>
#include<sstream>
#include<string>

using namespace mychain;

class hello:public Contract {
public:
    INTERFACE void hi(uint64_t x ) {

            //此处假定1585018706922是调用 GetBlockTimeStamp() 获得的毫秒时间戳
            //其长度是64位整型
            //因此需要先除以1000转换为秒
            std::time_t mytime = (std::time_t)(1585018706922 / 1000);

            //也可以调用gmtime接口格式化为0时区时间
            std::tm tm = *std::localtime(&mytime);

            std::stringstream ssTp;
            ssTp << std::put_time(&tm, "%Y%m%d%H%M%S");

            //ssTp.str() 返回一个string对象
            println("PUT_TIME: %s\n", ssTp.str().c_str());
    }
};
INTERFACE_EXPORT(hello, (hi))

示例三

下面使用time64_t类型来表示 2038 年以后的时间。

#include <mychainlib/contract.h>
#include <ctime>
#include <iomanip>
#include <sstream>

class Hello {
public:
    INTERFACE void hi() {
        time64_t t = 2234491342; // 某个 2040 年的时间

        std::ostringstream oss;
        oss << std::put_time(localtime64(&t), "%c");
        mychain::println("%s", oss.str().c_str());
        // 输出:Mon Oct 22 12:02:22 2040

        oss.str("");
        oss << std::put_time(gmtime64(&t), "%c");
        mychain::println("%s", oss.str().c_str());
        // 输出:Mon Oct 22 04:02:22 2040
    }
};
INTERFACE_EXPORT(Hello, (hi))

第三方库

  • XML 库版本 v1.1.0,需要包含头文件。

    #include <third_party/rapidxml/rapidxml.hpp>
    #include <third_party/rapidxml/rapidxml_print.hpp>

    使用示例:

      #include <mychainlib/contract.h>
      #include <third_party/rapidxml/rapidxml.hpp>
      #include <third_party/rapidxml/rapidxml_print.hpp>
    
      using namespace mychain;  // NOLINT
      class TestXMLParse : public Contract {
      public:
          INTERFACE XMLParse() {
              std::string for_parse = R"(<?xml version="1.0" encoding="UTF-8"?>
      <EllipsoidParams>
        <Datum Name="BeiJing54" SemiMajorAxis="6378245.0" Flattening="298.3"/>
        <Datum Name="XiAn80" SemiMajorAxis="6378140.0" Flattening="298.257"/>
        <Datum Name="CGCS2000" SemiMajorAxis="6378137.0" Flattening="298.257222101"/>
      </EllipsoidParams>)";
    
              // need memory more than 64*1024, so the stack can't hold it, use "static" to
              // make it allocate in global
              static rapidxml::xml_document<> doc;
              doc.parse<0>(for_parse.data());
    
              const rapidxml::xml_node<>* ellipsoid = doc.first_node("EllipsoidParams");
              if (NULL != ellipsoid) {
                  for (rapidxml::xml_node<>* datum = ellipsoid->first_node("Datum");
                       NULL != datum; datum = datum->next_sibling()) {
                      std::string szTmp;
                      for (rapidxml::xml_attribute<char>* attr =
                               datum->first_attribute("Name");
                           attr != NULL; attr = attr->next_attribute()) {
                          szTmp.append(attr->name());
                          szTmp.append(": ");
                          szTmp.append(attr->value());
                          szTmp.append(", ");
                      }
                      print("%s\n", szTmp.c_str());
                  }
              }
          }
      };
    
      INTERFACE_EXPORT(TestXMLParse, (XMLParse))
  • JSON 库版本 v1.1.0

    智能合约平台目前支持 rapidjson 和 jsoncpp 两种JSON 解析库,您可以根据自己的需要选择使用。下面展示两种 JSON 解析库的简单用法,您也可以到官方网站查询更详细的使用方法。

    rapidjson 使用示例

      #include <mychainlib/contract.h>
      #include <third_party/rapidjson/document.h>
      #include <third_party/rapidjson/stringbuffer.h>
      #include <third_party/rapidjson/writer.h>
    
      using namespace mychain;  // NOLINT
    
      class TestJsonParse : public Contract {
      public:
          INTERFACE JsonParse() {
              using namespace ::rapidjson;
              std::string stringFromStream = R"({
          "dictVersion": 1,  
          "content":  
          [   
              {"key": "word1", "value": "单词1"} ,
              {"key": "word2", "value": "单词2"} ,
              {"key": "word3", "value": "单词3"} ,
              {"key": "word4", "value": "单词4"} ,
              {"key": "word5", "value": "单词5"} 
          ]
          })";
    
              // ---------------------------- read json --------------------
              // parse json from string.
              using rapidjson::Document;
              Document doc;
              doc.Parse<0>(stringFromStream.c_str());
              if (doc.HasParseError()) {
                  rapidjson::ParseErrorCode code = doc.GetParseError();
                  MyAssert(code == kParseErrorNone, "parse from string");
              }
    
              // use values in parse result.
              using rapidjson::Value;
              Value& v = doc["dictVersion"];
              if (v.IsInt()) {
                  print("%d\n", v.GetInt());
              }
    
              Value& contents = doc["content"];
              if (contents.IsArray()) {
                  for (size_t i = 0; i < contents.Size(); ++i) {
                      Value& v = contents[i];
                      assert(v.IsObject());
                      if (v.HasMember("key") && v["key"].IsString()) {
                          print("%s\n", v["key"].GetString());
                      }
                      if (v.HasMember("value") && v["value"].IsString()) {
                          print("%s\n", v["value"].GetString());
                      }
                  }
              }
              // ---------------------------- write json --------------------
              print("add a value into array\n");
    
              Value item(Type::kObjectType);
              item.AddMember("key", "word5", doc.GetAllocator());
              item.AddMember("value", "单词5", doc.GetAllocator());
              contents.PushBack(item, doc.GetAllocator());
    
              // convert dom to string.
              StringBuffer buffer;                  // in rapidjson/stringbuffer.h
              Writer<StringBuffer> writer(buffer);  // in rapidjson/writer.h
              doc.Accept(writer);
    
              print("%s\n", buffer.GetString());
          }
      };
    
      INTERFACE_EXPORT(TestJsonParse, (JsonParse))

    jsoncpp 使用示例

      #include <mychainlib/contract.h>
      #include <third_party/jsoncpp/json.h>
    
      using namespace mychain;
    
      class TestJsoncpp : public Contract {
      public:
          INTERFACE void parse()
          {
              std::string strValue =
              "{                      \
                \"key\": \"value1\",  \
                \"array\": [          \
                   {\"arraykey\": 1}, \
                   {\"arraykey\": 2}  \
                 ]                    \
               }";
              Json::Reader reader;
              Json::Value root;
              if (reader.parse(strValue, root))
              {
                  if (!root["key"].isNull())
                  {
                      std::string strValue= root["key"].asString();
                      println("%s\n", strValue.c_str());
                  }
    
                  Json::Value arrayObj = root["array"];
                  for (int i=0; i<arrayObj.size(); i++)
                  {
                      int iarrayValue = arrayObj[i]["arraykey"].asInt();
                      println("%d\n", iarrayValue);
                  }
              }
          }
      };
    
      INTERFACE_EXPORT(TestJsoncpp, (parse))
  • 定点数库,需要包含头文件

      #include <third_party/bcmath/bcmath_stl.h>

    使用示例

      #include <mychainlib/contract.h>
      #include <third_party/bcmath/bcmath_stl.h>
      using namespace mychain;
      using namespace bcmath;
    
      void test_bcmath();
    
      class BCMathTest: public Contract {
      public:
          INTERFACE void run() {
              test_bcmath();
          }
      };
    
      INTERFACE_EXPORT(BCMathTest, (run))
    
      void test_bcmath()
      {
          BCMath::bcscale(4); //Num Decimals
          BCMath test("-5978");
          std::string gold;
    
          auto require = [](bool cond, const char* msg) {
              Require(cond, "Test failed: "s + msg);
          };
    
          test^=30; //Pow, only integers. Not work decimals.
          gold = "198005530669253749533290222782634796336450786581284861381777714804795900171726938603997395193921984842256586113024";
          require(test.toString() == gold, "BigDecimal 1");
    
          test-=1.23; //sub
          gold = "198005530669253749533290222782634796336450786581284861381777714804795900171726938603997395193921984842256586113022.7700";
          require(test.toString() == gold, "BigDecimal 2");
    
          test*=1.23; //mul
          gold = "243546802723182111925946974022640799493834467494980379499586589209898957211224134482916796088524041355975600919018.0071";
          require(test.toString() == gold, "BigDecimal 3");
    
          test*=-1.23; //mul
          gold = "-299562567349513997668914778047848183377416395018825866784491504728175717369805685413987659188884570867849989130392.1487";
          require(test.toString() == gold, "BigDecimal 4");
    
          BCMath::bcscale(70); //Num Decimals
    
          BCMath randNum("-5943534512345234545.8998928392839247844353457");
          BCMath pi("3.1415926535897932384626433832795028841971693993751058209749445923078164062862");
    
          BCMath result1 = randNum + pi;
          BCMath result2 = randNum - pi;
          BCMath result3 = randNum * pi;
          BCMath result4 = randNum / pi;
    
          gold = "-5943534512345234542.7583001856941315459727023167204971158028306006248941790250554076921835";
          require(result1.toString() == gold, "Super Precision 1");
          gold = "-5943534512345234549.0414854928737180228979890832795028841971693993751058209749445923078164";
          require(result2.toString() == gold, "Super Precision 2");
          gold = "-18672164360341183116.9114783895073349180904753962992796943871920962352436079118338887287186";
          require(result3.toString() == gold, "Super Precision 3");
          gold = "-1891885794154043400.2804849527556211973567525043250278948318788149660700494315139982452600";
          require(result4.toString() == gold, "Super Precision 4");
    
          //Other example
          BCMath::bcscale(4); //Num Decimals
          gold = "8023400.1075";
          require(BCMath::bcmul("1000000.0134", "8.0234") == gold, "Other 1");
          gold = "1000008.0368";
          require(BCMath::bcadd("1000000.0134", "8.0234") == gold, "Other 2");
    
          require(BCMath::bccomp("1", "2") == -1, "Compare 1");
          require(BCMath::bccomp("1.00001", "1", 3) == 0, "Compare 2");
          require(BCMath::bccomp("1.00001", "1", 5) == 1, "Compare 3");
          require(BCMath("1")< BCMath("2"), "Compare 4");
          require(BCMath("1")<=BCMath("2"), "Compare 5");
          require(!(BCMath("1")> BCMath("2")), "Compare 6");
          require(!(BCMath("1")>=BCMath("2")), "Compare 7");
          require(!(BCMath("2")< BCMath("2")), "Compare 8");
          require(BCMath("2")<=BCMath("2"), "Compare 9");
          require(!(BCMath("2")> BCMath("2")), "Compare 10");
          require(BCMath("2")>=BCMath("2"), "Compare 11");
    
          gold = "123.0125";
          require(BCMath::bcround("123.01254") == gold, "Round 1");
          gold = "-123.013";
          require(BCMath::bcround("-123.01254", 3) == gold, "Round 2");
          gold = "123.01";
          require(BCMath::bcround("123.01254", 2) == gold, "Round 3");
          pi.round(3);
          gold = "3.142";
          require(pi.toString() == gold, "Round 4");
    
          BCMath part1("-.123");
          BCMath part2(".123");
          BCMath part3("123");
          require(part1.getIntPart() == "-0", "Int part 1");
          require(part1.getDecPart() == "123", "Dec part 1");
          require(part2.getIntPart() == "0", "Int part 2");
          require(part2.getDecPart() == "123", "Dec part 2");
          require(part3.getIntPart() == "123", "Int part 3");
          require(part3.getDecPart() == "0", "Dec part 3");
      }