Zhuang's Diary

言之有物,持之以恒

CheckTx

在burrow项目中,/consensus/abci/app.go:

1
2
3
4
5
func (app *App) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx {
......
checkTx := ExecuteTx(logHeader, app.checker, app.txDecoder, req.GetTx())
......
}

此处的 ExecuteTx 位于 /execution/execution.go :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// If the tx is invalid, an error will be returned.
// Unlike ExecBlock(), state will not be altered.
func (exe *executor) Execute(txEnv *txs.Envelope) (txe *exec.TxExecution, err error) {
......
// Verify transaction signature against inputs
err = txEnv.Verify(exe.params.ChainID)
if err != nil {
logger.InfoMsg("Transaction Verify failed", structure.ErrorKey, err)
return nil, err
}

if txExecutor, ok := exe.contexts[txEnv.Tx.Type()]; ok {
// Establish new TxExecution
txe := exe.block.Tx(txEnv)
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered from panic in executor.Execute(%s): %v\n%s", txEnv.String(), r,
debug.Stack())
}
}()

err = exe.validateInputsAndStorePublicKeys(txEnv)
if err != nil {
logger.InfoMsg("Transaction validate failed", structure.ErrorKey, err)
txe.PushError(err)
return nil, err
}

err = txExecutor.Execute(txe, txe.Envelope.Tx.Payload)
if err != nil {
logger.InfoMsg("Transaction execution failed", structure.ErrorKey, err)
txe.PushError(err)
return nil, err
}

// Increment sequence numbers for Tx inputs
err = exe.updateSequenceNumbers(txEnv)
if err != nil {
logger.InfoMsg("Updating sequences failed", structure.ErrorKey, err)
txe.PushError(err)
return nil, err
}
// Return execution for this tx
return txe, nil
}
return nil, fmt.Errorf("unknown transaction type: %v", txEnv.Tx.Type())
}

此处 txExecutor.Execute(txe, txe.Envelope.Tx.Payload)txExecutor 类型的不同,分别对应至 /txs/payload/payload.go 中的 Type ,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Account transactions
TypeSend = Type(0x01)
TypeCall = Type(0x02)
TypeName = Type(0x03)
TypeBatch = Type(0x04)

// Validation transactions
TypeBond = Type(0x11)
TypeUnbond = Type(0x12)

// Admin transactions
TypePermissions = Type(0x21)
TypeGovernance = Type(0x22)
TypeProposal = Type(0x23)
TypeIdentify = Type(0x24)

根据 Type 不同,在如下 contexts 对应的 Context 的 Execute 方法则会不同,分别对应为如下代码文件中的 Execute 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
├── burrow
│ ├── execution
│ │ ├── contexts
│ │ │ ├── bond_context.go
│ │ │ ├── bond_context_test.go
│ │ │ ├── call_context.go
│ │ │ ├── governance_context.go
│ │ │ ├── identify_context.go
│ │ │ ├── name_context.go
│ │ │ ├── permissions_context.go
│ │ │ ├── proposal_context.go
│ │ │ ├── send_context.go
│ │ │ ├── shared.go
│ │ │ └── unbond_context.go

例如,在执行发送 TypeCall 类型的交易时, txExecutor.Execute(txe, txe.Envelope.Tx.Payload) 对应的具体逻辑为 /execution/contexts/call_context.go 中的 Execute 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func (ctx *CallContext) Execute(txe *exec.TxExecution, p payload.Payload) error {
var ok bool
ctx.tx, ok = p.(*payload.CallTx)
if !ok {
return fmt.Errorf("payload must be CallTx, but is: %v", p)
}
ctx.txe = txe
inAcc, outAcc, err := ctx.Precheck()
if err != nil {
return err
}
// That the fee less than the input amount is checked by Precheck to be greater than or equal to fee
value := ctx.tx.Input.Amount - ctx.tx.Fee

if ctx.RunCall {
return ctx.Deliver(inAcc, outAcc, value)
}
return ctx.Check(inAcc, value)
}

