您正在查看: EOS-新手教程 分类下的文章

get_table对于time_point类型得定位查询

根据场景需求需要对已存储得数据做更新查询,所以需要对update_timepoint做查询索引

struct [[eosio::table, eosio::contract("bcskill.com")]] xxxx_info {
        uint64_t id;                                        // 记录id
        eosio::checksum256 trx_id;                          // 交易id
        ....
        time_point create_timepoint;                        // 创建时间
        time_point update_timepoint;                        // 更新时间

        uint64_t primary_key() const { return id; }
        eosio::checksum256 second_key() const { return trx_id; }
        uint64_t third_key() const { return update_timepoint.time_since_epoch().count();} // 把time_point类型转换成微妙(1/1000000 秒)
    };

table中测试数据如下

{
  "rows": [{
      "id": 0,
      "trx_id": "d78c4da408a4d9c75ba03af4a481d79fa80e2b8e215e68a1fe1865fd866cc7bc",
      ...
      "create_timepoint": "2020-12-17T11:24:07.500",
      "update_timepoint": "2020-12-17T11:27:18.500"
    },{
      "id": 1,
      "trx_id": "7bb0038be49b171f8a394bfdd7da15f9a005908b25ca1b6aed31b2975d721730",
      ...
      "create_timepoint": "2020-12-17T11:29:01.500",
      "update_timepoint": "2020-12-17T11:30:01.500"
    },{
      "id": 2,
      "trx_id": "8cf1c32d38692dd93870c7a2376d617f85efa4f093588dbce94f9981d4e1818e",
      ...
      "create_timepoint": "2020-12-17T11:30:01.500",
      "update_timepoint": "2020-12-17T11:30:01.500"
    }
  ],
  "more": false
}

UTC时间转时间戳,目前没有找到现成的工具可以直接转换,
https://tool.lu/timestamp/ 只找到这个北京时间转时间戳的工具(稍后找到其他直接工具,或者单独开发个工具再做文章更新)

UTC 转北京时间(+8)

暂时先将UTC时间加8小时转换成本地时间,测试的UTC时间为2020-12-17T11:27:18.500,转换为本地时间为2020-12-17 19:27:18 其中的.500为0.5秒,后面再单独加上。

北京时间转时间戳

利用上面的在线工具2020-12-17 19:27:18得到1608204438,加上上面的0.500得到1608204438.5

根据合约类型需要转换为微妙

1608204438.5 * 1000000 得到 1608204438500000

根据测试数据演示下查询

cleos get table bcskillsurou bcskillsurou ammtb --index 3 --key-type i64 -L 1608204438500000 -U 1608204438500000

得到指定的记录

{
  "rows": [{
      "id": 0,
      "trx_id": "d78c4da408a4d9c75ba03af4a481d79fa80e2b8e215e68a1fe1865fd866cc7bc",
      ...
      "create_timepoint": "2020-12-17T11:24:07.500",
      "update_timepoint": "2020-12-17T11:27:18.500"
    }
  ],
  "more": false
}

EOSIO v2.1.0 动作返回值

昨晚期待已久的2.1.0 rc 版本终于发版了,
https://github.com/EOSIO/eos/releases/tag/v2.1.0-rc1
新的协议功能:ACTION_RETURN_VALUE。
https://github.com/EOSIO/eos/pull/8327
激活后,此功能提供了一种方法,该方法可以将返回的值在操作中的块头中严格落实到外部进程中,而不必依赖get_table或通过print语句使用调试控制台。这使智能合约开发人员能够直接处理操作的返回值。进一步简化智能合约开发流程。一个例子可以在这里看到。

演示例子

合约代码

[[eosio::action]]
int sum(int valueA, int valueB) {
    return valueA + valueB; // 合约返回结果
}

前端推送完交易后,直接获取返回值

 const transactionResult = await api.transact({
        actions: [{
          account: 'returnvalue',
          name: 'sum',
          authorization: [{
            actor: 'returnvalue',
            permission: 'active',
          }],
          data: {
            valueA: numbers.first,
            valueB: numbers.second
          }
        }]
      }, {
        blocksBehind: 3,
        expireSeconds: 30
      }) as any
      setResult(transactionResult.processed.action_traces[0].return_value_data) // 直接获取返回值

符合标准的EOS助记词生成私钥

最近要对接HD钱包,测试得到EOS的
eosjs-ecc 不符合标准的BIP44

m/44'/194'/0'/0/0

修正方法为

const hdkey = require('hdkey')
const wif = require('wif')
const ecc = require('eosjs-ecc')
const bip39 = require('bip39')
const mnemonic = 'real flame win provide layer trigger soda erode upset rate beef wrist fame design merit'
const seed = bip39.mnemonicToSeedSync(mnemonic)
const master = hdkey.fromMasterSeed(Buffer(seed, 'hex'))
const node = master.derive("m/44'/194'/0'/0/0")
console.log("publicKey: "+ecc.PublicKey(node._publicKey).toString())
console.log("privateKey: "+wif.encode(128, node._privateKey, false))

根据测试例子,修改eosjs-ecc支持扩展方法

package.json 增加新依赖

npm i bip39
npm i hdkey
npm i wif

修改api_common.js 增加bip44参数

默认false兼容之前版本

seedPrivate: (seed, bip44 = false) => PrivateKey.fromSeed(seed, bip44).toString(),

修改 key_private.js

增加新依赖

const hdkey = require('hdkey')
const WIFReturn = require('wif')
const bip39 = require('bip39')

修改fromSeed支持新实现

