本文汇总了 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 |
|
出参,获取到的 <公钥,权重> map,如果返回非 0,
注意:公钥不是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, 则参数
|
返回值:
参数 |
类型 |
说明 |
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 |
任意个不定类型数参数 |
调用合约传入的参数列表,取决于被调用合约方法接收几个参数。 |
返回值:
参数 |
类型 |
说明 |
返回值 |
|
返回结构体 |
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 |
|
获取到的结果 |
返回值:
参数 |
类型 |
说明 |
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 |
解析结果,支持的数据类型见 可序列化数据类型 。 |
pack
和
unpack
使用示例:
```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 |
若输入的
|
-
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 |
|
公开输入 |
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 |
|
pedersen commitment |
返回值:
参数 |
类型 |
说明 |
result |
int32_t |
-
-
-
|
-
int AddPedersenCommit(PC& PC_result, const PC& PC_left, const PC& PC_right);
PC相加,PC即std::string。
请求参数:
参数 |
类型 |
说明 |
PC_result |
std::string& |
PC相加结果 |
PC_left |
|
相加的左PC |
PC_right |
|
相加的右PC |
返回值:
参数 |
类型 |
说明 |
result |
int32_t |
-
-
|
-
int SubPedersenCommit(PC& PC_result, const PC& PC_left, const PC& PC_right);
PC相减,PC即std::string。
请求参数:
参数 |
类型 |
说明 |
PC_result |
std::string& |
PC相减结果 |
PC_left |
|
左PC |
PC_right |
|
右PC |
返回值:
参数 |
类型 |
说明 |
result |
int32_t |
-
-
|
-
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 |
|
正PC列表 |
negative |
|
负PC列表 |
返回值:
参数 |
类型 |
说明 |
result |
int32_t |
-
-
|
-
int PedersenCommitEqualityVerify(const std::vector<PC>& positive, const std::vector<PC>& negative);
PC等式验证。
请求参数:
参数 |
类型 |
说明 |
positive |
|
正PC列表 |
negative |
|
负PC列表 |
返回值:
参数 |
类型 |
说明 |
result |
int32_t |
-
-
-
|
ElGamal隐私保护API(半同态加密)
以下ElGamal隐私保护API采用半同态加密技术,并且仅在非TEE版本中支持。
-
int LiftedElgamalContractHomomorphicAdd( const std::string& first, const std::string& second, std::string& res);
计算两个密文相加。
请求参数:
参数 |
类型 |
说明 |
first |
const std::string& |
第一个密文原始字节串,长度要求为68字节,否则返回
|
second |
const std::string& |
第二个密文原始字节串,长度要求为68字节,否则返回
|
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字节,否则返回
|
second |
const std::string& |
第二个密文原始字节串,长度要求为68字节,否则返回
|
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字节,否则返回
|
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,否则返回
|
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 |
|
密文列表,每个密文要求68字节,否则报错
|
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 中
|
返回值:
参数 |
类型 |
说明 |
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");