DeliverTx

在执行 ExecuteTx(logHeader, app.committer, app.txDecoder, req.GetTx()) 中,executor execution.Executor 被指定为 app.committer , 与 CheckTX 执行同样的 Execute 逻辑

Commit

具体执行逻辑为 /execution/execution.go 中的 func (exe *executor) Commit(header *abciTypes.Header) (stateHash []byte, err error)

./burrow natives , Dump Solidity interface contracts for Burrow native contracts.

抽出Burrow内置的solidity接口合约。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
➜  script ./burrow natives       
pragma solidity >=0.4.24;

/**
* acmstate.ReaderWriter for managing Secure Native authorizations.
* @dev This interface describes the functions exposed by the native permissions layer in burrow.
* @dev These functions can be accessed as if this contract were deployed at a special address (0x0A758FEB535243577C1A79AE55BED8CA03E226EC).
* @dev This special address is defined as the last 20 bytes of the sha3 hash of the the contract name.
* @dev To instantiate the contract use:
* @dev Permissions permissions = Permissions(address(uint256(keccak256("Permissions"))));
*/
interface Permissions {
/**
* @notice Adds a role to an account
* @param Account account address
* @param Role role name
* @return result whether role was added
*/
function addRole(address _account, string memory _role) public view returns (bool _result);

/**
* @notice Removes a role from an account
* @param Account account address
* @param Role role name
* @return result whether role was removed
*/
function removeRole(address _account, string memory _role) public view returns (bool _result);

/**
* @notice Indicates whether an account has a role
* @param Account account address
* @param Role role name
* @return result whether account has role
*/
function hasRole(address _account, string memory _role) public view returns (bool _result);

/**
* @notice Sets the permission flags for an account. Makes them explicitly set (on or off).
* @param Account account address
* @param Permission the base permissions flags to set for the account
* @param Set whether to set or unset the permissions flags at the account level
* @return The permission flag that was set as uint64
*/
function setBase(address _account, uint64 _permission, bool _set) public view returns (uint64 _result);

/**
* @notice Unsets the permissions flags for an account. Causes permissions being unset to fall through to global permissions.
* @param Account account address
* @param Permission the permissions flags to unset for the account
* @return The permission flag that was unset as uint64
*/
function unsetBase(address _account, uint64 _permission) public view returns (uint64 _result);

/**
* @notice Indicates whether an account has a subset of permissions set
* @param Account account address
* @param Permission the permissions flags (mask) to check whether enabled against base permissions for the account
* @return result whether account has the passed permissions flags set
*/
function hasBase(address _account, uint64 _permission) public view returns (bool _result);

/**
* @notice Sets the global (default) permissions flags for the entire chain
* @param Permission the permissions flags to set
* @param Set whether to set (or unset) the permissions flags
* @return The permission flag that was set as uint64
*/
function setGlobal(uint64 _permission, bool _set) public view returns (uint64 _result);
}

./burrow dump , Dump chain state to backup

1
2
3
4
5
6
7
8
➜  script ./burrow dump local backup_dump
Sourcing config from first of: defaults
Sourcing config from defaults
Sourcing config from first of: genesis file at genesis.json
Sourcing config from genesis file at genesis.json
{"log_channel":"Info","message":"Dumping accounts"}
{"log_channel":"Info","message":"Dumping names"}
{"log_channel":"Info","message":"Dumping events"}

./burrow restore, Restore new chain from backup

从backup文件恢复区块链

文档链接=>https://hyperledger.github.io/burrow/

github链接=>https://github.com/hyperledger/burrow/

接前文《体验Hyperledger-Burrow-1》,启动4个节点如下:

