SickWorm的博客

EOS 账户体系简介

区块链  ·  

  1. eos 所有的代币都通过智能合约控制,包括 EOS。目前所有的代币的交易方法应该都是基于 eosio.token 智能合约,所以操作方法一致。

  2. eos 使用 action 来操作所有的链上数据,包括代币交易。action 需要签名,签名可以使用 ecc-secp256k1 或 ecc-secp256r1 曲线。 eos 通过 transaction(事务)来发送 action, action 可以有多个。

  3. action 的调用方法为:智能合约账户名 + 函数接口名 + 接口参数

  4. eos 使用 action 前需要先抵押一定的 eos 来换取 RAM,Network,CPU 资源。RAM 是持久资源,以当前市场价购买,卖出时也以当前市场价卖出;Network 和 CPU 资源限额24小时会重置,但只有新发起一笔操作后才会恢复。Network 和 CPU 资源赎回需要72小时后才能到手。发送 action 需要消耗Network 和 CPU。注册账户需要小量 RAM。抵押方法也是通过发送 transaction。cpu跟带宽的占用数据,只有在新发起一笔交易之后才会更新。

  5. eos 使用前需要先注册账户,方法是提交特定的 action,将指定公钥与账户名绑定。之后所有的操作都用账户名而不是公钥。账户名限制“.12345abcdefghijklmnopqrstuvwxyz”,12个字符以内,不可重复。目前只可注册 12个字符长的账号,其他账号以后可能以拍卖形式出售。目前不可注册带"."的账号,只有系统账号可以带"."

  6. eos 账户有权限等级体系,可以分配子权限给其他密钥。密钥派生一般使用 slip48 协议(对应 BTC 的 BIP44)。目前 eos 默认是 owner 和 active 两种权限,owner 可以更改 owner 和 active 对应的公钥,active 可以做除了更改公钥之外的所有操作。用户可自行增加下级权限。

  7. eos使用小端存储。

  8. eos transaction 格式:

    { 
      expiration: '2018-10-07T16:29:39',
      ref_block_num: 55567,
      ref_block_prefix: 637338379,
      max_net_usage_words: 0,
      max_cpu_usage_ms: 0,
      delay_sec: 0,
      context_free_actions: [],
      actions:
        [ {
        account: 'eosio.token',
        name: 'transfer',
        authorization: [ { "actor": "inita", "permission": "active"} ],
        data: '202902f2520e91c3000000008093dd747011010000000000045359530000000000' } ], // 序列化后数据。原数据 { "from": "inita", "to": "initb", "quantity": "7.0000 SYS", "memo": ""}
      transaction_extensions: [] },
      signatures:
        [ 'SIG_K1_KZQRFeGgN5EFctHBqhuV6u24Ewzme4TEnhnw8dEg5SVhkLes9kxcFWanYahdgt9N6LFJCKvREDabhGY5C1PGvhqj1uyJVD' ]
    }
    
    • expiration:超时时间。如果 transaction 没有在该时间内被确认,则将直接无效。可以避免交易确认时间无法被确定。
    • ref_block_num:参考区块的高度。参考区块使得 transaction 只能在指定的链上被确认。则交易无法被分叉攻击。参考区块一般取签名前最后一个不可逆转的区块。ref_block_num = last_irreversible_block_num % 0xffff
      ref_block_prefix:参考区块的前缀。ref_block_prefix = last_irreversible_block_id[8, 12]
    • max_net_usage_words:限制该 transaction 最大 Network 使用
    • max_net_usage_words:限制该 transaction 最大 CPU 使用
    • delay_sec:被打包进区块后需要经过 delay_sec 秒后 transaction 才会被执行。期间用户可取消该 transaction
    • context_free_actions:类似 BTC 的隔离见证。暂时没用。https://github.com/EOSIO/eos/issues/1387
    • actions:具体 action 列表,可以有多个。
    • action.account:智能合约账户名
    • action.name:action 名
    • action.authorization: 指定签名的账户,actor 账户名,permission 是权限。该字段决定签名的私钥。密钥选择方案:
      1. 若由上层解析,传入指定派生路径(根据 slip 48)给硬件。在上层被入侵的情况下,硬件可能会使用不匹配的密钥进行签名。如果在一开始权限授予的时候就被入侵,则子权限密钥可能不符合 slip48 规范,如子权限密钥和父密钥是同一个。此时权限等级机制将失效,安全性会降低。
      2. 硬件实现 slip48,自行解析 authorization 字段并选择恰当密钥。但这样一来扩展性会差一点。
      3. 硬件存储权限->密钥(或派生路径)键值对,这样麻烦一点,但扩展性好一点。
    • action.data:action 参数。已被序列化。

    • transaction_extensions:暂不支持的功能。

    • signatures:签名结果,base58编码,SIG_K1_ 前缀表示签名的曲线是 k1。
  9. eos transaction 序列化:

    eos 使用 eosjs-fcbuffer 进行序列化和反序列化,eosjs-fcbuffer 是 fcbuffer 的 fork 仓库,之前没太多人用。c++ 版本叫 fc

    序列化字段:

    {
    "expiration": 1538569524, // 需要转换为时间戳
    "ref_block_num": 56170,
    "ref_block_prefix": 3374189397,
    "max_net_usage_words": 0,
    "max_cpu_usage_ms": 0,
    "delay_sec": 0,
    "context_free_actions": [],
    "actions": [
      {
        "account": "eosio.token",
        "name": "transfer",
        "authorization": [
          {
            "actor": "inita",
            "permission": "active"
          }
        ],
        "data": { // 被序列化前的数据
          "from": "inita",
          "to": "initb",
          "quantity": "7.0000 SYS",
          "memo": ""
        }
      }
    ],
    "transaction_extensions": []
    }
    

    这些字段对应的类型为:

    {
    "expiration": uint32,
    "ref_block_num": uint16,
    "ref_block_prefix": uint32,
    "max_net_usage_words": varuint32,
    "max_cpu_usage_ms": uint8,
    "delay_sec": varuint32,
    "context_free_actions": vector,
    "actions": [ // vector
      {
        "account": name,
        "name": name,
        "authorization": [ // vector
          {
            "actor": name,
            "permission": name
          }
        ],
        "data": { // data
          "from": name,
          "to": name,
          "quantity": asset,
          "memo": string
        }
      }
    ],
    "transaction_extensions": vector
    }
    

    各字段的转换规则为:(小端存储)(根据 eosjs 和 eosjs-fcbuffer 源码得到)

    • uint8,uint16,uint32:正整数

    • varuint32:变长正整数,1-4个字节。每个 byte 的 [0, 6] 个 bit用于存储数据,最后一个bit用于是否是最后一个bit(0 是 1 不是)

    • vector:列表,size(varuint32) + {data + data + ...}(size 个)

    • name:base32 编码,定长8个字节。因为编码前 name 限制了长度为12,base32 占用5个bit,5 * 12 = 60 < 8 * 8

    • data:特殊类型,length(varuint32) + {from, to, quantity, memo}(length 长度)

    • asset:特殊类型,分为三个部分:amount,precision,symbol。

    • amount 类型为 uint64,amount = value * 10 ^ precision,如7则为0700000000000000, 7.0000则为7011010000000000。
    • precision 类型为 uint8,应小于18(否则amount 可能溢出)。
    • symbol 长度为固定 7 字节,ASCII 编码

    • string:varuint32(length) + UTF8encode(string)

    序列化结果:


    // expiration ref_block_num ref_block_prefix 34b5b45b 6adb 550b1ec9 // max_net_usage_words max_cpu_usage_ms delay_sec context_free_actions 00 00 00 00 // actions [{ // account // name // authorization [{ // actor // permission // }] // }] 01 00a6823403ea3055 000000572d3ccdcd 01 000000000093dd74 00000000a8ed3232 // data: { // from // to // quantity{amount, symbol} // memo // } 21 000000000093dd74 000000008093dd74 7011010000000000 04 53595300000000 00 transaction_extensions 00 // result: 34b5b45b6adb550b1ec9000000000100a6823403ea3055000000572d3ccdcd01000000000093dd7400000000a8ed323221000000000093dd74000000008093dd74701101000000000004535953000000000000
  10. eos 签名
    mainChainId = aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906 // 主网 eos 链 chainId
    jungleChainId = 038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca // 测试网 jungle eos 链 chainId
    sysChainId = cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f // 本地 eos 链默认 chainId
    
    privateKey = 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 // base 58
    // mainnet header privateKey                                                       using compressed pubkey(01 if exist)  checksum(sha256 ^ 2)
    // 80             D2653FF7CBB2D8FF129AC27EF5781CE68B2558C41A74AF1F2DDCA635CBEEF07D                                       AA08644A
    
    chainIdBuf = mainChainId
    buf = 34b5b45b6adb550b1ec9000000000100a6823403ea3055000000572d3ccdcd01000000000093dd7400000000a8ed323221000000000093dd74000000008093dd74701101000000000004535953000000000000 // transaction 序列化结果
    packedContextFreeData = 0000000000000000000000000000000000000000000000000000000000000000 // context_free_actions 的对应数据,eos 官方库是写死的,暂无作用
    
    // 待签名 data
    signBuf = chainIdBuf + buf + packedContextFreeData
    // aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e90692b4bc5bd2d8d970a04b000000000100a6823403ea3055000000572d3ccdcd01000000000093dd7400000000a8ed323227000000000093dd74000000008093dd747011010000000000045359530000000006e59388e59388000000000000000000000000000000000000000000000000000000000000000000
    
    // 待签名 hash
    hash = sha256(signBuf)
    // f502c5b410ef5d08caf0dc9634c4cc83269487864c740be44fca6f50a0c58e94
    
    // 签名
    signature = ecc256k1(hash, privateKey)
    // SIG_K1_KcKPUw1sZ38YYBgYuTKMZa4xvfnZf7pNob7DZ7H6CXfbcfD2o2XsGD1vo9rcMjHjZivvCiNTradUStEcxvuypKxFcdGxBN // base 58
    // i, r, s, checksum( ripemd(i, r, s, 'K1')[0, 4] )
    // 20 39DD0B8AAB045745C28D6B977AC3F23D9805300879C842F186C6CDF3484560F9 28C501782449287FEBB594EB181B5FC58B5242C976F0E2BFD5FAB174099A68CC AC8C898D
    
    // lib/signature.js
    // i = eccrecovery() + 4 + 27, 4 for compressed, 27 for compat // eosjs 是直接 + 4 + 27 的,网上资料不多,不太清楚4和27的含义。eccrecovery() 取值范围 [0, 3]
    
    // 另一个例子:
    // data: aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e9063cb8bc5b22e05aae1c75000000000100a6823403ea3055000000572d3ccdcd01000000000093dd7400000000a8ed323221000000000093dd74000000008093dd747011010000000000045359530000000000000000000000000000000000000000000000000000000000000000000000000000
    // hash: 3b0f1e23e39eff71ef6b2f2670086c3f0894ebf17820a0c3aac5f2467d1dbe2f
    // sig: SIG_K1_JyZ24w3Si9V8zt7axDVX3UNtStTVXWEd3diVwSyZMLMVHiRk3RyTi8LNv3qzWgKzz7LBb3uw7iLjMBhRHu7w4nXHWy1xVN
    
  11. eos 公钥格式

    pubKey = 026B996BC305719A8F563B9E85C9C96A54D40E15F9851FFED5F6A0710504FB5362

    checksum = ripemd160(pubKey)[0, 4] = 1b0e677c

    eosPubKey = 'EOS' + base58(pubKey + checksum) = EOS5hsqHg5EftNtVjVaz39LPnYPEZboYRLbRKK6s4oQEpgsooJ5tP

  12. eos 私钥格式(WIF,虽然公钥默认使用压缩公钥,但不会在私钥末尾加01,而标准WIF规范若使用压缩公钥是需要加01的)

    priKey = D2653FF7CBB2D8FF129AC27EF5781CE68B2558C41A74AF1F2DDCA635CBEEF07D

    checksum = sha256(sha256(80 + priKey)) = AA08644A

    eosPriKey = base58(priKey + checksum) = 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

  13. eos transactionId

    对序列化交易报文进行sha256哈希,不需要添加chainid和packedContextFreeData

  14. eos rpc push_transaction 提交格式

    {
    "compression": "none", // 暂不清楚用途
    "packed_context_free_data": "", // hex data,目前为0
    "packed_trx": "34b5b45b6adb550b1ec9000000000100a6823403ea3055000000572d3ccdcd01000000000093dd7400000000a8ed323221000000000093dd74000000008093dd74701101000000000004535953000000000000", // 交易序列化结果
    "signatures":[  // 所有签名
        "SIG_K1_KeH6wCsnUWRjrfGtqPpXFK4BJArfQ4FwuZARnpVyWkfgdrbrKMgH1msyvrvGyxABYj5UyNpMmipWhpyaruRaRFQbcuDBb4"
     ]
    }
    

版权所有,转载请注明出处:
https://sickworm.com/?p=436

# #