体验Hyperledger-Burrow-4

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)