1
2
3
4
5
6
➜  script ps aux | grep burrow
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
will 21409 2.1 0.8 133268 66036 pts/1 SNl 08:52 1:02 ./burrow start --config=burrow000.toml
will 21410 1.9 0.7 133268 59212 pts/1 SNl 08:52 0:56 ./burrow start --config=burrow001.toml
will 21411 2.0 0.8 133268 65924 pts/1 SNl 08:52 0:59 ./burrow start --config=burrow002.toml
will 21416 2.0 0.7 133268 63416 pts/1 SNl 08:52 1:01 ./burrow start --config=burrow003.toml

制作增加节点的配置文件

1
./burrow spec -v1 | ./burrow configure -s- > burrow_add.toml

运行完成后,增加公私钥文档如下:

1
2
3
4
5
6
7
8
➜  data pwd
/home/will/documents/burrow/script/.keys/data
➜ data cat 035B1B192A16FF8086C36304024010502CEB2DE0.json
{"CurveType":"ed25519","Address":"5ECA9967F5D363F21C4606CC971710200A64C5BC","PublicKey":"4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128","AddressHash":"go-crypto-0.5.0","PrivateKey":{"Crypto":"none","Plain":"486059FB274248423F92B7522D5A237AB99B38C80F84D46F720EAE1506D8E2DF4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128"}}
➜ names pwd
/home/will/documents/burrow/script/.keys/names
➜ names cat Validator_0
035B1B192A16FF8086C36304024010502CEB2DE0

修改burrow_add.toml配置:
1.删除GenesisDoc的内容,因为genesis.json中已经包含了节点们的GenesisDoc;
2.增加PersistentPeers,PersistentPeers在burrow000.toml中可以找到;
3关闭grpc端口,关闭rpc.info等,否则会跟已有的4个节点端口冲突

发出增加validator的Tx

制作增加validator Tx 交易的文件:

1
2
3
4
5
6
jobs:
- name: AddValidator
update-account:
target: 4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128
power: 222222
permissions: [root, send, call, createContract, createAccount, bond, name, proposal, input, batch, identify, hasBase, setBase, unsetBase, setGlobal, hasRole, addRole, removeRole]

其中4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128 是新节点的publickey。

执行交易命令(DCF0F3BD45EA59B2D471729EC22838DF7B119012 是增加节点前已经启动的4个节点中的Full Account节点。),即在已经启动的节点上执行本交易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
./burrow deploy -c 127.0.0.1:10997 --mempool-signing=true --address=DCF0F3BD45EA59B2D471729EC22838DF7B119012 deploy.yaml
log_channel=Info message="Using chain" Chain=127.0.0.1:10997 Signer=
log_channel=Info message="Loading Playbook File."
log_channel=Info message="Loading playbook file" path=/home/will/documents/burrow/script filename=/home/will/documents/burrow/script/deploy.yaml
log_channel=Info message="*****Executing Job*****" JobName=defaultAddr Type=Account
log_channel=Info message="Setting Account" account=DCF0F3BD45EA59B2D471729EC22838DF7B119012
log_channel=Info message="*****Executing Job*****" JobName=AddValidator Type=UpdateAccount
log_channel=Info message=GovTx account="unsupported value type"
log_channel=Info message="Using mempool signing since no keyClient set, pass --keys to sign locally or elsewhere"
log_channel=Info message="Using mempool signing"
log_channel=Info message="Tx Return" TransactionHash=5a1a57e975e5ead5079c12c63c473e1c04c59cf82fe9974f191faaf1d8aeb8b8 BlockHeight=18
log_channel=Info message="Job Vars" name=input value=DCF0F3BD45EA59B2D471729EC22838DF7B119012
log_channel=Info message="Job Vars" name=native value=
log_channel=Info message="Job Vars" name=power value=222222
log_channel=Info message="Job Vars" name=sequence value=
log_channel=Info message="Job Vars" name=address value=
log_channel=Info message="Job Vars" name=publicKey value=D90E05FAD677699B4FEE56B567F85D3A90438B4B627C27CED0D4C850BDC97876
log_channel=Info message="Writing to current directory" output=/home/will/documents/burrow/script/deploy.output.json
log_channel=Info message="JOBS THAT SUCCEEEDED" count=1
log_channel=Info message="Playbook result" jobNo=0 file=deploy.yaml time=230.744184ms

