EOS纯技术上手学习 转自知乎 季宙栋 3 个月前

in #eos7 years ago

链接原文

http://EOS.IO 已发布黎明V1.0版本。http://EOS.IO黎明V1.0版本是第一个预发布的http://EOS.IO SDK(软件开发工具包)。http://EOS.IO黎明V1.0版本可以让我们体验下EOS一部分区块链特性和简单上手开发、测试。本篇主要是一个快速的review目前EOS黎明V1.0版本的功能上手。

主要内容:

1. EOS Docker快速部署2. EOSC使用3. 创建钱包4. 将私钥导入钱包5. 锁定和解锁钱包6. 创建账户7. 内置转账8. 查询交易历史9. 测试合约 - currency10. 调用合约11. 查询合约12. 链接特定的节点13. 链接独立钱包服务14. 免签名验证15. 其他RPC调用

EOS Docker快速部署

构建eos镜像

git clone https://github.com/EOSIO/eos.git --recursive
cd eos
cp genesis.json Docker 
docker build -t eosio/eos -f Docker/Dockerfile .

启动容器

sudo rm -rf /data/store/eos # options 
sudo mkdir -p /data/store/eos
docker-compose -f Docker/docker-compose.yml up

如果 docker-compose 启动有报错, 可能需要给文件存储目录赋予用户读写权限

sudo chown -R SYSTEM_USER /data/store/eos

验证,查询区块链状态信息

curl http://127.0.0.1:8888/v1/chain/get_info

如果想使用多节点环境,可使用yml文件启动

version: "2"

services:
  node1:
    image: eosio/eos 
    ports:
    - "8888:8888"
    - "9876:9876"
    volumes:
      - ./node1/data:/opt/eos/bin/data-dir

  node2:
    image: eosio/eos 
    ports:
    - "8889:8889"
    - "9877:9877"
    volumes:
      - ./node2/data:/opt/eos/bin/data-dir
    depends_on:
      - "node1"

EOSC使用

EOSC是EOS的核心进程EOSD对外暴露的RESTAPI命令行工具。EOSC的使用会利用到一些内置插件,插件在EOSD的配置文件config.ini中进行设置,如与链的交互需要使用'plugin = eos::chain_api_plugin'。为了签署交易并发送到区块链上,需要使用‘plugin = eos::wallet_api_plugin’。为了查询交易和历史记录,需要使用'eos::account_history_api_plugin' 。

# Plugin(s) to enable, may be specified multiple times
plugin =
eos::producer_plugin
plugin =
eos::chain_api_plugin
plugin =
eos::wallet_api_plugin
plugin =
eos::account_history_api_plugin

启动eosd后,可以使用EOSC查询当前的区块链状态

docker exec docker_node1_1 eosc get info
{
  "head_block_num": 23449,
  "last_irreversible_block_num": 23432,
  "head_block_id": "00005b996cc85962b28537c3d72696a012d1071638f5e4bad1809cf9afc9abb6",
  "head_block_time": "2017-09-29T01:53:33",
  "head_block_producer": "initi",
  "recent_slots": "1111111111111111111111111111111111111111111111111111111111111111",
  "participation_rate": "1.00000000000000000"
}

创建钱包

任何发送到区块链的交易都需要由所有者持有的私钥进行签名。首先,我们需要一个钱包来储存和管理私钥,使用EOSC命令创建一个钱包。

docker exec docker_node1_1 eosc wallet create
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5JXSxkHqNEwRKCpG2JUTLqkR8SNCBXofkAwaFDLwQkNdqaSXwC8"

命令执行完成,会在eos-walletd中创建一个名为‘default’的钱包,并返回钱包密码。这时候可以查看钱包列表

docker exec docker_node1_1 eosc wallet list
Wallets: 
[
  "default *"
]

如果你没有指定钱包名称,默认都操作的是‘default’钱包

将私钥导入钱包

如果你想授权某个钱包可以由某人来管理和控制,需要导入该授权者的私钥。

docker exec docker_node1_1 eosc wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
imported private key for:
EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

导入后,可以查询钱包已经导入的私钥和对应的公钥

docker exec docker_node1_1 eosc wallet keys
[[
"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"
]
]

锁定和解锁钱包

日常使用,为了保证私钥安全,可临时锁定钱包,锁定后查看钱包列表是不可见的

