/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적용때 추가됨. 다른 체인에서 트랜잭션이 재실행되는것을 방지함.
/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)
}
/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() 호출 부분에서 포함된 필드에 따라 트랜잭션 타입을 결정하여 리턴시킨다.
트랜잭션이 완료되면 해당 트랜잭션의 리십트를 확인할 수 있다. 리십트는 트랜잭션의 로그를 저장하는 용도로 사용한다. 주로 컨트랙트를 실행하면서 발생하는 이벤트를 저장한다.
/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이 비어있음