注意:新创建的validator没有余额。

启动新增加的节点

1
./burrow start --config=burrow_add.toml --genesis=genesis.json --address=5ECA9967F5D363F21C4606CC971710200A64C5BC

5ECA9967F5D363F21C4606CC971710200A64C5BC 是被增加节点的地址(address)。

1
2
3
4
5
6
7
➜  script ps aux | grep burrow
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
will 21409 2.1 0.8 133268 66036 pts/1 SNl 08:52 1:02 ./burrow start --config=burrow000.toml
will 21410 1.9 0.7 133268 59212 pts/1 SNl 08:52 0:56 ./burrow start --config=burrow001.toml
will 21411 2.0 0.8 133268 65924 pts/1 SNl 08:52 0:59 ./burrow start --config=burrow002.toml
will 21416 2.0 0.7 133268 63416 pts/1 SNl 08:52 1:01 ./burrow start --config=burrow003.toml
will 21505 2.2 0.7 133268 58864 pts/1 Sl+ 08:55 1:01 ./burrow start --config=burrow_add.toml --genesis=genesis.json --address=DCF0F3BD45EA59B2D471729EC22838DF7B119012

ed25519是tendermint选择的加密曲线,secp256k1是ethereum选择的加密曲线。

两者都可以在./burrow keys list 中看到账户地址和名称。在web3.getAccounts中只能够看到secp256k1曲线下生成的账户地址,metamask和remix也是如此。

burrow keys gen -n -t secp256k1 --name zhuang 如果不指定 -n 的话,需要输入密码。

发送转账交易

创建转账交易 deploy_sendToken.yaml

1
2
3
4
5
jobs:
- name: sendTxTest1
send:
destination: 0DE8C14FE07FA693D3A6F65D826647D39E9A3BB0
amount: 2000

发起

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜  script ./burrow keys gen -n -t secp256k1 --name zhuang1
0DE8C14FE07FA693D3A6F65D826647D39E9A3BB0
➜ script ./burrow deploy --address CCC93802D38A33B636D8B2B74218021A571CF252 deploy_sendToken.yaml
log_channel=Info message="Using chain" Chain=127.0.0.1:10997 Signer=
log_channel=Info message="Loading Playbook File."
log_channel=Info message="Loading playbook file" path=/home/will/documents/burrow/script filename=/home/will/documents/burrow/script/deploy_sendToken.yaml
log_channel=Info message="*****Executing Job*****" JobName=defaultAddr Type=Account
log_channel=Info message="Setting Account" account=CCC93802D38A33B636D8B2B74218021A571CF252
log_channel=Info message="*****Executing Job*****" JobName=sendTxTest1 Type=Send
log_channel=Info message="Sending Transaction" source=CCC93802D38A33B636D8B2B74218021A571CF252 destination=0DE8C14FE07FA693D3A6F65D826647D39E9A3BB0 amount=2000
log_channel=Info message=SendTx send="unsupported value type"
log_channel=Info message="Using mempool signing since no keyClient set, pass --keys to sign locally or elsewhere"
log_channel=Info message="Using mempool signing"
log_channel=Info message="Tx Return" TransactionHash=a0abda87ea4751beaeae04d5ac67c35114b9f068720db6e1795ec7083c4a872e BlockHeight=27
log_channel=Info message="Writing to current directory" output=/home/will/documents/burrow/script/deploy_sendToken.output.json
log_channel=Info message="JOBS THAT SUCCEEEDED" count=1
log_channel=Info message="Playbook result" jobNo=0 file=deploy_sendToken.yaml time=347.234362ms

文档链接=>https://hyperledger.github.io/burrow/

github链接=>https://github.com/hyperledger/burrow/