PrivateKey.fromSeed = function(seed, bip44) { // generate_private_key
    if (!(typeof seed === 'string')) {
        throw new Error('seed must be of type string');
    }
    if(bip44) {
      const seedString = bip39.mnemonicToSeedSync(seed)
      const master = hdkey.fromMasterSeed(Buffer(seedString, 'hex'))
      const node = master.derive("m/44'/194'/0'/0/0")
      return WIFReturn.encode(128, node._privateKey, false)
    }
    return PrivateKey.fromBuffer(hash.sha256(seed));
}

测试

测试助记词

real flame win provide layer trigger soda erode upset rate beef wrist fame design merit

原版eosjs-ecc

<script src="./dist-web/eosjs-ecc.js"></script>
    <script>
   (async () => {
    let wif = eosjs_ecc.seedPrivate('real flame win provide layer trigger soda erode upset rate beef wrist fame design merit');
    console.log(wif + '\n');
    let pubKey = eosjs_ecc.privateToPublic(wif);
    console.log(pubKey + '\n');
   })();
  </script>

生成结果为

5JX94izH6NMZkGqq9VvrmSTWux28HKRyns5mBwujzB9p48XSgNQ
EOS6j4E5ksFkDBAP32XXYseTaUkGqBKqPzYjcwUVeBV4JY8UbS1N5

使用修改后得标准BIP44

<script src="./dist-web/eosjs-ecc.js"></script>
    <script>
   (async () => {
    let wif = eosjs_ecc.seedPrivate('real flame win provide layer trigger soda erode upset rate beef wrist fame design merit',true);
    console.log(wif + '\n');
    let pubKey = eosjs_ecc.privateToPublic(wif);
    console.log(pubKey + '\n');
   })();
  </script>

结果为

5KX4T16FtxG9LvRJukA31TP9BKq3jYve3xQ3Px3ui8mzuJ7nUYE
EOS61oRAVkx1rqPM8mEsBZxPAFAa9Nm6kLa7mQs6mRKTsRTFQaad7

参考

https://github.com/satoshilabs/slips/blob/master/slip-0044.md
https://iancoleman.io/bip39/

备注

eosjs编译时需要先

npm run build

不能直接

npm run build_browser

如果测试自定义得bip44中得 coin type,可以在https://iancoleman.io/bip39/ 中得Derivation Path 选项中,选择BIP32,并去掉最后一层,例如,自定义coin type为9527

m/44'/9527'/0'/0

EOS 根据链Mongo数据判断交易状态

根据几个测试交易对比

  1. 正常发起普通交易(余额充足,非延迟)
  2. 正常发起延迟交易(余额充足,延迟)
  3. 正常发起延迟交易,交易到期前,将转出账户的余额转空(余额不足,延迟)

对比链Mongo表transactionstransaction_traces

对于transactions体现了交易所在块是否不可逆irreversible,而transaction_traces

 "receipt" : {
        "status" : "hard_fail",
        ...
    },

status状态来判断交易状态。
对于交易对比的1和2对于数据来说只是delay_sec数量问题,并且交易到期前,数据库中无法查到延迟交易。
1或2与3进行比较,transactions无关键差别,transaction_tracesstatus状态存在差别。

清洗数据

为了方便数据的使用,最好还是需要单独新洗出一个交易状态表,此表中关键包含,

  1. 交易id
  2. 所在块号
  3. 交易状态
  4. 是否不可逆

测试数据如下

库名:trx_status

{
    "_id" : ObjectId("5fbb8ef5349bfe65ef744506"),
    "trx_id" : "c1811e16a77288e3f374faf2eb2b0308d2f480b3414a07357d6e45cf29ffe56e",
    "block_num" : 11414152,
    "status" : 0,
    "irreversible" : true,
    "block_time" : ISODate("2020-11-23T10:29:10.000Z"),
    "block_timestamp" : NumberLong(1606127350000),
    "createdAt" : ISODate("2020-11-23T10:29:09.952Z"),
    "updatedAt" : ISODate("2020-11-23T10:31:05.985Z"),
    "block_id" : "00ae2a8818a6bd8cd33e9873419ac7258813ea9578dde95c8e0771397351b952"
}

交易等待不可逆

status==0 && irreversible == fasle

交易丢失(丢块)

status==0 && irreversible == fasle && ((current_time - block_time) >((head_block_num - last_irreversible_block_num) * 0.5 + 容差值))
// current_time - block_time 为当前时间与交易创建时间的秒数
// 容差值是为了避免误判,通常为 1-2分钟即可

交易失败

status!=0

因为交易到执行时间前,数据库中没有插入数据,所以没有delayed事件

当交易不可逆

status==0 && irreversible == true

备注

status的状态

status_enum {
    // 这个表示执行成功(所以不需要执行出错逻辑)
    executed  = 0,
    // 客观的来说,执行失败了(或者没有执行),某一个出错逻辑执行了
    soft_fail = 1,
    // 执行失败了,并且执行的出错逻辑也失败了,所以并没有状态改变
    hard_fail = 2,
    // 交易被延迟了,计划到未来的某个时间执行
    delayed   = 3,
    // 交易过期了,并且存储空间返还给用户
    expired   = 4  ///< transaction expired and storage space refuned to user
};

修改配置

config.ini配置中,去掉onblock交易,较少垃圾数据

mongodb-filter-out = eosio:onblock:

参考

https://www.bcskill.com/index.php/archives/621.html

EOS js name To Uint64 OR Uint64 to name

源代码仓库地址:
https://github.com/bcskill/eosjs-name

演示地址
Try on run-kit https://npm.runkit.com/eosjs-account-name

测试代码
// name To Uint64

const eosjsAccountName = require("eosjs-account-name")
const n = eosjsAccountName.nameToUint64('eosio');
console.log('eosio to uint64: ' + n);
console.log('uint64 to name: ' + eosjsAccountName.uint64ToName(n));

// Uint64 to name

const uint64 = '6138663577826885632';
const name = eosjsAccountName.uint64ToName(uint64);