Geth - Transaction 구조

CHOYEAH·2023년 11월 27일
0

Go ethreume

목록 보기
6/11

Transaction 구조

/go-ethereum/internal/ethapi/transaction_args.go

type TransactionArgs struct {
	From                 *common.Address `json:"from"`
	To                   *common.Address `json:"to"`
	Gas                  *hexutil.Uint64 `json:"gas"`
	GasPrice             *hexutil.Big    `json:"gasPrice"`
	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
	Value                *hexutil.Big    `json:"value"`
	Nonce                *hexutil.Uint64 `json:"nonce"`

	// We accept "data" and "input" for backwards-compatibility reasons.
	// "input" is the newer name and should be preferred by clients.
	// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
	Data  *hexutil.Bytes `json:"data"`
	Input *hexutil.Bytes `json:"input"`

	// Introduced by AccessListTxType transaction.
	AccessList *types.AccessList `json:"accessList,omitempty"`
	ChainID    *hexutil.Big      `json:"chainId,omitempty"`
}
  • MaxFeePerGas: eip1559에 적용되어 추가된 필드, 이더리움 네트워크에서 정해진 가스 가격보다 높게 책정되어야한다. 남은 가스는 돌려받을 수 있고 사용된 가스는 소각된다.

  • MaxPriorityFeePerGas: eip1559에 적용되어 추가된 필드,채굴자에게 지급되는 수수료.

  • Nonce: 트랜잭션을 발생시킨 계정의 트랜잭션 횟수, 0부터 1씩 증가함. 트랜잭션이 재사용되는것을 방지함.

  • Data: 트랜잭션에 포함시키는 데이터, 컨트랙트 배포나 실행시 이 필드에 값을 넣어 사용. 그외에도 특정한 문자를 16진수로 변환하여 포함시켜 사용할 수 있다.

  • input: data 필드의 데이터를 읽을때 사용, 반환된 트랜잭션 객체에서 인풋 필드를 통해 데이터의 값을 가져올 수 있다.

  • AccessList: 트랜잭션이 접근할 address와 스토리지 키 목록, eip2930 적용때 추가됨, 어드레스와 스토리지 키를 명시함으로써 트랜잭션 가스 소비량을 줄일 수 있음.

    스토리지 키는 스마트 계약 내의 특정 데이터를 참조하는 데 사용되는 키이다. 이더리움의 스마트 계약은 각자 고유한 저장 공간을 가지며, 이 저장 공간은 키-값(key-value) 쌍으로 구성된 "스토리지"를 통해 데이터를 저장하고 검색한다.

  • ChainID: 트랜잭션을 실행할 네트워크 아이디, eip155적용때 추가됨. 다른 체인에서 트랜잭션이 재실행되는것을 방지함.

SendTransaction()

/go-ethereum/internal/ethapi/api.go

// SendTransaction creates a transaction for the given argument, sign it and submit it to the
// transaction pool.
func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) {
	// Look up the wallet containing the requested signer
	account := accounts.Account{Address: args.from()}

	wallet, err := s.b.AccountManager().Find(account)
	if err != nil {
		return common.Hash{}, err
	}

	if args.Nonce == nil {
		// Hold the mutex around signing to prevent concurrent assignment of
		// the same nonce to multiple accounts.
		s.nonceLock.LockAddr(args.from())
		defer s.nonceLock.UnlockAddr(args.from())
	}

	// Set some sanity defaults and terminate on failure
	if err := args.setDefaults(ctx, s.b); err != nil {
		return common.Hash{}, err
	}
	// Assemble the transaction and sign with the wallet
	tx := args.toTransaction()

	signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID)
	if err != nil {
		return common.Hash{}, err
	}
	return SubmitTransaction(ctx, s.b, signed)
}

Transacion types

/go-ethereum/core/types/transaction.go


// Transaction types.
const (
	LegacyTxType     = 0x00
	AccessListTxType = 0x01
	DynamicFeeTxType = 0x02
	BlobTxType       = 0x03
)

베를린 하드포크 이전엔 단일 트랜잭션만 존재했었음

/go-ethereum/internal/ethapi/transaction_args.go