docker exec docker_node1_1 eosc wallet lock
Locked: 'default'

当想要使用时,可以用创建钱包时生成的密码来解锁钱包

docker exec docker_node1_1 eosc wallet unlock --password PW5KVWrn81Y8PLAb52gr2FyXCanVavcrj9d5TC9C3yKhqq1PJYRPk
Unlocked: 'default'

解锁后,可以在列表重新看到default钱包了

docker exec docker_node1_1 eosc wallet list
Wallets: 
[
  "default *"
]

创建账户

创建账户需要有两组密钥:owner和active。EOS使用EOSC工具来创建密钥对1)owner key.

Private key:5JRc8XxvodWey4StZ2zzkUhCQhDaHvGMkABtfHzQR2ie4qaUFJ7
Public key: EOS5mFEdAzxvMkHLQXt2v4naUjnBrPGmzMUCikymqhSR6m7QLGSTB

2)active key

Private key:5KNzFCbToz2a9Hztz9Qen5cyJcM3x5Wpq4GFiTYZgGhzntXdmYo
Public key: EOS5EdsvESpibWLJxupTqod1nswJnbiXQZuUcLiAWEEsqcZskymeB

EOSC不会保存生成的私钥因为后续测试智能合约需要,我们创建一个名为currency的账号。目前这个版本,所有的账户都需要用已有账户来创建,所以我们用inita账户的owener key和active key来创建currency。 为了使inita获得发送交易的权限,需要先导入inita的私钥到钱包。(参见私钥导入钱包的步骤

docker exec docker_node1_1 eosc create account inita currency EOS6NpEqWi177VKQkuJQL9V6Y3LqAAp9C2jDsAagMW4uELw72Z2oP EOS5V8geYBkAEtCcs5TMgMsWJqsRk5CMyh5jCvPxbGtGDfnnSXjqP 

执行成功,会输出一串json的交易信息,打印账户创建相关内容
我们可以查询inita可以创建了哪些用户

docker exec docker_node1_1 eosc get servants inita
{
"controlled_accounts": [
"currency"
]
}

内置转账

创建账户之后,可以查看当前账户的状态,可以看到创建的测试账号没有余额,这样不少功能无法测试,我们需要试着给创建账户添加一些余额

docker exec docker_node1_1 eosc get account currency
{
  "name": "currency",
  "eos_balance": "0.0000 EOS",
  "staked_balance": "0.0001 EOS",
  "unstaking_balance": "0.0000 EOS",
  "last_unstaking_time": "1969-12-31T23:59:59",
  "permissions": [{
      "name": "active",
      "parent": "owner",
      "required_auth": {
        "threshold": 1,
        "keys": [{
            "key": "EOS8ff42NMpJUybVj3nwUSnPpc3mMysKxyE4HVJy1E5o3fQv7knWf",
            "weight": 1
          }
        ],
        "accounts": []
      }
    },{
      "name": "owner",
      "parent": "owner",
      "required_auth": {
        "threshold": 1,
        "keys": [{
            "key": "EOS5fQ4saiHV426EQ7AKrGoD2AVMBYe77bnGSq42JjXBUfipv7o3E",
            "weight": 1
          }
        ],
        "accounts": []
      }
    }
  ]
}

保存全网余额的创世账号是eos,查询余额状态

docker exec docker_node1_1 eosc get account eos
{
  "name": "eos",
  "eos_balance": "69000000.0000 EOS",
  "staked_balance": "0.0000 EOS",
  "unstaking_balance": "0.0000 EOS",
  "last_unstaking_time": "1969-12-31T23:59:59",
  "permissions": [{
      "name": "active",
      "parent": "owner",
      "required_auth": {
        "threshold": 1,
        "keys": [],
        "accounts": []
      }
    },{
      "name": "owner",
      "parent": "owner",
      "required_auth": {
        "threshold": 1,
        "keys": [],
        "accounts": []
      }
    }
  ]
}

我们可以通过创世块定义的创世账户使用EOSC给当前创建的账户转移余额

docker exec docker_node1_1 eosc transfer inita currency 100000000
{
  "transaction_id": "59575b8caf08eac7c00eb7483c048f12d0e7abf1ede839c3b2ed41dc6c5c7c5f",
  "processed": {
    "refBlockNum": 24199,
    "refBlockPrefix": 1485651173,
    "expiration": "2017-09-29T02:31:03",
    "scope": [
      "currency",
      "inita"
    ],
    "signatures": [
      "1f14229bdd4bfb927021bf96ff0651c8b0fa5666e9f5cf423a0270a1b91f2d2f690b573e179d8475ce2c6b160f5cd5507d58a44f8f6cf536348584efa8dd62ade0"
    ],
    "messages": [{
        "code": "eos",
        "type": "transfer",
        "authorization": [{
            "account": "inita",
            "permission": "active"
          }
        ],
        "data": {
          "from": "inita",
          "to": "currency",
          "amount": 100000000,
          "memo": ""
        },
        "hex_data": "000000000093dd740000001e4d75af4600e1f5050000000000"
      }
    ],
    "output": [{
        "notify": [{
            "name": "currency",
            "output": {
              "notify": [],
              "deferred_transactions": []
            }
          },{
            "name": "inita",
            "output": {
              "notify": [],
              "deferred_transactions": []
            }
          }
        ],
        "deferred_transactions": []
      }
    ]
  }
}

再通过执行get account 命令,验证余额已经成功转移到创建的账户下

查询交易历史

查询交易历史会使用到插件account_history_api_plugin,我们已经在config.ini中定义

docker exec docker_node1_1 eosc get transaction 
如果需要查询一个特定账户最近一次的交易记录
docker exec docker_node1_1 eosc get transaction inita

创建智能合约

官方提供了一个示例合约currency,我们依然使用EOSC来创建并部署智能合约,合约代码位置contracts/currency。1)为合约创建一个所有者账户。前文已经创建了currency账户2)检查区块链上有无同名合约