Burrow是一个权限控制较为严格、以太坊EVM和WASM虚拟机支持、运行于Tendermint共识之上的区块链客户端。其主要由Monax贡献,并由Monax 和英特尔赞助。

其强调的设计理念包括:

  1. 防篡改的Merkle状态—Tamper-resistant merkle state
  2. PoS支持
  3. 链上治理原生支持
  4. 以太坊账户一览
  5. 可以根据每个帐户设置代码执行权限
  6. 事件流支持
  7. 智能合约事件弹出至SQL表记录
  8. GRPC和Protobuf支持
  9. Javascript SDK支持,客户端库可以生成代码来访问合约,生成的代码是静态的Typescript对象
  10. Keys服务,提供代理签名服务器
  11. Web3 RPC,兼容Ethereum主网的开发工具,如 Truffle、 Metamask、Remix

Burrow应用于多个区块链生产项目

初始化Burrow节点

https://github.com/hyperledger/burrow/下载可执行文件,本文以 ubuntu 环境为例。

1
./burrow spec -f2 -p2 | ./burrow configure --curve-type secp256k1 -s- --pool --separate-genesis-doc=genesis.json

./burrow spec 建立一个GenesisSpec作为GenesisDoc和configure命令的模板,f2是指2个full-accounts,p2是指2个participant-accounts。

--curve-type secp256k1 是指定加密曲线的类型。

./burrow configure -s- 通过使用GenesisDoc或GenesisSpec,创建密钥并创建配置文档。--pool 为名为burrowNNN.toml的所有共识节点(validators)编写配置文件。--separate-genesis-doc 将genesis文档投送至 JSON或者TOML文件。

  • validator-accounts 共识的参与者,需要抵押一部分资金

  • root-accounts 根账户

  • developer-accounts 开发者,功能很多和全节点很像

  • participant-accounts 参与者

  • full-accounts 全功能

启动Burrow节点

1
2
3
4
5
6
7
8
➜  script ./burrow start --config=burrow000.toml &
./burrow start --config=burrow001.toml &
./burrow start --config=burrow002.toml &
./burrow start --config=burrow003.toml &
[5] 12458
[6] 12459
[7] 12460
[8] 12464

网页端访问RPC服务

http://127.0.0.1:26759/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Available endpoints:
//127.0.0.1:26759/account_stats
//127.0.0.1:26759/accounts
//127.0.0.1:26759/chain_id
//127.0.0.1:26759/consensus
//127.0.0.1:26759/genesis
//127.0.0.1:26759/network
//127.0.0.1:26759/network/registry
//127.0.0.1:26759/validators

Endpoints that require arguments:
//127.0.0.1:26759/account?address=_
//127.0.0.1:26759/account_human?address=_
//127.0.0.1:26759/block?height=_
//127.0.0.1:26759/blocks?minHeight=_&maxHeight=_
//127.0.0.1:26759/dump_storage?address=_
//127.0.0.1:26759/name?name=_
//127.0.0.1:26759/names?regex=_
//127.0.0.1:26759/status?block_time_within=_&block_seen_time_within=_
//127.0.0.1:26759/storage?address=_&key=_
//127.0.0.1:26759/unconfirmed_txs?maxTxs=_

Kuboard 是 Kubernetes 的一款图形化管理界面。参考如下链接:https://kuboard.cn/install/install-dashboard.html 安装kuboard

  1. kuboard 首页
  1. Deployment 视图页面

体验结论:

  1. kuboard 比 Kubernetes Dashboard(Kubernetes 的官方 Web UI)要友好许多,并且 Kubernetes Dashboard 需要在操作机中具备 Kubectl;
  2. wayne 对用户的权限管理会优秀一些。但是经过docker-compose实验,启动为dev版本,未成功打开页面
  3. rancherhttps://github.com/rancher/)Rancher为您提供“Kubernetes即服务(Kubernetes-as-a-Service)”。在国内北京、上海、深圳、沈阳均有办公地点,汉语支持较好。推荐使用。