// toTransaction converts the arguments to a transaction.
// This assumes that setDefaults has been called.
func (args *TransactionArgs) toTransaction() *types.Transaction {
	var data types.TxData
	switch {
	case args.MaxFeePerGas != nil:
		al := types.AccessList{}
		if args.AccessList != nil {
			al = *args.AccessList
		}
		data = &types.DynamicFeeTx{
			To:         args.To,
			ChainID:    (*big.Int)(args.ChainID),
			Nonce:      uint64(*args.Nonce),
			Gas:        uint64(*args.Gas),
			GasFeeCap:  (*big.Int)(args.MaxFeePerGas),
			GasTipCap:  (*big.Int)(args.MaxPriorityFeePerGas),
			Value:      (*big.Int)(args.Value),
			Data:       args.data(),
			AccessList: al,
		}
	case args.AccessList != nil:
		data = &types.AccessListTx{
			To:         args.To,
			ChainID:    (*big.Int)(args.ChainID),
			Nonce:      uint64(*args.Nonce),
			Gas:        uint64(*args.Gas),
			GasPrice:   (*big.Int)(args.GasPrice),
			Value:      (*big.Int)(args.Value),
			Data:       args.data(),
			AccessList: *args.AccessList,
		}
	default:
		data = &types.LegacyTx{
			To:       args.To,
			Nonce:    uint64(*args.Nonce),
			Gas:      uint64(*args.Gas),
			GasPrice: (*big.Int)(args.GasPrice),
			Value:    (*big.Int)(args.Value),
			Data:     args.data(),
		}
	}
	return types.NewTx(data)
}

SendTransaction() 내부의 args.toTransaction() 호출 부분에서 포함된 필드에 따라 트랜잭션 타입을 결정하여 리턴시킨다.

Transaction Receipt

트랜잭션이 완료되면 해당 트랜잭션의 리십트를 확인할 수 있다. 리십트는 트랜잭션의 로그를 저장하는 용도로 사용한다. 주로 컨트랙트를 실행하면서 발생하는 이벤트를 저장한다.

/go-ethereum/core/types/receipt.go

// Receipt represents the results of a transaction.
type Receipt struct {
	// Consensus fields: These fields are defined by the Yellow Paper
	Type              uint8  `json:"type,omitempty"`
	PostState         []byte `json:"root"`
	Status            uint64 `json:"status"`
	CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
	Bloom             Bloom  `json:"logsBloom"         gencodec:"required"`
	Logs              []*Log `json:"logs"              gencodec:"required"`

	// Implementation fields: These fields are added by geth when processing a transaction.
	TxHash            common.Hash    `json:"transactionHash" gencodec:"required"`
	ContractAddress   common.Address `json:"contractAddress"`
	GasUsed           uint64         `json:"gasUsed" gencodec:"required"`
	EffectiveGasPrice *big.Int       `json:"effectiveGasPrice"` // required, but tag omitted for backwards compatibility
	BlobGasUsed       uint64         `json:"blobGasUsed,omitempty"`
	BlobGasPrice      *big.Int       `json:"blobGasPrice,omitempty"`

	// Inclusion information: These fields provide information about the inclusion of the
	// transaction corresponding to this receipt.
	BlockHash        common.Hash `json:"blockHash,omitempty"`
	BlockNumber      *big.Int    `json:"blockNumber,omitempty"`
	TransactionIndex uint        `json:"transactionIndex"`
}

콘솔에서 트랜잭션 해시로 리십트 확인

> eth.getTransactionReceipt("0x88abfcaac5e2de99ee8f19877318c1c99f3bf677216666430795eb245e53d846")
{
  blockHash: "0xec155e8565eb52c11baa40e7c251ef384cd7415f22a5f2798d83b67c1199610a",
  blockNumber: 987,
  contractAddress: null,
  cumulativeGasUsed: 21064,
  effectiveGasPrice: 1000000000,
  from: "0x6730ae899d1b135f13544543c88f354b5d79a715",
  gasUsed: 21064,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  to: "0x8ef79508112a2369ec7a3f276ea803eb8be5a9fe",
  transactionHash: "0x88abfcaac5e2de99ee8f19877318c1c99f3bf677216666430795eb245e53d846",
  transactionIndex: 0,
  type: "0x0"
}

컨트랙트를 배포하거나 실행한것이 아니기 때문에 logs, logsBloom이 비어있음

profile
Move fast & break things

0개의 댓글