From b7165cea9c23fc2bae7a8ba6c6f69e616443e6af Mon Sep 17 00:00:00 2001 From: smin-k Date: Fri, 5 Apr 2024 17:36:50 +0900 Subject: [PATCH] EIPs: add eip-2.md --- EIPs/eip-2.md | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 EIPs/eip-2.md diff --git a/EIPs/eip-2.md b/EIPs/eip-2.md new file mode 100644 index 0000000000..fa8981b88c --- /dev/null +++ b/EIPs/eip-2.md @@ -0,0 +1,256 @@ +##
EIP-2: Homestead Hard-fork 분석
+ +
Seungmin Kim
+
2024-04-04
+ + + +### 개요 +이 문서는 오라클 일반세션 오픈소스 팀 EIP 분석 프로젝트의 일환으로 EIP-2 에서 제안하는 내용과 그 분석에 대해서 서술합니다. + + +### 변경사항. + +#### 1. 트랜잭션을 통해 스마트계약을 생성하는 경우의 가스 비용을 21,000 에서 53,000으로 증가시킵니다. + +트랜잭션을 보내고 받는 사람 주소가 빈 문자열인 경우 차감되는 초기 가스는 현재의 경우인 21,000이 아니라 53,000에 tx 데이터의 가스 비용을 더한 금액입니다. CREATE opcode를 사용한 계약 생성은 영향을 받지 않습니다. + +스마트 계약을 생성하는 방식은 두개가 존재한다. + +1. 트랜잭션 To 를 빈 주소(0x0)로 전송하는 방법: 21,000 gas + +2. CREATE opcode를 사용하는 방법: 32,000 gas + +홈스테드 이전의 이더리움 버전의 경우 비용이 32,000인 CREATE opcode 보다 비용이 21,000인 거래를 통해 계약을 생성하는 데 초과 인센티브가 있습니다. + +또한 가스비용이 저렴하기 때문에, 자살 환불(suicide refunds)방법을 통해 11,664개의 가스만 사용하여 이더리움을 전송할 수 있었습니다. + +자살 환불(suicide refunds)방법은 환불되는 가스의 주소를 전송할 주소로 지정하여 계약을 배포하는 방법입니다. + +자살환불을 시도하는 python code +```python +from ethereum import tester as t +> from ethereum import utils +> s = t.state() +> c = s.abi_contract('def init():\n suicide(0x47e25df8822538a8596b28c637896b4d143c351e)', endowment=10**15) +> s.block.get_receipts()[-1].gas_used +11664 +>s.block.get_balance(utils.normalize_address(0x47e25df8822538a8596b28c637896b4d143c351e)) +1000000000000000 +``` + +code +```go +TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions. +TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. + +... + +CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. + +... + +SelfdestructRefundGas uint64 = 24000 // suicide 는 현재 selfdestruct 로 변경되었음. +``` + +```go +// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. +func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { + // Set the starting gas for the raw transaction + var gas uint64 + //eip2: 계약 생성 트랜잭션의 경우 가스비를 추가함. + if isContractCreation && isHomestead { + gas = params.TxGasContractCreation + } else { + gas = params.TxGas + } +... +``` + +#### 2. S 값이 (secp256k1 ∙ n)/2 보다 큰 모든 거래 서명은 이제 유효하지 않은 것으로 간주됩니다. + +홈스테드 이전 버전에서는 공격자가 원래의 서명을 통해 새로운 유효한 서명을 생성할 수 있습니다. 이더리움의 ECDSA 서명은 (r,s) 의 쌍 값과 복구 식별자 'v' 를 가집니다. 그러나 이 서명 값을 알고 있다면,유효한 서명을 s를 사용하여 하나 더 생성할 수 있습니다. + +(r, n - s) 와 v를 뒤집으면(27-> 28, 28->27), 새로운 유효한 서명이 생성됩니다. + +이더리움은 이더 가치 전송이나 다른 거래에 대한 입력으로 주소를 사용하기 때문에 이는 심각한 보안 결함은 아니지만 공격자가 거래를 방해할 수 있으므로 불편함을 초래할 수 있습니다. + +```go +func VerifySignature(pubkey, hash, signature []byte) bool { + if len(signature) != 64 { + return false + } + var r, s btcec.ModNScalar + if r.SetByteSlice(signature[:32]) { + return false // overflow + } + if s.SetByteSlice(signature[32:]) { + return false + } + sig := btc_ecdsa.NewSignature(&r, &s) + key, err := btcec.ParsePubKey(pubkey) + if err != nil { + return false + } + // Reject malleable signatures. libsecp256k1 does this check but btcec doesn't. + if s.IsOverHalfOrder() { + return false + } + return sig.Verify(hash, key) +} +``` + + + +#### 3. 계약 생성 프로세스에서 계약 코드를 상태에 추가하기 위한 최종 가스 요금을 지불할 만큼 가스가 충분하지 않은 경우 빈 계약을 유지하는 대신 계약 생성이 실패되도록 합니다. + +최종 가스 수수료를 지불할 가스가 충분하지 않은 경우 계약 생성에 실패하면, 다음과 같은 이점이 있습니다. + +(i) 현재의 "성공, 실패 또는 빈 계약"의 삼분법보다는 계약 생성 프로세스의 결과에 보다 직관적인 "성공 또는 실패" 구분을 생성합니다. + +(ii) 계약 생성이 완전히 성공하지 않으면 계약 계정이 전혀 생성되지 않으므로 실패를 더 쉽게 감지할 수 있습니다. 그리고 + +(iii) 전체 개시 프로세스가 발생하거나 거래가 실패하고 기부금이 환불된다는 보장이 있으므로 기부금이 있는 경우 계약 생성을 더 안전하게 만듭니다. + +code +```go + // We first execute the transaction at the highest allowable gas limit, since if this fails we + // can return error immediately. + failed, result, err := execute(ctx, call, opts, hi) + if err != nil { + return 0, nil, err + } + if failed { + if result != nil && !errors.Is(result.Err, vm.ErrOutOfGas) { + return 0, result.Revert(), result.Err + } + return 0, nil, fmt.Errorf("gas required exceeds allowance (%d)", hi) + } +``` + + + +#### 4. 현재 공식에서 난이도 조정 알고리즘을 변경합니다: + +$ +\text{block\_diff} = \text{parent\_diff} + \frac{\text{parent\_diff}}{2048} \times \begin{cases} +1, & \text{if block\_timestamp} - \text{parent\_timestamp} < 13 \\ +-1, & \text{otherwise} +\end{cases} + \text{int}\left(2^{\left(\frac{\text{block.number}}{100000} - 2\right)}\right) +$ + +를 + +$\text{block\_diff} = \text{parent\_diff} + \frac{\text{parent\_diff}}{2048} \times \max\left(1 - \frac{\text{block\_timestamp} - \text{parent\_timestamp}}{10}, -99\right) + \text{int}\left(2^{\left(\frac{\text{block.number}}{100000} - 2\right)}\right) +$ + +로 변경합니다. 최소 난이도는 그대로 유지되며 최소 난이도 아래로는 변경되지 않습니다. + +기존의 난이도 알고리즘은 네트워크의 해시레이크가 급격하게 변하는 경우, 빠르게 이에 적응하는 것이 어렵습니다. 때문에 2015년 9월 이더리움 프로토콜에서 과도한 수의 채굴자가 $parent_{timestamp} + 1$ 의 타임스탬프 값(1초의 블록 생성 시간을)을 가지는 블록들을 채굴하던 문제가 있었고, 이는 블록 시간 분포를 왜곡 시켰습니다. + + + +따라서 새로운 난이도 알고리즘은 이러한 문제를 해결하도록 제안되었습니다. 제안된 새로운 공식은 대략적으로 평균값을 목표로 하고 있으며, 이 공식은 24초보다 긴 평균 블록 시간이 수학적으로 불가능하다는 것을 증명할 수 있습니다. + +시간 차이가 아닌 $\frac{block\_timestamp - parent\_timestamp}{10}$을 주요 입력 변수로 사용하는 것은 알고리즘의 대략적인 특성을 직접적으로 유지하는 역할을 합니다. + +이는 채굴자들이 약간 높은 난이도를 가진 블록을 생성하여 가능한 모든 포크를 확실히 이길 수 있도록 타임스탬프 차이를 정확히 $1$로 설정하는 과도한 유인을 방지합니다. + +$-99$의 상한은 두 블록이 시간상 매우 멀리 떨어져 있는 경우 난이도가 크게 떨어지지 않도록 하는 역할을 합니다. + +#### Code +Homestead + +```go +func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki + // algorithm: + // diff = (parent_diff + + // (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) + // ) + 2^(periodCount - 2) + + bigTime := new(big.Int).SetUint64(time) + bigParentTime := new(big.Int).SetUint64(parentTime) + + // holds intermediate values to make the algo easier to read & audit + x := new(big.Int) + y := new(big.Int) + + // 1 - (block_timestamp -parent_timestamp) // 10 + x.Sub(bigTime, bigParentTime) + x.Div(x, big10) + x.Sub(common.Big1, x) + + // max(1 - (block_timestamp - parent_timestamp) // 10, -99))) + if x.Cmp(bigMinus99) < 0 { + x.Set(bigMinus99) + } + + // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) + y.Div(parentDiff, params.DifficultyBoundDivisor) + x.Mul(y, x) + x.Add(parentDiff, x) + + // minimum difficulty can ever be (before exponential factor) + if x.Cmp(params.MinimumDifficulty) < 0 { + x = params.MinimumDifficulty + } + + // for the exponential factor + periodCount := new(big.Int).Add(parentNumber, common.Big1) + periodCount.Div(periodCount, ExpDiffPeriod) + + // the exponential factor, commonly refered to as "the bomb" + // diff = diff + 2^(periodCount - 2) + if periodCount.Cmp(common.Big1) > 0 { + y.Sub(periodCount, common.Big2) + y.Exp(common.Big2, y, nil) + x.Add(x, y) + } + + return x +} +``` + +Frontier + +```go +func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { + diff := new(big.Int) + adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor) + bigTime := new(big.Int) + bigParentTime := new(big.Int) + + bigTime.SetUint64(time) + bigParentTime.SetUint64(parentTime) + + if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 { + diff.Add(parentDiff, adjust) + } else { + diff.Sub(parentDiff, adjust) + } + if diff.Cmp(params.MinimumDifficulty) < 0 { + diff = params.MinimumDifficulty + } + + periodCount := new(big.Int).Add(parentNumber, common.Big1) + periodCount.Div(periodCount, ExpDiffPeriod) + if periodCount.Cmp(common.Big1) > 0 { + // diff = diff + 2^(periodCount - 2) + expDiff := periodCount.Sub(periodCount, common.Big2) + expDiff.Exp(common.Big2, expDiff, nil) + diff.Add(diff, expDiff) + diff = common.BigMax(diff, params.MinimumDifficulty) + } + + return diff +} +``` + +Reference + +https://eips.ethereum.org/EIPS/eip-2 + +https://medium.com/coinmonks/learn-solidity-lesson-37-creating-and-destroying-contracts-6921ae32413a + +https://github.com/ethereum/go-ethereum/compare/v1.3.3...v1.3.