docker exec docker_node1_1 eosc get code currency 
code hash: 0000000000000000000000000000000000000000000000000000000000000000 

3)为了获得部署权限(发送交易请求)需要将currency的active key导入到钱包中4)部署合约(.wast后缀文件)和他的abi(.abi后缀文件)

docker exec docker_node1_1 eosc set contract currency ../../contracts/currency/currency.wast ../../contracts/currency/currency.abi
Reading WAST...
Assembling WASM...
Publishing contract...

屏幕打印部署成功相关的信息,并查询合约hash

docker exec docker_node1_1 eosc get code currency 
code hash: c4023f74b3c7a3321d1641e4111b13584078fa7265c6ab12e1c19ff7ee800faf

调用合约

在合约部署到区块链上之后,所有的currency余额会分配给我们创建的currency账户。我们可以调用合约测试做一些转账交易。为了更好了解区块链合约的调用方式,我们可以通过.abi查看可以执行的操作列表和消息结构。

docker exec docker_node1_1 eosc get code -a currency.abi currency
code hash: c4023f74b3c7a3321d1641e4111b13584078fa7265c6ab12e1c19ff7ee800faf
saving abi to currency.abi
cat currency.abi #查看
{
  "types": [{
      "newTypeName": "AccountName",
      "type": "Name"
    }
  ],
  "structs": [{
      "name": "transfer",
      "base": "",
      "fields": {
        "from": "AccountName",
        "to": "AccountName",
        "amount": "UInt64"
      }
    },{
      "name": "account",
      "base": "",
      "fields": {
        "account": "Name",
        "balance": "UInt64"
      }
    }
  ],
  "actions": [{
      "action": "transfer",
      "type": "transfer"
    }
  ],
  "tables": [{
      "table": "account",
      "type": "account",
      "indextype": "i64",
      "keynames" : ["account"],
      "keytypes" : ["Name"]
    }
  ]
}

通过上面的abi我们可以看到currency合约可以执行transfer操作,消息格式为from,to和amount。我们调用合约从currency账户转移50个余额到inita账户

docker exec docker_node1_1 eosc push message currency transfer '{"from":"currency","to":"inita","amount":50}' --scope currency,inita --permission currency@active

执行完成,我们查询余额验证结果

docker exec docker_node1_1 eosc get table inita currency account
{
  "rows": [{
      "account": "account",
      "balance": 50 
       }
    ],
  "more": false
}
docker exec docker_node1_1 eosc get table currency currency account
{
  "rows": [{
      "account": "account",
      "balance": 999999950
    }
  ],
  "more": false
}

余额不足的账户尝试转账,会提示失败

docker exec docker_node1_1 eosc push message currency transfer '{"from":"tester","to":"inita","amount":50}'-S inita -S tester -p tester@active
3543610ms thread-0 main.cpp:271 operator() ] Converting argument to binary...
3543615ms thread-0 main.cpp:311  main ] Failed with error: 10 assert_exception: Assert Exception
status_code == 200: Error : 10 assert_exception: Assert Exception
test: assertion failed: integer underflow subtracting token balance
{"s":"integer underflow subtracting token balance","ptr":176} thread-1 wasm_interface.cpp:248 assertnonei32i32 [...snipped...]

查询合约

如上文验证步骤,在调用完合约后,可以通过查询表来验证每个帐户持有的余额。

docker exec docker_node1_1 eosc get table currency currency account

连接特定节点

默认情况下,EOSC连接本地端口8888的节点。可以通过指定主机地址和端口来连接其他EOSD节点。同样的,钱包服务也可以指定特定的主机地址和端口。

docker exec docker_node1_1 eosc --host  --port 

链接独立钱包服务

除了使用EOSD内置的钱包服务,也可以独立部署钱包服务

docker exec docker_node1_1 eos-walletd --http-server-endpoint host:port
调用独立钱包服务需要添加如下选项
docker exec docker_node1_1 eosc --wallet-host --wallet-port

免签名验证

开发者如果需要快速测试功能,可以跳过节点签名的步骤,这样可以解耦密码学的问题而关注应用功能

启动时使用特定参数
eosd --skip-transaction-signatures
EOSC调用时添加-s 选项
docker exec docker_node1_1 eosc <COMMAND> <SUBCOMMAND> -s <PARAMS>

其他RPC调用

EOSD RPC 包含通过HTTP RPC与eosd和注册其上的插件进行调用的方式.1)区块链API 配置想要查询eosd信息需要启用plugin = eos::chain_api_plugin插件并添加至config.ini中2)get_info接口用于查询区块链的基础信息

curl http://127.0.0.1:8888/v1/chain/get_info 

返回结果如下:

{"head_block_num":25028,"last_irreversible_block_num":25014,"head_block_id":"000061c443dd3e85932c442a8e5176b7ac822a0f6d09d034298f508e71c5ae6c","head_block_time":"2017-09-29T03:12:30","head_block_producer":"initm","recent_slots":"1111111111111111111111111111111111111111111111111111111111111111","participation_rate":"1.00000000000000000"}

3) get_block接口用于查询区块相关信息

curl  http://localhost:8888/v1/chain/get_block -X POST -d '{"block_num_or_id":5}'
curl  http://localhost:8888/v1/chain/get_block -X POST -d '{"block_num_or_id":0000000445a9f27898383fd7de32835d5d6a978cc14ce40d9f327b5329de796b}'

返回结果如下:

{"previous":"000000047aba47492d2143beebfdfba171192970a0f9248f0408a8614ff42dca","timestamp":"2017-09-28T06:21:21","transaction_merkle_root":"0000000000000000000000000000000000000000000000000000000000000000","producer":"initf","producer_changes":[],"producer_signature":"1f25a5b592b7f605ffdbd1cba90497e94b3e1c0e5805b70851de6875e0f33e20dd1f363cd1fcfd2dc8421fb918d694d260e255956cc7f8f554fa0be01d805a84ed","cycles":[],"id":"00000005bf39fd177fc2ea8ba6540d5f31e8b07218f054016123a34b16d0b30e","block_num":5,"refBlockPrefix":2347418239}

4)push_transaction接口,调用合约交易该调用为JSON格式并会将结果更新到区块链上执行正确的结果返回

返回 HTTP 200 和交易ID号
{ 
'transaction_id' : "..." 
}

执行错误的结果返回,一般为400错误(参数错误)或者500错误

HTTP/1.1 500 Internal Server Error
Content-Length: 1466
...error message..

push_transaction 调用方法

curl  http://localhost:8888/v1/chain/push_transaction -X POST -d '{"refBlockNum":"5","refBlockPrefix":"27728114","expiration":"2017-07-18T22:28:49","scope":["initb","initc"],"messages":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"c9252a0000000000050f14dc29000000d00700000000000008454f530000000000"}],"signatures":[],"authorizations":[]}'

此示例模拟一个转账交易。 refBlockNum和refBlockPrefix使用的前例block查询的结果