eos源码地址 https://github.com/EOSIO/eos
欧链源码地址 https://github.com/OracleChain/EOSDevHelper
节点ip
192.168.199.110
1.创建账户
二.实现交易转账
1.构建交易信息
交易信息 包括 1.自己账户名 2对方帐户名 3.交易金额 4.交易备注 (备注 账户名规则 (. 1-5 a-z ) 长度12)
示例json
{
"from":"eosio.token", //账户按规则
"to":"eosio",
"quantity":"20.0000 EOS", 金额和EOS之间必须存在一个空格
"memo":"dd"
}
2.交易信息编码 交易信息json传data
1.编码from的value NameToLong 然后转16进制 然后两个字节反转 示例<eosio.token> 值"00a6823403ea3055
2.编码to 的value NameToLong 然后转16进制 然后两个字节反转 示例<eosio> 值"0000000000ea3055
3编码quantity 转16进制 然后编码小数点后几位的长度 转16 进制 先编码EOS转16进制 在加八个0
4.memo 编码备注长度 长度转16进制 (如dd 他的长度为2 2转为16进制再加上) 备注值转16进制
3.getinfo方法 (后台返回交易信息)
示例json
{
"block_cpu_limit": 99900,
"block_net_limit": 1048576,
"head_block_id": "00007b2b ee b3 e1 fb 5b5d8574 f7719149b550a73ed06939b7a8ba741bc82ad367",
"head_block_num": 31531,
"head_block_producer": "eosio",
"head_block_time": "2018-05-29T07:49:50",
"last_irreversible_block_id": "00007b2a2965202c71b62290a51826eb896b4a54986bbf2b9a8ac87e8da7a7cb",
"last_irreversible_block_num": 31530,
"server_version": "2877bd76",
"virtual_block_cpu_limit": 100000000,
"virtual_block_net_limit": 1048576000
}
4.构建未签名交易
包括 1.公钥集合 2.
示例json
{
"available_keys": [
"EOS8hdhrncnn1fKk21iHb7g9F8Q7MGa3VdfDiYEffqVeNVgo9iJ5K" //公钥
],
"transaction": {
"actions": [
{
"account": "eosio.token", //账户
"authorization": [
{
"actor": "eosio.token", //from 签名的账户
"permission": "active" //权限 owner主账户 active 活动 //(active 子账户的意思,可以限制权限比如只能转账, owner 所有权限)
}
],
"data": "00a6823403ea3055(from) 0000000000ea3055 (to) 400d030000000000 (金额编码 自己写把 ) 04(金额小数点后几位长度转16进制) 454f53(EOS) 00000000(默认存在) 026464(备注)", //交易信息的编码第二部
"name": "transfer" //合约方法名
}
],
"context_free_actions": [
], "context_free_actions": || "context_free_data": 目前是空集合
"context_free_data": [
],
//getinfo方法 (以下是后台返回交易信息)
"delay_sec": 0, // 目前是0 大概意思是延迟
"expiration": "2018-05-29T15:50:20", // 过期时间
"max_kcpu_usage": 0, // 目前是0 大概意思KCPU使用
"max_net_usage_words": 0, // 目前是0 大概意思是网络使用词
"ref_block_num": 31531, // 由getinfo方法返回的head_block_id 16进制的 然后字段截取前八位 转10进制 //TransactionHeader.cpp::setReferenceBlock(
"ref_block_prefix": 1954897243, // 由getinfo方法返回的head_block_id 16进制的 然后字段截取16到24 然后两个字节反转(5b5d8574 反转为74855d5b) 转10进制
"signatures": [
]
}
}
4.对未签名交易序列化 //SignedTransaction::getDigestForSignature 签名前打包数据
(次序不能乱)
1.先空置32字节
2.对expiration编码 时间格式转得到long 由于时间java得到的gettime是精确到毫秒 而eos只精确到秒 所以需要除以1000 然后long值加30 //TransactionHeader::serializ
3.ref_block_num 转16进制 然后两个字节反转
4.ref_block_prefix 转16进制 然后两个字节反转
5.编码 "max_net_usage_words": "max_kcpu_usage": "delay_sec": (次序不能乱) putVariableUInt
6.context_free_actions 编码List 的长度 然后编码list子条目 EOSByteWriter 头文件 SerializeCollection 走的方法 putVariableUInt
首先编码actions 的长度 putVariableUInt()
7.account的value 编码 调用nametolong方法 putLongLE
8.name的value 编码 调用nametolong方法 putLongLE
编码authorization长度 putVariableUInt()
9 编码actor的value 调用nametolong方法 putLongLE
10.编码permission的value 调用nametolong方法 putLongLE
11.data已经是编码后的数据 获取string 转成byte[] 编码byte[]长度 putVariableUInt 然后把byte[] 存到流里
12.transaction_extensions 由于目前为空集合 长度为0 (C) SerializeCollection (java) SerializeCollectionextension
13 序列化待签名的信息 拿到date 先构建255长度 前32字节空置 把date放进去 如果不足255 补0
/**
* 序列化待签名的信息
*/
public byte[] getDigestForSignature() {
ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(255);
try {
EOSUtils.putBytes(stream, bytes);
serialize(stream);
return stream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return stream.toByteArray();
}
5.签名
SignedTransaction::sign
1. 无论数据data多长首先sha256得到固定长度32字节数据
2. ECC加密得到64字节数据
判断是否签名过
3. 在得出的数据头增加一字节指定数据包长度
4. 将以上得出的65字节数据hash压缩得出字节的压缩数据并追加在后面得到69字节数据
5. 将以上数据base58编码并在消息头上添加SIG_K1_
void SignedTransaction::sign(const std::vector<unsigned char> &pri_key, const TypeChainId &cid)
{
std::vector<unsigned char> packedBytes = getDigestForSignature(cid);
uint8_t packedSha256[SHA256_DIGEST_LENGTH];
sha256_Raw(packedBytes.data(), packedBytes.size(), packedSha256);
uint8_t signature[uECC_BYTES * 2] = { 0 };
int recId = uECC_sign_forbc(pri_key.data(), packedSha256, signature);
if (recId == -1) {
// could not find recid, data probably already signed by the key before?
return;
} else {
unsigned char bin[65+4] = { 0 };
unsigned char *rmdhash = NULL;
int binlen = 65+4;
int headerBytes = recId + 27 + 4;
bin[0] = (unsigned char)headerBytes;
memcpy(bin + 1, signature, uECC_BYTES * 2);
unsigned char temp[67] = { 0 };
memcpy(temp, bin, 65);
memcpy(temp + 65, "K1", 2);
rmdhash = RMD(temp, 67);
memcpy(bin + 1 + uECC_BYTES * 2, rmdhash, 4);
char sigbin[100] = { 0 };
size_t sigbinlen = 100;
b58enc(sigbin, &sigbinlen, bin, binlen);
std::string sig = "SIG_K1_";
sig += sigbin;
signatures.push_back(sig);
}
}
6.服务器广播交易
广播交易的信息
{
"compression": "none", 默认设置为none
"packed_context_free_data": "00", action里面的free_data 转16进制
"packed_trx": " (序列化的数据 不用补0 不用前空32位 也是13步之前的 )6e360d5b06599dfc701d000000000100a6823403ea3055000000572d3ccdcd0100a6823403ea305500000000a8ed32322100a6823403ea30550000000000ea3055b94885010000000005454f53000000000000",
"signatures": [
"SIG_K1_K69ggSmfTkLDf327ct5K511rn86kB3YieoQTQtCV9ZxndJY69gaQPxHFLDMtxecSf5wdic7thUxggpEYibgu5fTjuPewdr" //签名的值
]
}
post请求 提交json
注意 金额前缀编码没有搞定
两个字节反转
public static String strreverse(String str) {
char[] chars = str.toCharArray();
String qq = "";
for (int i = chars.length - 2; i >= 0; i = i - 2) {
qq = qq + chars[i] + chars[i + 1];
}
return qq;
}
欧链源码地址 https://github.com/OracleChain/EOSDevHelper
节点ip
192.168.199.110
1.创建账户
二.实现交易转账
1.构建交易信息
交易信息 包括 1.自己账户名 2对方帐户名 3.交易金额 4.交易备注 (备注 账户名规则 (. 1-5 a-z ) 长度12)
示例json
{
"from":"eosio.token", //账户按规则
"to":"eosio",
"quantity":"20.0000 EOS", 金额和EOS之间必须存在一个空格
"memo":"dd"
}
2.交易信息编码 交易信息json传data
1.编码from的value NameToLong 然后转16进制 然后两个字节反转 示例<eosio.token> 值"00a6823403ea3055
2.编码to 的value NameToLong 然后转16进制 然后两个字节反转 示例<eosio> 值"0000000000ea3055
3编码quantity 转16进制 然后编码小数点后几位的长度 转16 进制 先编码EOS转16进制 在加八个0
4.memo 编码备注长度 长度转16进制 (如dd 他的长度为2 2转为16进制再加上) 备注值转16进制
3.getinfo方法 (后台返回交易信息)
示例json
{
"block_cpu_limit": 99900,
"block_net_limit": 1048576,
"head_block_id": "00007b2b ee b3 e1 fb 5b5d8574 f7719149b550a73ed06939b7a8ba741bc82ad367",
"head_block_num": 31531,
"head_block_producer": "eosio",
"head_block_time": "2018-05-29T07:49:50",
"last_irreversible_block_id": "00007b2a2965202c71b62290a51826eb896b4a54986bbf2b9a8ac87e8da7a7cb",
"last_irreversible_block_num": 31530,
"server_version": "2877bd76",
"virtual_block_cpu_limit": 100000000,
"virtual_block_net_limit": 1048576000
}
4.构建未签名交易
包括 1.公钥集合 2.
示例json
{
"available_keys": [
"EOS8hdhrncnn1fKk21iHb7g9F8Q7MGa3VdfDiYEffqVeNVgo9iJ5K" //公钥
],
"transaction": {
"actions": [
{
"account": "eosio.token", //账户
"authorization": [
{
"actor": "eosio.token", //from 签名的账户
"permission": "active" //权限 owner主账户 active 活动 //(active 子账户的意思,可以限制权限比如只能转账, owner 所有权限)
}
],
"data": "00a6823403ea3055(from) 0000000000ea3055 (to) 400d030000000000 (金额编码 自己写把 ) 04(金额小数点后几位长度转16进制) 454f53(EOS) 00000000(默认存在) 026464(备注)", //交易信息的编码第二部
"name": "transfer" //合约方法名
}
],
"context_free_actions": [
], "context_free_actions": || "context_free_data": 目前是空集合
"context_free_data": [
],
//getinfo方法 (以下是后台返回交易信息)
"delay_sec": 0, // 目前是0 大概意思是延迟
"expiration": "2018-05-29T15:50:20", // 过期时间
"max_kcpu_usage": 0, // 目前是0 大概意思KCPU使用
"max_net_usage_words": 0, // 目前是0 大概意思是网络使用词
"ref_block_num": 31531, // 由getinfo方法返回的head_block_id 16进制的 然后字段截取前八位 转10进制 //TransactionHeader.cpp::setReferenceBlock(
"ref_block_prefix": 1954897243, // 由getinfo方法返回的head_block_id 16进制的 然后字段截取16到24 然后两个字节反转(5b5d8574 反转为74855d5b) 转10进制
"signatures": [
]
}
}
4.对未签名交易序列化 //SignedTransaction::getDigestForSignature 签名前打包数据
(次序不能乱)
1.先空置32字节
2.对expiration编码 时间格式转得到long 由于时间java得到的gettime是精确到毫秒 而eos只精确到秒 所以需要除以1000 然后long值加30 //TransactionHeader::serializ
3.ref_block_num 转16进制 然后两个字节反转
4.ref_block_prefix 转16进制 然后两个字节反转
5.编码 "max_net_usage_words": "max_kcpu_usage": "delay_sec": (次序不能乱) putVariableUInt
6.context_free_actions 编码List 的长度 然后编码list子条目 EOSByteWriter 头文件 SerializeCollection 走的方法 putVariableUInt
首先编码actions 的长度 putVariableUInt()
7.account的value 编码 调用nametolong方法 putLongLE
8.name的value 编码 调用nametolong方法 putLongLE
编码authorization长度 putVariableUInt()
9 编码actor的value 调用nametolong方法 putLongLE
10.编码permission的value 调用nametolong方法 putLongLE
11.data已经是编码后的数据 获取string 转成byte[] 编码byte[]长度 putVariableUInt 然后把byte[] 存到流里
12.transaction_extensions 由于目前为空集合 长度为0 (C) SerializeCollection (java) SerializeCollectionextension
13 序列化待签名的信息 拿到date 先构建255长度 前32字节空置 把date放进去 如果不足255 补0
/**
* 序列化待签名的信息
*/
public byte[] getDigestForSignature() {
ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(255);
try {
EOSUtils.putBytes(stream, bytes);
serialize(stream);
return stream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return stream.toByteArray();
}
5.签名
SignedTransaction::sign
1. 无论数据data多长首先sha256得到固定长度32字节数据
2. ECC加密得到64字节数据
判断是否签名过
3. 在得出的数据头增加一字节指定数据包长度
4. 将以上得出的65字节数据hash压缩得出字节的压缩数据并追加在后面得到69字节数据
5. 将以上数据base58编码并在消息头上添加SIG_K1_
void SignedTransaction::sign(const std::vector<unsigned char> &pri_key, const TypeChainId &cid)
{
std::vector<unsigned char> packedBytes = getDigestForSignature(cid);
uint8_t packedSha256[SHA256_DIGEST_LENGTH];
sha256_Raw(packedBytes.data(), packedBytes.size(), packedSha256);
uint8_t signature[uECC_BYTES * 2] = { 0 };
int recId = uECC_sign_forbc(pri_key.data(), packedSha256, signature);
if (recId == -1) {
// could not find recid, data probably already signed by the key before?
return;
} else {
unsigned char bin[65+4] = { 0 };
unsigned char *rmdhash = NULL;
int binlen = 65+4;
int headerBytes = recId + 27 + 4;
bin[0] = (unsigned char)headerBytes;
memcpy(bin + 1, signature, uECC_BYTES * 2);
unsigned char temp[67] = { 0 };
memcpy(temp, bin, 65);
memcpy(temp + 65, "K1", 2);
rmdhash = RMD(temp, 67);
memcpy(bin + 1 + uECC_BYTES * 2, rmdhash, 4);
char sigbin[100] = { 0 };
size_t sigbinlen = 100;
b58enc(sigbin, &sigbinlen, bin, binlen);
std::string sig = "SIG_K1_";
sig += sigbin;
signatures.push_back(sig);
}
}
6.服务器广播交易
广播交易的信息
{
"compression": "none", 默认设置为none
"packed_context_free_data": "00", action里面的free_data 转16进制
"packed_trx": " (序列化的数据 不用补0 不用前空32位 也是13步之前的 )6e360d5b06599dfc701d000000000100a6823403ea3055000000572d3ccdcd0100a6823403ea305500000000a8ed32322100a6823403ea30550000000000ea3055b94885010000000005454f53000000000000",
"signatures": [
"SIG_K1_K69ggSmfTkLDf327ct5K511rn86kB3YieoQTQtCV9ZxndJY69gaQPxHFLDMtxecSf5wdic7thUxggpEYibgu5fTjuPewdr" //签名的值
]
}
post请求 提交json
注意 金额前缀编码没有搞定
两个字节反转
public static String strreverse(String str) {
char[] chars = str.toCharArray();
String qq = "";
for (int i = chars.length - 2; i >= 0; i = i - 2) {
qq = qq + chars[i] + chars[i + 1];
}
return qq;
}