burrow, tx

burrow tx commit

RPC -> Transactor.BroadcastTxSync -> Mempoo.CheckTx -> abci.CheckTx -> executor.Execute -> SendContext.Execute

Call stack:

github.com/hyperledger/burrow/execution/contexts.(*SendContext).Execute at send_context.go:20
github.com/hyperledger/burrow/execution.(*executor).Execute at execution.go:254
github.com/hyperledger/burrow/consensus/abci.ExecuteTx at execute_tx.go:30
github.com/hyperledger/burrow/consensus/abci.(*App).CheckTx at app.go:189
github.com/tendermint/tendermint/abci/client.(*localClient).CheckTxAsync at local_client.go:99
github.com/tendermint/tendermint/proxy.(*appConnMempool).CheckTxAsync at app_conn.go:114
github.com/tendermint/tendermint/mempool.(*CListMempool).CheckTx at clist_mempool.go:281
github.com/tendermint/tendermint/mempool.Mempool.CheckTx-fm at mempool.go:18
github.com/hyperledger/burrow/execution.(*Transactor).CheckTxAsyncRaw at transactor.go:237
github.com/hyperledger/burrow/execution.(*Transactor).CheckTxSyncRaw at transactor.go:206
github.com/hyperledger/burrow/execution.(*Transactor).CheckTxSync at transactor.go:134
github.com/hyperledger/burrow/execution.(*Transactor).BroadcastTxSync at transactor.go:83
github.com/hyperledger/burrow/rpc/rpctransact.(*transactServer).BroadcastTxSync at transact_server.go:55
github.com/hyperledger/burrow/rpc/rpctransact._Transact_BroadcastTxSync_Handler.func1 at rpctransact.pb.go:505
github.com/hyperledger/burrow/rpc.unaryInterceptor.func1 at grpc.go:31
github.com/hyperledger/burrow/rpc/rpctransact._Transact_BroadcastTxSync_Handler at rpctransact.pb.go:507
google.golang.org/grpc.(*Server).processUnaryRPC at server.go:1024
google.golang.org/grpc.(*Server).handleStream at server.go:1313
google.golang.org/grpc.(*Server).serveStreams.func1.1 at server.go:722
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
google.golang.org/grpc.(*Server).serveStreams.func1 at server.go:720

TX executor

Verify and execute the ‘TypeSend’ context: exe.contexts[txEnv.Tx.Type()]

// 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) {
	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())
		}
	}()

	logger := exe.logger.WithScope("executor.Execute(tx txs.Tx)").With(
		"height", exe.block.Height,
		"run_call", exe.runCall,
		structure.TxHashKey, txEnv.Tx.Hash())

	logger.InfoMsg("Executing transaction", "tx", txEnv.String())

	// 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())
}

Executor context

0 = TypeUnbond (18) ->
1 = TypeBond (17) ->
2 = TypeProposal (35) ->
3 = TypeIdentify (36) ->
4 = TypeCall (2) ->
5 = TypeSend (1) ->
6 = TypeName (3) ->
7 = TypePermissions (33) ->
8 = TypeGovernance (34) ->

TypeSend

  • Check permission
  • Make output account if need
  • Check account balance
  • adjust by input and output
func (ctx *SendContext) Execute(txe *exec.TxExecution, p payload.Payload) error {
	var ok bool
	ctx.tx, ok = p.(*payload.SendTx)
	if !ok {
		return fmt.Errorf("payload must be SendTx, but is: %v", txe.Envelope.Tx.Payload)
	}
	accounts, inTotal, err := getInputs(ctx.State, ctx.tx.Inputs)
	if err != nil {
		return err
	}

	// ensure all inputs have send permissions
	err = allHavePermission(ctx.State, permission.Send, accounts, ctx.Logger)
	if err != nil {
		return errors.Wrap(err, "at least one input lacks permission for SendTx")
	}

	// add outputs to accounts map
	// if any outputs don't exist, all inputs must have CreateAccount perm
	accounts, err = getOrMakeOutputs(ctx.State, accounts, ctx.tx.Outputs, ctx.Logger)
	if err != nil {
		return err
	}

	outTotal, err := validateOutputs(ctx.tx.Outputs)
	if err != nil {
		return err
	}
	if outTotal > inTotal {
		return errors.Codes.InsufficientFunds
	}
	if outTotal < inTotal {
		return errors.Codes.Overpayment
	}
	if outTotal == 0 {
		return errors.Codes.ZeroPayment
	}

	// Good! Adjust accounts
	err = adjustByInputs(accounts, ctx.tx.Inputs)
	if err != nil {
		return err
	}

	err = adjustByOutputs(accounts, ctx.tx.Outputs)
	if err != nil {
		return err
	}

	for _, acc := range accounts {
		err = ctx.State.UpdateAccount(acc)
		if err != nil {
			return err
		}
	}

	for _, i := range ctx.tx.Inputs {
		txe.Input(i.Address, nil)
	}

	for _, o := range ctx.tx.Outputs {
		txe.Output(o.Address, nil)
	}

	return nil
}

allHavePermission

It wll check the accounts of Input for permissions:

func allHavePermission(accountGetter acmstate.AccountGetter, perm permission.PermFlag,
	accs map[crypto.Address]*acm.Account, logger *logging.Logger) error {
	for _, acc := range accs {
		if !HasPermission(accountGetter, acc, perm, logger) {
			return errors.PermissionDenied{
				Address: acc.Address,
				Perm:    perm,
			}
		}
	}
	return nil
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值