mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
Merge branch 'master' of https://github.com/orakle-opensource/EIP_opensource
This commit is contained in:
commit
f0995b4f1a
1 changed files with 367 additions and 0 deletions
367
EIPs/eip-1559.md
367
EIPs/eip-1559.md
|
|
@ -48,6 +48,373 @@ EIP-1559에서는 이전 블록의 사이즈가 목표 블록 사이즈보다
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
```python
|
||||||
|
from typing import Union, Dict, Sequence, List, Tuple, Literal
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TransactionLegacy:
|
||||||
|
signer_nonce: int = 0
|
||||||
|
gas_price: int = 0
|
||||||
|
gas_limit: int = 0
|
||||||
|
destination: int = 0
|
||||||
|
amount: int = 0
|
||||||
|
payload: bytes = bytes()
|
||||||
|
v: int = 0
|
||||||
|
r: int = 0
|
||||||
|
s: int = 0
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Transaction2930Payload:
|
||||||
|
chain_id: int = 0
|
||||||
|
signer_nonce: int = 0
|
||||||
|
gas_price: int = 0
|
||||||
|
gas_limit: int = 0
|
||||||
|
destination: int = 0
|
||||||
|
amount: int = 0
|
||||||
|
payload: bytes = bytes()
|
||||||
|
access_list: List[Tuple[int, List[int]]] = field(default_factory=list)
|
||||||
|
signature_y_parity: bool = False
|
||||||
|
signature_r: int = 0
|
||||||
|
signature_s: int = 0
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Transaction2930Envelope:
|
||||||
|
type: Literal[1] = 1
|
||||||
|
payload: Transaction2930Payload = Transaction2930Payload()
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Transaction1559Payload:
|
||||||
|
chain_id: int = 0
|
||||||
|
signer_nonce: int = 0
|
||||||
|
# EIP-1559 트랜잭션은 priority_fee 도입
|
||||||
|
max_priority_fee_per_gas: int = 0
|
||||||
|
max_fee_per_gas: int = 0
|
||||||
|
gas_limit: int = 0
|
||||||
|
destination: int = 0
|
||||||
|
amount: int = 0
|
||||||
|
payload: bytes = bytes()
|
||||||
|
access_list: List[Tuple[int, List[int]]] = field(default_factory=list)
|
||||||
|
signature_y_parity: bool = False
|
||||||
|
signature_r: int = 0
|
||||||
|
signature_s: int = 0
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Transaction1559Envelope:
|
||||||
|
type: Literal[2] = 2
|
||||||
|
payload: Transaction1559Payload = Transaction1559Payload()
|
||||||
|
|
||||||
|
Transaction2718 = Union[Transaction1559Envelope, Transaction2930Envelope]
|
||||||
|
|
||||||
|
Transaction = Union[TransactionLegacy, Transaction2718]
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NormalizedTransaction:
|
||||||
|
signer_address: int = 0
|
||||||
|
signer_nonce: int = 0
|
||||||
|
max_priority_fee_per_gas: int = 0
|
||||||
|
max_fee_per_gas: int = 0
|
||||||
|
gas_limit: int = 0
|
||||||
|
destination: int = 0
|
||||||
|
amount: int = 0
|
||||||
|
payload: bytes = bytes()
|
||||||
|
access_list: List[Tuple[int, List[int]]] = field(default_factory=list)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Block:
|
||||||
|
parent_hash: int = 0
|
||||||
|
uncle_hashes: Sequence[int] = field(default_factory=list)
|
||||||
|
author: int = 0
|
||||||
|
state_root: int = 0
|
||||||
|
transaction_root: int = 0
|
||||||
|
transaction_receipt_root: int = 0
|
||||||
|
logs_bloom: int = 0
|
||||||
|
difficulty: int = 0
|
||||||
|
number: int = 0
|
||||||
|
gas_limit: int = 0 # note the gas_limit is the gas_target * ELASTICITY_MULTIPLIER
|
||||||
|
gas_used: int = 0
|
||||||
|
timestamp: int = 0
|
||||||
|
extra_data: bytes = bytes()
|
||||||
|
proof_of_work: int = 0
|
||||||
|
nonce: int = 0
|
||||||
|
base_fee_per_gas: int = 0
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Account:
|
||||||
|
address: int = 0
|
||||||
|
nonce: int = 0
|
||||||
|
balance: int = 0
|
||||||
|
storage_root: int = 0
|
||||||
|
code_hash: int = 0
|
||||||
|
|
||||||
|
INITIAL_BASE_FEE = 1000000000
|
||||||
|
INITIAL_FORK_BLOCK_NUMBER = 10 # TBD
|
||||||
|
BASE_FEE_MAX_CHANGE_DENOMINATOR = 8
|
||||||
|
ELASTICITY_MULTIPLIER = 2
|
||||||
|
|
||||||
|
class World(ABC):
|
||||||
|
# EIP-1559에서 제안된 baseFee 계산 방식과 블록 검증 로직 구현
|
||||||
|
# geth, consensus/misc/eip1559/eip1559.go
|
||||||
|
# VerifyEIP1559Header: EIP-1559이후 변경된 헤더 속성을 검증
|
||||||
|
# CalcBaseFee: header의 basefee를 계산
|
||||||
|
# geth, consensus/misc/gaslimit.go
|
||||||
|
# VerifyGaslimit은 header gas limit관 parentgas limit의 증가/감소관계를 확인한다.
|
||||||
|
def validate_block(self, block: Block) -> None:
|
||||||
|
parent_gas_target = self.parent(block).gas_limit // ELASTICITY_MULTIPLIER
|
||||||
|
parent_gas_limit = self.parent(block).gas_limit
|
||||||
|
|
||||||
|
# on the fork block, don't account for the ELASTICITY_MULTIPLIER to avoid
|
||||||
|
# unduly halving the gas target.
|
||||||
|
# 포크 블록에서는 gas target이 과도하게 반감되는 것을 방지하기 위해 Elasticity_multiplier를 고려하지 않음
|
||||||
|
# 포크 시점에 가스 목표량은 유지되지만, 가스 한도는 증가하여 네트워크 처리량 감소를 방지
|
||||||
|
if INITIAL_FORK_BLOCK_NUMBER == block.number:
|
||||||
|
parent_gas_target = self.parent(block).gas_limit
|
||||||
|
parent_gas_limit = self.parent(block).gas_limit * ELASTICITY_MULTIPLIER
|
||||||
|
|
||||||
|
parent_base_fee_per_gas = self.parent(block).base_fee_per_gas
|
||||||
|
parent_gas_used = self.parent(block).gas_used
|
||||||
|
transactions = self.transactions(block)
|
||||||
|
|
||||||
|
# check if the block used too much gas
|
||||||
|
# 가스가 너무 많이 사용되었는지 확인
|
||||||
|
assert block.gas_used <= block.gas_limit, 'invalid block: too much gas used'
|
||||||
|
|
||||||
|
# check if the block changed the gas limit too much
|
||||||
|
# gas limit 이 너무 크게 변경되었는지 확인
|
||||||
|
assert block.gas_limit < parent_gas_limit + parent_gas_limit // 1024, 'invalid block: gas limit increased too much'
|
||||||
|
assert block.gas_limit > parent_gas_limit - parent_gas_limit // 1024, 'invalid block: gas limit decreased too much'
|
||||||
|
|
||||||
|
# check if the gas limit is at least the minimum gas limit
|
||||||
|
# gas limit 이 최소 gas limit 이상인지 확인
|
||||||
|
assert block.gas_limit >= 5000
|
||||||
|
|
||||||
|
# check if the base fee is correct
|
||||||
|
# base fee 계산 및 확인
|
||||||
|
# geth, consensus/misc/eip1559/eip1559.go, CalcBaseFee
|
||||||
|
if INITIAL_FORK_BLOCK_NUMBER == block.number:
|
||||||
|
expected_base_fee_per_gas = INITIAL_BASE_FEE
|
||||||
|
elif parent_gas_used == parent_gas_target:
|
||||||
|
expected_base_fee_per_gas = parent_base_fee_per_gas
|
||||||
|
elif parent_gas_used > parent_gas_target:
|
||||||
|
gas_used_delta = parent_gas_used - parent_gas_target
|
||||||
|
base_fee_per_gas_delta = max(parent_base_fee_per_gas * gas_used_delta // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR, 1)
|
||||||
|
expected_base_fee_per_gas = parent_base_fee_per_gas + base_fee_per_gas_delta
|
||||||
|
else:
|
||||||
|
gas_used_delta = parent_gas_target - parent_gas_used
|
||||||
|
base_fee_per_gas_delta = parent_base_fee_per_gas * gas_used_delta // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR
|
||||||
|
expected_base_fee_per_gas = parent_base_fee_per_gas - base_fee_per_gas_delta
|
||||||
|
assert expected_base_fee_per_gas == block.base_fee_per_gas, 'invalid block: base fee not correct'
|
||||||
|
|
||||||
|
# execute transactions and do gas accounting
|
||||||
|
# 트랜잭션을 실행하고 gas 집계를 수행
|
||||||
|
cumulative_transaction_gas_used = 0
|
||||||
|
for unnormalized_transaction in transactions:
|
||||||
|
# Note: this validates transaction signature and chain ID which must happen before we normalize
|
||||||
|
# below since normalized transactions don't include signature or chain ID
|
||||||
|
# normalized transaction에는 signature와 chainID가 포함되지 않기 때문에 트랜잭션 일반화를 하기 전에 트랜잭션 서명과 chain ID를 검증
|
||||||
|
signer_address = self.validate_and_recover_signer_address(unnormalized_transaction)
|
||||||
|
transaction = self.normalize_transaction(unnormalized_transaction, signer_address)
|
||||||
|
|
||||||
|
signer = self.account(signer_address)
|
||||||
|
|
||||||
|
signer.balance -= transaction.amount
|
||||||
|
assert signer.balance >= 0, 'invalid transaction: signer does not have enough ETH to cover attached value'
|
||||||
|
# the signer must be able to afford the transaction
|
||||||
|
# 최소한 트랜잭션을 보낼 수 있는 가스비 여유가 있는지 확인
|
||||||
|
assert signer.balance >= transaction.gas_limit * transaction.max_fee_per_gas
|
||||||
|
|
||||||
|
# ensure that the user was willing to at least pay the base fee
|
||||||
|
# fee로 최소한 base fee만큼 지불할 의사가 있는지 확인
|
||||||
|
assert transaction.max_fee_per_gas >= block.base_fee_per_gas
|
||||||
|
|
||||||
|
# Prevent impossibly large numbers
|
||||||
|
# 불가능할 정도로 큰 수 방지
|
||||||
|
assert transaction.max_fee_per_gas < 2**256
|
||||||
|
# Prevent impossibly large numbers
|
||||||
|
assert transaction.max_priority_fee_per_gas < 2**256
|
||||||
|
# The total must be the larger of the two
|
||||||
|
# total max fee가 priority max fee보다 커야한다
|
||||||
|
assert transaction.max_fee_per_gas >= transaction.max_priority_fee_per_gas
|
||||||
|
|
||||||
|
# priority fee is capped because the base fee is filled first
|
||||||
|
# priority fee는 base fee가 먼저 부과되기 때문에 제한된다.
|
||||||
|
priority_fee_per_gas = min(transaction.max_priority_fee_per_gas, transaction.max_fee_per_gas - block.base_fee_per_gas)
|
||||||
|
|
||||||
|
# signer pays both the priority fee and the base fee
|
||||||
|
# 서명자는 priority fee와 base fee를 둘다 지불한다
|
||||||
|
effective_gas_price = priority_fee_per_gas + block.base_fee_per_gas
|
||||||
|
signer.balance -= transaction.gas_limit * effective_gas_price
|
||||||
|
assert signer.balance >= 0, 'invalid transaction: signer does not have enough ETH to cover gas'
|
||||||
|
|
||||||
|
# effective_gas_price는 GASPRICE (0x3a) opcode에 의해 리턴되는 값이다.
|
||||||
|
gas_used = self.execute_transaction(transaction, effective_gas_price)
|
||||||
|
|
||||||
|
# 실제로 사용되고 남은 gas는 다시 환불된다.
|
||||||
|
# signer gets refunded for unused gas
|
||||||
|
gas_refund = transaction.gas_limit - gas_used
|
||||||
|
cumulative_transaction_gas_used += gas_used
|
||||||
|
signer.balance += gas_refund * effective_gas_price
|
||||||
|
# miner only receives the priority fee; note that the base fee is not given to anyone (it is burned)
|
||||||
|
# 채굴자는 priority fee만 받고, base fee는 burned 된다.
|
||||||
|
self.account(block.author).balance += gas_used * priority_fee_per_gas
|
||||||
|
|
||||||
|
# check if the block spent too much gas transactions
|
||||||
|
# 블록에 속한 모든 트랜잭션의 사용된 가스량의 합(cumulative_transaction_gas_used)과 블록이 사용한 gas량(block.gas_used)이 동일한지 확인한다.
|
||||||
|
assert cumulative_transaction_gas_used == block.gas_used, 'invalid block: gas_used does not equal total gas used in all transactions'
|
||||||
|
|
||||||
|
# TODO: verify account balances match block's account balances (via state root comparison)
|
||||||
|
# 계정잔액이 블록의 account balances와 동일한지 확인
|
||||||
|
# 블록체인에서는 모든 계정의 상태(잔액, 코드, 저장된 데이터 등)가 블록 헤더에 있는 상태 루트를 통해 요약됩니다.
|
||||||
|
# 따라서 블록에 대한 유효성 검사를 수행할 때는 블록 헤더에 있는 상태 루트와 실제 계정의 상태를 비교하여 일치하는지 확인해야 함
|
||||||
|
# TODO: validate the rest of the block
|
||||||
|
# 나머지 블록 검증
|
||||||
|
|
||||||
|
# 트랜잭션 정규화
|
||||||
|
def normalize_transaction(self, transaction: Transaction, signer_address: int) -> NormalizedTransaction:
|
||||||
|
# legacy transactions
|
||||||
|
if isinstance(transaction, TransactionLegacy):
|
||||||
|
return NormalizedTransaction(
|
||||||
|
signer_address = signer_address,
|
||||||
|
signer_nonce = transaction.signer_nonce,
|
||||||
|
gas_limit = transaction.gas_limit,
|
||||||
|
max_priority_fee_per_gas = transaction.gas_price,
|
||||||
|
max_fee_per_gas = transaction.gas_price,
|
||||||
|
destination = transaction.destination,
|
||||||
|
amount = transaction.amount,
|
||||||
|
payload = transaction.payload,
|
||||||
|
access_list = [],
|
||||||
|
)
|
||||||
|
# 2930 transactions
|
||||||
|
elif isinstance(transaction, Transaction2930Envelope):
|
||||||
|
return NormalizedTransaction(
|
||||||
|
signer_address = signer_address,
|
||||||
|
signer_nonce = transaction.payload.signer_nonce,
|
||||||
|
gas_limit = transaction.payload.gas_limit,
|
||||||
|
max_priority_fee_per_gas = transaction.payload.gas_price,
|
||||||
|
max_fee_per_gas = transaction.payload.gas_price,
|
||||||
|
destination = transaction.payload.destination,
|
||||||
|
amount = transaction.payload.amount,
|
||||||
|
payload = transaction.payload.payload,
|
||||||
|
access_list = transaction.payload.access_list,
|
||||||
|
)
|
||||||
|
# 1559 transactions
|
||||||
|
elif isinstance(transaction, Transaction1559Envelope):
|
||||||
|
return NormalizedTransaction(
|
||||||
|
signer_address = signer_address,
|
||||||
|
signer_nonce = transaction.payload.signer_nonce,
|
||||||
|
gas_limit = transaction.payload.gas_limit,
|
||||||
|
max_priority_fee_per_gas = transaction.payload.max_priority_fee_per_gas,
|
||||||
|
max_fee_per_gas = transaction.payload.max_fee_per_gas,
|
||||||
|
destination = transaction.payload.destination,
|
||||||
|
amount = transaction.payload.amount,
|
||||||
|
payload = transaction.payload.payload,
|
||||||
|
access_list = transaction.payload.access_list,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise Exception('invalid transaction: unexpected number of items')
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def parent(self, block: Block) -> Block: pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def block_hash(self, block: Block) -> int: pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def transactions(self, block: Block) -> Sequence[Transaction]: pass
|
||||||
|
|
||||||
|
# effective_gas_price is the value returned by the GASPRICE (0x3a) opcode
|
||||||
|
# effective_gas_price는 GASPRICE (0x3a) opcode에 의해 리턴되는 값이다.
|
||||||
|
@abstractmethod
|
||||||
|
def execute_transaction(self, transaction: NormalizedTransaction, effective_gas_price: int) -> int: pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def validate_and_recover_signer_address(self, transaction: Transaction) -> int: pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def account(self, address: int) -> Account: pass
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
// VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559,
|
||||||
|
// - gas limit check
|
||||||
|
// - basefee check
|
||||||
|
// VerifyEIP1559Header 함수는 EIP-1559이후 변경된 헤더 속성을 검증한다
|
||||||
|
func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Header) error {
|
||||||
|
// Verify that the gas limit remains within allowed bounds
|
||||||
|
// gas limit이 허용된 범위 안에 있는지 검증한다
|
||||||
|
parentGasLimit := parent.GasLimit
|
||||||
|
if !config.IsLondon(parent.Number) {
|
||||||
|
parentGasLimit = parent.GasLimit * config.ElasticityMultiplier()
|
||||||
|
}
|
||||||
|
if err := misc.VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Verify the header is not malformed
|
||||||
|
// 헤더가 잘못된 형식이 아닌지 확인한다(baseFee)
|
||||||
|
if header.BaseFee == nil {
|
||||||
|
return errors.New("header is missing baseFee")
|
||||||
|
}
|
||||||
|
// Verify the baseFee is correct based on the parent header.
|
||||||
|
// baseFee가 parent header에 근거해 올바른지 확인한다.
|
||||||
|
expectedBaseFee := CalcBaseFee(config, parent)
|
||||||
|
if header.BaseFee.Cmp(expectedBaseFee) != 0 {
|
||||||
|
return fmt.Errorf("invalid baseFee: have %s, want %s, parentBaseFee %s, parentGasUsed %d",
|
||||||
|
header.BaseFee, expectedBaseFee, parent.BaseFee, parent.GasUsed)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalcBaseFee calculates the basefee of the header.
|
||||||
|
// CalcBaseFee는 header의 basefee를 계산한다.
|
||||||
|
func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||||
|
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
||||||
|
// 현재 블록이 EIP-1559의 첫번째 블록이면, InitialBaseFee를 반환한다.
|
||||||
|
// -----Config가 런던인지 검사하는데 첫번째 블록과 어떤 관련성 있는지?
|
||||||
|
// ----->EIP-1559는 런던 하드포크에서 시행됨, 즉 런던 하드포크의 첫번째 블록부터 BaseFee시행
|
||||||
|
if !config.IsLondon(parent.Number) {
|
||||||
|
return new(big.Int).SetUint64(params.InitialBaseFee)
|
||||||
|
}
|
||||||
|
|
||||||
|
parentGasTarget := parent.GasLimit / config.ElasticityMultiplier()
|
||||||
|
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
|
||||||
|
// 부모블록의 gasUsed가 target과 같으면, baseFee는 변경되지 않음.
|
||||||
|
if parent.GasUsed == parentGasTarget {
|
||||||
|
return new(big.Int).Set(parent.BaseFee)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
num = new(big.Int)
|
||||||
|
denom = new(big.Int)
|
||||||
|
)
|
||||||
|
|
||||||
|
if parent.GasUsed > parentGasTarget {
|
||||||
|
// If the parent block used more gas than its target, the baseFee should increase.
|
||||||
|
// max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
|
||||||
|
// 만약 부모 블록이 타겟보다 많은 gas를 사용했으면, baseFee는 증가한다.
|
||||||
|
num.SetUint64(parent.GasUsed - parentGasTarget)
|
||||||
|
num.Mul(num, parent.BaseFee)
|
||||||
|
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||||
|
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
||||||
|
baseFeeDelta := math.BigMax(num, common.Big1)
|
||||||
|
|
||||||
|
return num.Add(parent.BaseFee, baseFeeDelta)
|
||||||
|
} else {
|
||||||
|
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
|
||||||
|
// max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
|
||||||
|
// 만약 부모 블록이 타겟보다 적은 gas를 사용했으면, baseFee는 감소한다.
|
||||||
|
num.SetUint64(parentGasTarget - parent.GasUsed)
|
||||||
|
num.Mul(num, parent.BaseFee)
|
||||||
|
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||||
|
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
||||||
|
baseFee := num.Sub(parent.BaseFee, num)
|
||||||
|
// 코드가 위 로직이랑 일관되지 않은데 개선사항?
|
||||||
|
return math.BigMax(baseFee, common.Big0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue