From ae9eae457cd32f749f2738ff2efc149260c7e122 Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Sun, 31 Mar 2024 22:54:33 +0900 Subject: [PATCH 01/23] Orakle: open-source EIP team --- README.md | 345 +----------------------------------------------------- 1 file changed, 2 insertions(+), 343 deletions(-) diff --git a/README.md b/README.md index 0d5b7872124a..011edc5873f8 100644 --- a/README.md +++ b/README.md @@ -2,350 +2,9 @@ Golang execution layer implementation of the Ethereum protocol. -[![API Reference]( -https://pkg.go.dev/badge/github.com/ethereum/go-ethereum -)](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc) -[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum) -[![Travis](https://app.travis-ci.com/ethereum/go-ethereum.svg?branch=master)](https://app.travis-ci.com/github/ethereum/go-ethereum) -[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/nthXNEv) +## Orakle -Automated builds are available for stable releases and the unstable master branch. Binary -archives are published at https://geth.ethereum.org/downloads/. - -## Building the source - -For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). - -Building `geth` requires both a Go (version 1.21 or later) and a C compiler. You can install -them using your favourite package manager. Once the dependencies are installed, run - -```shell -make geth -``` - -or, to build the full suite of utilities: - -```shell -make all -``` - -## Executables - -The go-ethereum project comes with several wrappers/executables found in the `cmd` -directory. - -| Command | Description | -| :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/fundamentals/command-line-options) for command line options. | -| `clef` | Stand-alone signing tool, which can be used as a backend signer for `geth`. | -| `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. | -| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings) page for details. | -| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | -| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | -| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | - -## Running `geth` - -Going through all the possible command line flags is out of scope here (please consult our -[CLI Wiki page](https://geth.ethereum.org/docs/fundamentals/command-line-options)), -but we've enumerated a few common parameter combos to get you up to speed quickly -on how you can run your own `geth` instance. - -### Hardware Requirements - -Minimum: - -* CPU with 2+ cores -* 4GB RAM -* 1TB free storage space to sync the Mainnet -* 8 MBit/sec download Internet service - -Recommended: - -* Fast CPU with 4+ cores -* 16GB+ RAM -* High-performance SSD with at least 1TB of free space -* 25+ MBit/sec download Internet service - -### Full node on the main Ethereum network - -By far the most common scenario is people wanting to simply interact with the Ethereum -network: create accounts; transfer funds; deploy and interact with contracts. For this -particular use case, the user doesn't care about years-old historical data, so we can -sync quickly to the current state of the network. To do so: - -```shell -$ geth console -``` - -This command will: - * Start `geth` in snap sync mode (default, can be changed with the `--syncmode` flag), - causing it to download more data in exchange for avoiding processing the entire history - of the Ethereum network, which is very CPU intensive. - * Start the built-in interactive [JavaScript console](https://geth.ethereum.org/docs/interacting-with-geth/javascript-console), - (via the trailing `console` subcommand) through which you can interact using [`web3` methods](https://github.com/ChainSafe/web3.js/blob/0.20.7/DOCUMENTATION.md) - (note: the `web3` version bundled within `geth` is very old, and not up to date with official docs), - as well as `geth`'s own [management APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc). - This tool is optional and if you leave it out you can always attach it to an already running - `geth` instance with `geth attach`. - -### A Full node on the Görli test network - -Transitioning towards developers, if you'd like to play around with creating Ethereum -contracts, you almost certainly would like to do that without any real money involved until -you get the hang of the entire system. In other words, instead of attaching to the main -network, you want to join the **test** network with your node, which is fully equivalent to -the main network, but with play-Ether only. - -```shell -$ geth --goerli console -``` - -The `console` subcommand has the same meaning as above and is equally -useful on the testnet too. - -Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a bit: - - * Instead of connecting to the main Ethereum network, the client will connect to the Görli - test network, which uses different P2P bootnodes, different network IDs and genesis - states. - * Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth` - will nest itself one level deeper into a `goerli` subfolder (`~/.ethereum/goerli` on - Linux). Note, on OSX and Linux this also means that attaching to a running testnet node - requires the use of a custom endpoint since `geth attach` will try to attach to a - production node endpoint by default, e.g., - `geth attach /goerli/geth.ipc`. Windows users are not affected by - this. - -*Note: Although some internal protective measures prevent transactions from -crossing over between the main network and test network, you should always -use separate accounts for play and real money. Unless you manually move -accounts, `geth` will by default correctly separate the two networks and will not make any -accounts available between them.* - -### Configuration - -As an alternative to passing the numerous flags to the `geth` binary, you can also pass a -configuration file via: - -```shell -$ geth --config /path/to/your_config.toml -``` - -To get an idea of how the file should look like you can use the `dumpconfig` subcommand to -export your existing configuration: - -```shell -$ geth --your-favourite-flags dumpconfig -``` - -*Note: This works only with `geth` v1.6.0 and above.* - -#### Docker quick start - -One of the quickest ways to get Ethereum up and running on your machine is by using -Docker: - -```shell -docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \ - -p 8545:8545 -p 30303:30303 \ - ethereum/client-go -``` - -This will start `geth` in snap-sync mode with a DB memory allowance of 1GB, as the -above command does. It will also create a persistent volume in your home directory for -saving your blockchain as well as map the default ports. There is also an `alpine` tag -available for a slim version of the image. - -Do not forget `--http.addr 0.0.0.0`, if you want to access RPC from other containers -and/or hosts. By default, `geth` binds to the local interface and RPC endpoints are not -accessible from the outside. - -### Programmatically interfacing `geth` nodes - -As a developer, sooner rather than later you'll want to start interacting with `geth` and the -Ethereum network via your own programs and not manually through the console. To aid -this, `geth` has built-in support for a JSON-RPC based APIs ([standard APIs](https://ethereum.github.io/execution-apis/api-documentation/) -and [`geth` specific APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc)). -These can be exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based -platforms, and named pipes on Windows). - -The IPC interface is enabled by default and exposes all the APIs supported by `geth`, -whereas the HTTP and WS interfaces need to manually be enabled and only expose a -subset of APIs due to security reasons. These can be turned on/off and configured as -you'd expect. - -HTTP based JSON-RPC API options: - - * `--http` Enable the HTTP-RPC server - * `--http.addr` HTTP-RPC server listening interface (default: `localhost`) - * `--http.port` HTTP-RPC server listening port (default: `8545`) - * `--http.api` API's offered over the HTTP-RPC interface (default: `eth,net,web3`) - * `--http.corsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced) - * `--ws` Enable the WS-RPC server - * `--ws.addr` WS-RPC server listening interface (default: `localhost`) - * `--ws.port` WS-RPC server listening port (default: `8546`) - * `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`) - * `--ws.origins` Origins from which to accept WebSocket requests - * `--ipcdisable` Disable the IPC-RPC server - * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,txpool,web3`) - * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) - -You'll need to use your own programming environments' capabilities (libraries, tools, etc) to -connect via HTTP, WS or IPC to a `geth` node configured with the above flags and you'll -need to speak [JSON-RPC](https://www.jsonrpc.org/specification) on all transports. You -can reuse the same connection for multiple requests! - -**Note: Please understand the security implications of opening up an HTTP/WS based -transport before doing so! Hackers on the internet are actively trying to subvert -Ethereum nodes with exposed APIs! Further, all browser tabs can access locally -running web servers, so malicious web pages could try to subvert locally available -APIs!** - -### Operating a private network - -Maintaining your own private network is more involved as a lot of configurations taken for -granted in the official networks need to be manually set up. - -#### Defining the private genesis state - -First, you'll need to create the genesis state of your networks, which all nodes need to be -aware of and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`): - -```json -{ - "config": { - "chainId": , - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0 - }, - "alloc": {}, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x20000", - "extraData": "", - "gasLimit": "0x2fefd8", - "nonce": "0x0000000000000042", - "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x00" -} -``` - -The above fields should be fine for most purposes, although we'd recommend changing -the `nonce` to some random value so you prevent unknown remote nodes from being able -to connect to you. If you'd like to pre-fund some accounts for easier testing, create -the accounts and populate the `alloc` field with their addresses. - -```json -"alloc": { - "0x0000000000000000000000000000000000000001": { - "balance": "111111111" - }, - "0x0000000000000000000000000000000000000002": { - "balance": "222222222" - } -} -``` - -With the genesis state defined in the above JSON file, you'll need to initialize **every** -`geth` node with it prior to starting it up to ensure all blockchain parameters are correctly -set: - -```shell -$ geth init path/to/genesis.json -``` - -#### Creating the rendezvous point - -With all nodes that you want to run initialized to the desired genesis state, you'll need to -start a bootstrap node that others can use to find each other in your network and/or over -the internet. The clean way is to configure and run a dedicated bootnode: - -```shell -$ bootnode --genkey=boot.key -$ bootnode --nodekey=boot.key -``` - -With the bootnode online, it will display an [`enode` URL](https://ethereum.org/en/developers/docs/networking-layer/network-addresses/#enode) -that other nodes can use to connect to it and exchange peer information. Make sure to -replace the displayed IP address information (most probably `[::]`) with your externally -accessible IP to get the actual `enode` URL. - -*Note: You could also use a full-fledged `geth` node as a bootnode, but it's the less -recommended way.* - -#### Starting up your member nodes - -With the bootnode operational and externally reachable (you can try -`telnet ` to ensure it's indeed reachable), start every subsequent `geth` -node pointed to the bootnode for peer discovery via the `--bootnodes` flag. It will -probably also be desirable to keep the data directory of your private network separated, so -do also specify a custom `--datadir` flag. - -```shell -$ geth --datadir=path/to/custom/data/folder --bootnodes= -``` - -*Note: Since your network will be completely cut off from the main and test networks, you'll -also need to configure a miner to process transactions and create new blocks for you.* - -#### Running a private miner - - -In a private network setting a single CPU miner instance is more than enough for -practical purposes as it can produce a stable stream of blocks at the correct intervals -without needing heavy resources (consider running on a single thread, no need for multiple -ones either). To start a `geth` instance for mining, run it with all your usual flags, extended -by: - -```shell -$ geth --mine --miner.threads=1 --miner.etherbase=0x0000000000000000000000000000000000000000 -``` - -Which will start mining blocks and transactions on a single CPU thread, crediting all -proceedings to the account specified by `--miner.etherbase`. You can further tune the mining -by changing the default gas limit blocks converge to (`--miner.targetgaslimit`) and the price -transactions are accepted at (`--miner.gasprice`). - -## Contribution - -Thank you for considering helping out with the source code! We welcome contributions -from anyone on the internet, and are grateful for even the smallest of fixes! - -If you'd like to contribute to go-ethereum, please fork, fix, commit and send a pull request -for the maintainers to review and merge into the main code base. If you wish to submit -more complex changes though, please check up with the core devs first on [our Discord Server](https://discord.gg/invite/nthXNEv) -to ensure those changes are in line with the general philosophy of the project and/or get -some early feedback which can make both your efforts much lighter as well as our review -and merge procedures quick and simple. - -Please make sure your contributions adhere to our coding guidelines: - - * Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) - guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). - * Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) - guidelines. - * Pull requests need to be based on and opened against the `master` branch. - * Commit messages should be prefixed with the package(s) they modify. - * E.g. "eth, rpc: make trace configs optional" - -Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/geth-developer/dev-guide) -for more details on configuring your environment, managing project dependencies, and -testing procedures. - -### Contributing to geth.ethereum.org - -For contributions to the [go-ethereum website](https://geth.ethereum.org), please checkout and raise pull requests against the `website` branch. -For more detailed instructions please see the `website` branch [README](https://github.com/ethereum/go-ethereum/tree/website#readme) or the -[contributing](https://geth.ethereum.org/docs/developers/geth-developer/contributing) page of the website. +Orakle open-source EIP team repository. ## License From 409be2442a5b6e97a7a545c189a3620f4fb04ba4 Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Sun, 31 Mar 2024 22:55:48 +0900 Subject: [PATCH 02/23] consensus/misc: eip-1559 comment --- consensus/misc/eip1559/eip1559.go | 12 +++++++++++- consensus/misc/gaslimit.go | 2 ++ params/config.go | 7 +++++++ params/protocol_params.go | 8 +++++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/consensus/misc/eip1559/eip1559.go b/consensus/misc/eip1559/eip1559.go index 84b82c4c492e..1bb093aa07fc 100644 --- a/consensus/misc/eip1559/eip1559.go +++ b/consensus/misc/eip1559/eip1559.go @@ -31,8 +31,10 @@ import ( // 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() @@ -41,10 +43,12 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade 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", @@ -54,14 +58,18 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade } // 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를 반환한다. + // -----런던인지 검사하는데 첫번째 블록과 어떤 관련성 있는지? 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) } @@ -74,6 +82,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *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)) @@ -84,12 +93,13 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { } 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) } } diff --git a/consensus/misc/gaslimit.go b/consensus/misc/gaslimit.go index dfcabd9a802c..501479edaa1c 100644 --- a/consensus/misc/gaslimit.go +++ b/consensus/misc/gaslimit.go @@ -24,8 +24,10 @@ import ( // VerifyGaslimit verifies the header gas limit according increase/decrease // in relation to the parent gas limit. +// VerifyGaslimit은 header gas limit관 parentgas limit의 증가/감소관계를 확인한다. func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error { // Verify that the gas limit remains within allowed bounds + // gas limit이 허용된 범위안에 있는지 확인한다 diff := int64(parentGasLimit) - int64(headerGasLimit) if diff < 0 { diff *= -1 diff --git a/params/config.go b/params/config.go index 439e88218924..7683b147e271 100644 --- a/params/config.go +++ b/params/config.go @@ -319,12 +319,16 @@ var NetworkNames = map[string]string{ } // ChainConfig is the core config which determines the blockchain settings. +// ChainConfig는 블록체인 설정을 결정하는 핵심 config이다. // // ChainConfig is stored in the database on a per block basis. This means // that any network, identified by its genesis block, can have its own // set of configuration options. +// ChainConfig는 블록 단위로 데이터베이스에 저장된다. +// 이는 제네시스 블록에 의해 구별되는 모든 네트워크는 고유의 configuration option set를 가질 수 있음을 의미한다. type ChainConfig struct { ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection + // chainId는 현재 체인을 식별하고 replay attack의 protection에 사용된다 HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) @@ -539,6 +543,7 @@ func (c *ChainConfig) IsBerlin(num *big.Int) bool { } // IsLondon returns whether num is either equal to the London fork block or greater. +// IsLondon는 num이 London fork block보다 크거나 같은지 여부를 반환한다. func (c *ChainConfig) IsLondon(num *big.Int) bool { return isBlockForked(c.LondonBlock, num) } @@ -746,11 +751,13 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, } // BaseFeeChangeDenominator bounds the amount the base fee can change between blocks. +// BaseFeeChangeDenominator는 블록간 base fee가 변할 수 있는 양을 제한한다. func (c *ChainConfig) BaseFeeChangeDenominator() uint64 { return DefaultBaseFeeChangeDenominator } // ElasticityMultiplier bounds the maximum gas limit an EIP-1559 block may have. +// ElasticityMultiplier는 EIP-1559 블록이 가지는 최대 gas limit을 제한한다 func (c *ChainConfig) ElasticityMultiplier() uint64 { return DefaultElasticityMultiplier } diff --git a/params/protocol_params.go b/params/protocol_params.go index 4e01b80970f1..d45af37433eb 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -124,9 +124,11 @@ const ( // Introduced in Tangerine Whistle (Eip 150) CreateBySelfdestructGas uint64 = 25000 - DefaultBaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. - DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. - InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. + DefaultBaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. + // 블록 간 변화하는 base fee 양 제한 + DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. + // EIP-1559블록의 최대 gas limit 범위 + InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. MaxCodeSize = 24576 // Maximum bytecode to permit for a contract MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions From 93418502a48e777b79b474c124ffc434c1054c9a Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Mon, 1 Apr 2024 14:45:41 +0900 Subject: [PATCH 03/23] consensus/misc: eip-4844 comment --- consensus/misc/eip4844/eip4844.go | 17 +++++++++++++++++ core/types/block.go | 2 ++ params/protocol_params.go | 23 ++++++++++++++++------- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 2dad9a0cd3de..8fc6f7cb60d1 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -33,8 +33,11 @@ var ( // VerifyEIP4844Header verifies the presence of the excessBlobGas field and that // if the current block contains no transactions, the excessBlobGas is updated // accordingly. +// VerifyEIP4844Header는 excessBlobGas, BlobGasUsed 필드의 존재 등을 검증하고, +// 현재 블록이 트랜잭션을 담고 있지 않으면, 그에따라 excessBlobGas가 업데이트한다. func VerifyEIP4844Header(parent, header *types.Header) error { // Verify the header is not malformed + // 헤더의 형식 검증 if header.ExcessBlobGas == nil { return errors.New("header is missing excessBlobGas") } @@ -42,6 +45,7 @@ func VerifyEIP4844Header(parent, header *types.Header) error { return errors.New("header is missing blobGasUsed") } // Verify that the blob gas used remains within reasonable limits. + // 사용된 blob gas가 합리적인 한도 내에 있는지 검증한다. if *header.BlobGasUsed > params.MaxBlobGasPerBlock { return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, params.MaxBlobGasPerBlock) } @@ -49,6 +53,7 @@ func VerifyEIP4844Header(parent, header *types.Header) error { return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) } // Verify the excessBlobGas is correct based on the parent header + // excessBlobGas가 parent header를 기준으로 올바른지 확인한다. var ( parentExcessBlobGas uint64 parentBlobGasUsed uint64 @@ -67,25 +72,32 @@ func VerifyEIP4844Header(parent, header *types.Header) error { // CalcExcessBlobGas calculates the excess blob gas after applying the set of // blobs on top of the excess blob gas. +// CalcExcessBlobGas는 excess blob gas위에 blob set을 적용한 이후, excess blob gas를 계산한다. func CalcExcessBlobGas(parentExcessBlobGas uint64, parentBlobGasUsed uint64) uint64 { excessBlobGas := parentExcessBlobGas + parentBlobGasUsed + // 목표치 이하로 사용했으므로 excess blob gas = 0 if excessBlobGas < params.BlobTxTargetBlobGasPerBlock { return 0 } + // excessBlobGas = (parentExcessBlobGas + parentBlobGasUsed) - BlobTxTargetBlobGasPerBlock return excessBlobGas - params.BlobTxTargetBlobGasPerBlock } // CalcBlobFee calculates the blobfee from the header's excess blob gas field. +// CalcBlobFee는 header의 excess blob gase field로 blobfee를 계산한다. func CalcBlobFee(excessBlobGas uint64) *big.Int { return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(excessBlobGas), blobGaspriceUpdateFraction) } // fakeExponential approximates factor * e ** (numerator / denominator) using // Taylor expansion. +// 테일러 급수 전개로 근사적으로 계산 +// e^x = 1 + x + x^2/2! + x^3/3! + ... func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { var ( output = new(big.Int) accum = new(big.Int).Mul(factor, denominator) + // ------ accoum = new(big.Int).Set(factor) ) for i := 1; accum.Sign() > 0; i++ { output.Add(output, accum) @@ -95,4 +107,9 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { accum.Div(accum, big.NewInt(int64(i))) } return output.Div(output, denominator) + // ------ return output + // 왜 굳이 마지막에 output을 denominator로 나누는거지? + // 내 생각엔 함수의 시작에서 accum을 정의할때 factor와 denominator의 곱을 저장하기 때문에 + // denominator로 나누어준 거 같은데 그냥 처음부터 accum을 factor로 정의해서 + // denominator를 곱하고 나누는 연산과정을 생략할 수 있지 않나? } diff --git a/core/types/block.go b/core/types/block.go index 1a357baa3a41..14c1bea48c73 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -86,9 +86,11 @@ type Header struct { WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` // BlobGasUsed was added by EIP-4844 and is ignored in legacy headers. + // BlobGasUsed는 EIP-4844에 추가되고, legacy headers에서는 무시된다. BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"` // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. + // ExcessBlobGas는 EIP-4844에 추가되고, legacy headers에서는 무시된다. ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. diff --git a/params/protocol_params.go b/params/protocol_params.go index d45af37433eb..32ce83f255ed 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -166,15 +166,24 @@ const ( RefundQuotient uint64 = 2 RefundQuotientEIP3529 uint64 = 5 - BlobTxBytesPerFieldElement = 32 // Size in bytes of a field element - BlobTxFieldElementsPerBlob = 4096 // Number of field elements stored in a single data blob - BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size) - BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs - BlobTxBlobGaspriceUpdateFraction = 3338477 // Controls the maximum rate of change for blob gas price - BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile. + BlobTxBytesPerFieldElement = 32 // Size in bytes of a field element + BlobTxFieldElementsPerBlob = 4096 // Number of field elements stored in a single data blob + BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size) + // 한 data blob당 가스 소모량(blob의 byte size) + + BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs + // data blobs의 최소 gas price + + BlobTxBlobGaspriceUpdateFraction = 3338477 // Controls the maximum rate of change for blob gas price + // blob gas price의 최대 변동 폭 제어 + + BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile. BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing) - MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block + // 블록당 data blobs에 소비될 수 있는 목표 blob gas + + MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block + // 블록당 data blobs에 소비될 수 있는 최대 blob gas ) // Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations From 1b139eb53ad64d1b1a7865516baef9bc8479726f Mon Sep 17 00:00:00 2001 From: c0np4nn4 Date: Tue, 2 Apr 2024 03:08:29 +0900 Subject: [PATCH 04/23] consensus/misc/dao.go: eip-779 comment --- cmd/evm/internal/t8ntool/execution.go | 2 + consensus/misc/dao.go | 11 +++++ core/chain_makers.go | 2 + core/state_processor.go | 2 + core/tracing/hooks.go | 2 + params/config.go | 64 ++++++++++++++++++--------- params/dao.go | 7 +++ tests/difficulty_test.go | 4 +- 8 files changed, 73 insertions(+), 21 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 3c09229e1c5c..a3eba92d2249 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -187,6 +187,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's // done in StateProcessor.Process(block, ...), right before transactions are applied. + // EIP-779, DAO fork 가 지원되고 ChainConfig에 명시된 블록 넘버가 현재 블록 넘버와 동일하다면 + // DAO fork 를 DB 에 적용합니다. if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 { diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index 45669d0bcec8..f6d6ed1a0bbf 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -47,6 +47,10 @@ var ( // with the fork specific extra-data set. // - if the node is pro-fork, require blocks in the specific range to have the // unique extra-data set. +// +// 블록헤더의 extra-data field 를 검증하여 DAO fork 규칙을 만족하는지 검사하는 함수입니다. +// 만약 현재 node 가 `no-fork` 라면, [fork, fork+10) 범위의 블록을 accept 하지 않습니다. +// 만약 현재 node 가 `pro-fork` 라면, 특정 범위의 블록들이 고유한 `extra-data set`을 갖는 것이 필요합니다. func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error { // Short circuit validation if the node doesn't care about the DAO fork if config.DAOForkBlock == nil { @@ -74,13 +78,20 @@ func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) // ApplyDAOHardFork modifies the state database according to the DAO hard-fork // rules, transferring all balances of a set of DAO accounts to a single refund // contract. +// +// EIP-779, TheDAO hard-fork 에 따라 DB의 상태를 변경하는 함수입니다. +// EIP-779에서도 설명하듯이 DAODrainList 의 계정들로부터 하나의 DAORefundContract 에 +// 돈을 전송하게 됩니다. func ApplyDAOHardFork(statedb *state.StateDB) { // Retrieve the contract to refund balances into + // EIP-779, 돈을 받을 계정이 존재하지 않는다면 새로 하나 생성합니다. + // 참고로, 계정주소는 "common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d20bca754")" 입니다. if !statedb.Exist(params.DAORefundContract) { statedb.CreateAccount(params.DAORefundContract) } // Move every DAO account and extra-balance account funds into the refund contract + // 모든 `DAODrainList` 의 계정으로부터 `refund contract`에 돈을 보냅니다. for _, addr := range params.DAODrainList() { statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), tracing.BalanceIncreaseDaoContract) statedb.SetBalance(addr, new(uint256.Int), tracing.BalanceDecreaseDaoAccount) diff --git a/core/chain_makers.go b/core/chain_makers.go index 13d7cb86c043..47f5000811e2 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -338,6 +338,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } } } + // EIP-779, DAO fork 를 지원하고 Chain Config에 DAO fork 블록 넘버가 현재 블록 넘버와 동일하다면 + // TheDAO hard-fork 를 적용합니다. if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 { misc.ApplyDAOHardFork(statedb) } diff --git a/core/state_processor.go b/core/state_processor.go index b1a8938f677a..be67b4b982ac 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -69,6 +69,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ) // Mutate the block and state according to any hard-fork specs + // EIP-779, DAO fork 를 지원하고 Chain Config에 DAO fork 블록 넘버가 현재 블록 넘버와 동일하다면 + // TheDAO hard-fork 를 적용합니다. if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 48cb4d20275c..dd8cad046e56 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -193,8 +193,10 @@ const ( // DAO fork // BalanceIncreaseDaoContract is ether sent to the DAO refund contract. + // EIP-779, DAO fork 를 위해 DAO refund contract에 전송되는 `ether` 를 의미합니다. BalanceIncreaseDaoContract BalanceChangeReason = 8 // BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract. + // EIP-779, DAO fork 를 위해 DAO Drain List의 account 들로부터 가져온 `ether`를 의미합니다. BalanceDecreaseDaoAccount BalanceChangeReason = 9 // BalanceChangeTransfer is ether transferred via a call. diff --git a/params/config.go b/params/config.go index 7683b147e271..14f86321eb7c 100644 --- a/params/config.go +++ b/params/config.go @@ -39,8 +39,9 @@ var ( // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(1_150_000), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(1_150_000), + // EIP-779, TheDAO hard-fork 가 적용되는 블록이 1,920,000 임을 명시합니다. DAOForkBlock: big.NewInt(1_920_000), DAOForkSupport: true, EIP150Block: big.NewInt(2_463_000), @@ -63,8 +64,9 @@ var ( } // HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network. HoleskyChainConfig = &ChainConfig{ - ChainID: big.NewInt(17000), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(17000), + HomesteadBlock: big.NewInt(0), + // EIP-779, Holesky test network 상에서는 TheDAO hard-fork 가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: true, EIP150Block: big.NewInt(0), @@ -88,8 +90,9 @@ var ( } // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. SepoliaChainConfig = &ChainConfig{ - ChainID: big.NewInt(11155111), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(11155111), + HomesteadBlock: big.NewInt(0), + // EIP-779, Sepolia test network 상에서는 TheDAO hard-fork 가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: true, EIP150Block: big.NewInt(0), @@ -113,8 +116,9 @@ var ( } // GoerliChainConfig contains the chain parameters to run a node on the Görli test network. GoerliChainConfig = &ChainConfig{ - ChainID: big.NewInt(5), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(5), + HomesteadBlock: big.NewInt(0), + // EIP-779, Goerli test network 상에서는 TheDAO hard-fork 가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: true, EIP150Block: big.NewInt(0), @@ -140,8 +144,9 @@ var ( // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. AllEthashProtocolChanges = &ChainConfig{ - ChainID: big.NewInt(1337), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + // EIP-779, TheDAO hard-fork 가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), @@ -191,8 +196,9 @@ var ( // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. AllCliqueProtocolChanges = &ChainConfig{ - ChainID: big.NewInt(1337), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + // EIP-779, AllCliqueProtocolChanges 에서는 TheDAO hard-fork 가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), @@ -221,8 +227,9 @@ var ( // TestChainConfig contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers for testing purposes. TestChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + // EIP-779, TestChainConfig 에서는 TheDAO hard-fork 가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), @@ -251,8 +258,9 @@ var ( // MergedTestChainConfig contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers for testing purposes. MergedTestChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + // EIP-779, MergedTestChainConfig 에서는 TheDAO hard-fork 가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), @@ -281,8 +289,9 @@ var ( // NonActivatedConfig defines the chain configuration without activating // any protocol change (EIPs). NonActivatedConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: nil, + ChainID: big.NewInt(1), + HomesteadBlock: nil, + // EIP-779, NonActivatedConfig 에서는 TheDAO hard-fork가 적용되지 않습니다. DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: nil, @@ -332,8 +341,10 @@ type ChainConfig struct { HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) - DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) - DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork + // EIP-779 에 따라, TheDAO hard-fork 가 적용되는 블록 넘버를 명시합니다. + DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) + // EIP-779 에 따라, 현재 노드가 TheDAO hard-fork 를 지원하는지 여부를 명시합니다. + DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) @@ -393,6 +404,7 @@ func (c *CliqueConfig) String() string { return "clique" } +// Chain 설정에 대해 사람이 읽을 수 있는 형태의 Description 을 반환하는 함수 // Description returns a human-readable description of ChainConfig. func (c *ChainConfig) Description() string { var banner string @@ -428,8 +440,11 @@ func (c *ChainConfig) Description() string { // Create a list of forks with a short description of them. Forks that only // makes sense for mainnet should be optional at printing to avoid bloating // the output for testnets and private networks. + // FORK 들에 대한 짧은 기술을 담은 리스트를 생성합니다. + // mainnet 에만 해당하는 FORK 들은 '선택'으로 두어서 testnet 과 private networks 에 대한 결과물이 부풀어 오르지 않도록 해야합니다. banner += "Pre-Merge hard forks (block based):\n" banner += fmt.Sprintf(" - Homestead: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md)\n", c.HomesteadBlock) + // DAOForkBlock 이 설정되어 있으면, TheDAO hard-fork 에 대한 FORK 정보를 추가합니다. if c.DAOForkBlock != nil { banner += fmt.Sprintf(" - DAO Fork: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/dao-fork.md)\n", c.DAOForkBlock) } @@ -491,6 +506,8 @@ func (c *ChainConfig) IsHomestead(num *big.Int) bool { } // IsDAOFork returns whether num is either equal to the DAO fork block or greater. +// +// 인자로 받은 수 `num` 이 TheDAO fork 를 위한 블록 넘버보다 크거나 같은지 함수입니다. func (c *ChainConfig) IsDAOFork(num *big.Int) bool { return isBlockForked(c.DAOForkBlock, num) } @@ -613,6 +630,8 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time u // CheckConfigForkOrder checks that we don't "skip" any forks, geth isn't pluggable enough // to guarantee that forks can be implemented in a different order than on official networks +// CheckConfigForkOrder는 포크를 "건너뛰지" 않았는지 확인합니다. +// geth는 공식 네트워크와 다른 순서로 포크를 구현할 수 있도록 보장할 수 있을 만큼 충분히 플러그 가능하지 않습니다. func (c *ChainConfig) CheckConfigForkOrder() error { type fork struct { name string @@ -623,6 +642,8 @@ func (c *ChainConfig) CheckConfigForkOrder() error { var lastFork fork for _, cur := range []fork{ {name: "homesteadBlock", block: c.HomesteadBlock}, + // 현재 ChainConfig 에 명시된 TheDAO hard-fork 블록 넘버를 활용합니다. + // optional 값이 설정되어있기 때문에, 해당 fork 를 적용하지 않을 수도 있습니다. {name: "daoForkBlock", block: c.DAOForkBlock, optional: true}, {name: "eip150Block", block: c.EIP150Block}, {name: "eip155Block", block: c.EIP155Block}, @@ -683,9 +704,12 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkBlockIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, headNumber) { return newBlockCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) } + // 현재의 Chain 설정 `c` 와 새로운 설정 `newcfg` 가 호환되는지 검사합니다. + // `headNumber`는 현재 블록 넘버를 의미합니다. if isForkBlockIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, headNumber) { return newBlockCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock) } + // EIP-779 를 지원하는지 검사합니다. if c.IsDAOFork(headNumber) && c.DAOForkSupport != newcfg.DAOForkSupport { return newBlockCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock) } diff --git a/params/dao.go b/params/dao.go index da3c8dfc992b..709b4cf455ca 100644 --- a/params/dao.go +++ b/params/dao.go @@ -25,17 +25,24 @@ import ( // DAOForkBlockExtra is the block header extra-data field to set for the DAO fork // point and a number of consecutive blocks to allow fast/light syncers to correctly // pick the side they want ("dao-hard-fork"). +// EIP-779, DAO hard-fork 지점 이후 및 추가로 연속되는 블록들의 `extra-data` 필드에 +// "dao-hard-fork" 를 16진수 형태로 변환하여 기록합니다. +// 이를 통해, 빠른 동기화나 경량 클라이언트 같은 동기화 메커니즘들이 올바른 체인을 선택하도록 돕습니다. var DAOForkBlockExtra = common.FromHex("0x64616f2d686172642d666f726b") // DAOForkExtraRange is the number of consecutive blocks from the DAO fork point // to override the extra-data in to prevent no-fork attacks. +// EIP-779, `no-fork attack` 으로부터 체인을 보호하기 위해 얼마나 많은 +// DAO fork 지점 이후 연속되는 블록의 `extra-data`에 덮어쓰기를 할 것인지 명시합니다. var DAOForkExtraRange = big.NewInt(10) // DAORefundContract is the address of the refund contract to send DAO balances to. +// EIP-779, 환불(refund)을 위해 사용할 refund contract 의 주소를 명시합니다. var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d20bca754") // DAODrainList is the list of accounts whose full balances will be moved into a // refund contract at the beginning of the dao-fork block. +// EIP-779, 돈을 회수할 계정을 명시합니다. func DAODrainList() []common.Address { return []common.Address{ common.HexToAddress("0xd4fe7bc31cedb7bfb8a345f31e668033056b2728"), diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index 03e14df7c4df..74883b8543c0 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -27,7 +27,9 @@ var ( mainnetChainConfig = params.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(1150000), - DAOForkBlock: big.NewInt(1920000), + // EIP-779, mainnet에서 TheDAO hard fork가 블록 1,920,000에서 발생했음을 보여줌 + DAOForkBlock: big.NewInt(1920000), + // EIP-779, TheDAO hard fork 적용 여부를 나타냄 DAOForkSupport: true, EIP150Block: big.NewInt(2463000), EIP155Block: big.NewInt(2675000), From 44d5ea96727aef57bdf49dbf21d33e4471bb5a48 Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Thu, 4 Apr 2024 19:09:23 +0900 Subject: [PATCH 05/23] accounts/abi/bind: eip-1559 comment --- accounts/abi/bind/base.go | 15 ++++++++++++++- consensus/misc/eip1559/eip1559.go | 3 ++- consensus/misc/gaslimit.go | 2 +- core/types/transaction.go | 2 ++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index c8972a9dff2a..abed24586032 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -54,16 +54,20 @@ type CallOpts struct { // TransactOpts is the collection of authorization data required to create a // valid Ethereum transaction. +// TransactOpts는 유효한 이더리움 트랜잭션을 생성하기 위해 필요한 authorization data의 집합이다. type TransactOpts struct { From common.Address // Ethereum account to send the transaction from Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) Signer SignerFn // Method to use for signing the transaction (mandatory) + // 트랜잭션 사인에 사용하는 메소드 Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds) GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle) + // 1559 transaction을 실행하기 위해 필요한 최대 가스 한도 GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle) - GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) + // 1559 transaction을 실행하기 위해 필요한 최대 가스 팁 한도 + GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) @@ -112,6 +116,9 @@ func (m *MetaData) GetAbi() (*abi.ABI, error) { // BoundContract is the base wrapper object that reflects a contract on the // Ethereum network. It contains a collection of methods that are used by the // higher level contract bindings to operate. +// BoundContract는 이더리움 네트워크에 컨트랙트를 반영시키는 wrapper 객체입니다. +// 이는 상위레벨의 컨트랙트가 실행될 수 있도록 연결하는데 사용되는 메소드의 집합을 포함합니다. +// 쉽게 생각하면 smart contract <=> 이더리움 간의 호환을 위한 객체 type BoundContract struct { address common.Address // Deployment address of the contract on the Ethereum blockchain abi abi.ABI // Reflect based ABI to access the correct Ethereum methods @@ -385,8 +392,10 @@ func (c *BoundContract) getNonce(opts *TransactOpts) (uint64, error) { // transact executes an actual transaction invocation, first deriving any missing // authorization fields, and then scheduling the transaction for execution. +// transact는 실제 트랜잭션 호출을 실행하고, 먼저 누락된 authorization 필드를 도출한 다음 트랜잭션을 실행하도록 스케줄링합니다. func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { if opts.GasPrice != nil && (opts.GasFeeCap != nil || opts.GasTipCap != nil) { + // 트랜잭션은 GasPrice 혹은 (GasFeeCap or GasTipCap) 중 하나는 지정되어 있어야 합니다. return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } // Create the transaction @@ -395,11 +404,15 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i err error ) if opts.GasPrice != nil { + // GasPrice가 설정되어 있으면 legacy transaction 실행을 실행합니다. rawTx, err = c.createLegacyTx(opts, contract, input) } else if opts.GasFeeCap != nil && opts.GasTipCap != nil { + // GasFeeCap, GasTipCap 모두 설정되어 있으면 EIP-1559 transaction을 실행합니다. rawTx, err = c.createDynamicTx(opts, contract, input, nil) } else { // Only query for basefee if gasPrice not specified + // gasPrice가 지정되지 않으면 baseFee만 쿼리하고, baseFee 존재시 EIP-1559 transaction, 없으면 legacy transaction을 실행합니다. + // 사용자가 명시적으로 가스 관련한 field를 지정하지 않았을때 네트워크 config에 맞게 자동으로 트랜잭션 유형을 결정하기 위한 조건입니다. if head, errHead := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil); errHead != nil { return nil, errHead } else if head.BaseFee != nil { diff --git a/consensus/misc/eip1559/eip1559.go b/consensus/misc/eip1559/eip1559.go index 1bb093aa07fc..ba30cd9bd11a 100644 --- a/consensus/misc/eip1559/eip1559.go +++ b/consensus/misc/eip1559/eip1559.go @@ -62,7 +62,8 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade 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) } diff --git a/consensus/misc/gaslimit.go b/consensus/misc/gaslimit.go index 501479edaa1c..d954eb1bd0dc 100644 --- a/consensus/misc/gaslimit.go +++ b/consensus/misc/gaslimit.go @@ -24,7 +24,7 @@ import ( // VerifyGaslimit verifies the header gas limit according increase/decrease // in relation to the parent gas limit. -// VerifyGaslimit은 header gas limit관 parentgas limit의 증가/감소관계를 확인한다. +// VerifyGaslimit은 header gas limit과 parent gas limit의 증가/감소관계를 확인한다. func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error { // Verify that the gas limit remains within allowed bounds // gas limit이 허용된 범위안에 있는지 확인한다 diff --git a/core/types/transaction.go b/core/types/transaction.go index 7d2e9d5325a6..077161d8a5e8 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -52,9 +52,11 @@ const ( ) // Transaction is an Ethereum transaction. +// 이더리움의 트랜잭션 구조체 type Transaction struct { inner TxData // Consensus contents of a transaction time time.Time // Time first seen locally (spam avoidance) + //로컬 시간 사용 // caches hash atomic.Value From 6d81e2910105219718e4861ddd24fb6673985901 Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Thu, 4 Apr 2024 19:39:11 +0900 Subject: [PATCH 06/23] EIPs: add vision and schedule for opensource EIP contribution --- EIPs/README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 EIPs/README.md diff --git a/EIPs/README.md b/EIPs/README.md new file mode 100644 index 000000000000..de04471fb2a5 --- /dev/null +++ b/EIPs/README.md @@ -0,0 +1,54 @@ +# EIP Contribution Plan + +## VISION + +### Why Open-Source? +- Recognition from the global blockchain community +- Small but practical, core contributions +- Learn 24 standards and perform open-source contributions +- Top-notch experience and career in the industry + +## Schedule + +### Learning Period + +#### April 1 - April 14 (2 weeks) +- Each person to research 1 EIP + +#### April 15 - May 8 (2 weeks) +- Each person to research 2 EIPs + +*One week break for personal schedules, etc.* +*You have to notify a week in advance of your personal schedule break* + +#### Tasks +- Study EIP theory and code, write on Medium (in Korean/English) / Total of 6 EIP researches per person +- In addition to studying your own research, also familiarize yourself with the research done by other team members / Learn a total of 24 EIPs +- Update status on Telegram every Saturday by 12 pm +- Review status and receive feedback in Orakle online sessions +- If an EIP is too simple, it may be counted as 0.5 (personal judgement) + +### Topic Selection + +#### May 9 - May 16 (1 week) + +#### Task +- Select EIP contribution topic + +### Contribution Period + +#### May 16 - July 16 (7 weeks) + +#### Tasks +- Perform EIP contribution +- Write documentation (github/medium) + +*One week break for personal schedules, etc.* +*You have to notify a week in advance of your personal schedule break* + +#### July 16 - July 23 (1 week) + +#### Task +- Prepare for final presentation + +#### July 27 - Final Presentation \ No newline at end of file From 9b9ef6a52d79f2b62a46bbefe9fe10f3c15d48bd Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Thu, 4 Apr 2024 20:07:02 +0900 Subject: [PATCH 07/23] EIPs: add eip-1559.md --- EIPs/eip-1559.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 EIPs/eip-1559.md diff --git a/EIPs/eip-1559.md b/EIPs/eip-1559.md new file mode 100644 index 000000000000..b78c7ac4bfef --- /dev/null +++ b/EIPs/eip-1559.md @@ -0,0 +1,58 @@ +# EIP-1559: Fee market change for ETH 1.0 chain + + +## TL;DR +EIP-1559는 이더리움 네트워크에서 트랜잭션 수수료를 계산하는 새로운 방식입니다. 기존에는 사용자가 직접 수수료를 입찰하는 방식이었다면, EIP-1559에서는 기본 수수료는 네트워크 혼잡도에 따라 동적으로 조정되며, 소각(Burn)됩니다. 또한 블록 사이즈도 동적으로 확장 및 축소되어 네트워크 혼잡을 효과적으로 처리할 수 있습니다. +** EIP-1559에서 블록 사이즈는 블록의 데이터 크기가 아닌, 한 블록에 담기는 총 가스 수량을 의미합니다. + + +## Abstract +기본 수수료(Base Fee)는 이전 블록의 가스 사용량을 기반으로 계산됩니다. 이전 블록이 목표 가스 사용량보다 많은 가스를 사용했다면 기본 수수료가 상승하고, 그렇지 않다면 하락합니다. 이렇게 계산된 기본 수수료는 채굴자에게 지급되지 않고, 소각되어 영구적으로 제거됩니다. EIP-1559가 적용된 이후의 트랜잭션을 제출할 때 사용자는 최대 수수료(Maximum Fee)를 설정하는데, 최대 수수료는 기본 수수료와 우선순위 수수료(Priority Fee)의 합입니다. 우선순위 수수료는 마이너에게 지급되는 인센티브로, 이는 사용자가 직접 설정합니다. 실제 사용자가 지불하는 수수료는 baseFee와 PriorityFee의 합이며, 이 값은 최대 수수료를 초과할 수 없습니다. + +## Motivation +EIP-1559 이전의 이더리움은 자유경매 매커니즘으로 transactionFee를 결정했습니다. 사용자가 트랜잭션을 제출할 때 입찰가격(Gas Price)를 제시하면, 채굴자는 가장 높은 입찰 가격을 가진 트랜잭션을 선택하여 블록에 포함시켰습니다. 그러나 이런 기존 방식에는 몇가지 문제점이 있습니다. + +첫째, 트랜잭션 수수료 수준의 변동성과 트랜잭션의 실제 네트워크 비용이 일치하지 않습니다. +자유 경매 메커니즘으로 transactionFee가 결정되고, 블록이 가득 찰 정도로 충분히 사용되는 성숙한 블록체인에서, 이 체인에 트랜잭션을 포함시키려는 transactionFee의 입찰가는 예측하기 어렵고 변동성이 매우 큰 경향이 있습니다. 또한 실제 네트워크 비용이 수수료에 반영되지 않아 네트워크 과부하 조절 기능이 떨어졌습니다. 예를 들어 네트워크가 혼잡하지만 transactionFee가 낮아 오히려 네트워크를 더 혼잡하게 만들 수 있습니다. + +둘째, 최고 입찰가 트랜잭션만 선택되는 경매 방식은 비효율적이고 예측할 수 없으며, 복잡한 수수료 측정 메커니즘이 필요합니다. 사용자는 자신이 얼마나 수수료를 지불해야 네트워크에 자신의 트랜잭션을 포함시킬 수 있을지 예측할 수 없습니다. 따라서 종종 사용자의 트랜잭션은 너무 낮은 수수료를 제시하여 네트워크에 포함되지 못하거나, 혹은 너무 높은 수수료를 지불하였습니다. + +마지막으로 장기적으로 블록 보상이 없어지면, 트랜잭션 수수료만으로 채굴자에게 보상을 지급해야 하는데 이때 수수료를 훔치려는 공격(sister block, selfish mining) 등에 대한 유인이 높아질 수 있습니다. + +EIP-1559에서 제시된 fee 계산 메커니즘은 네트워크 혼잡도에 따라 baseFee를 동적으로 조절합니다. 또한 baseFee의 변동폭은 제한되어 있어 이전 블록을 참고하여 블록간 수수료의 최대 차이를 예측할 수 있습니다. 이를 통해 지갑 dApp들은 안정적인 방식으로 사용자의 가스요금을 자동으로 설정할 수 있고, 사용자는 자신의 트랜잭션을 포함시키기 위해 과도한 수수료를 지불하거나, 너무 낮은 fee를 제시하여 트랜잭션이 포함되지 못하는 상황을 피할 수 있습니다. +주목할 점은 계산된 기본 수수료는 항상 소각되고, 채굴자들은 PriorityFee만 받는 것입니다. 기본 수수료의 소각으로 이더리움의 인플레이션을 상쇄하는 동시에, 채굴자에게 블록보상과 PriorityFee를 제공할 수 있습니다. +채굴자가 사용자로부터 수수료를 추출하기 위해 체인을 조작할 유인을 제거하기 때문에 채굴자가 기본 수수료를 받지 않도록 하는 것은 매우 중요합니다. + +## BaseFee 계산 메커니즘 + +** EIP-1559에서 블록사이즈는 블록의 데이터크기가 아닌, 한 블록에 담기는 총 가스 수량을 의미합니다. + +EIP-1559에서는 이전 블록의 사이즈가 목표 블록 사이즈보다 크면 트랜잭션 수요를 줄여야 하므로 기본 수수료(Base Fee)를 증가시킵니다. 반대로 이전 블록 사이즈가 목표치보다 작으면 수요를 늘려야 하므로 기본 수수료를 감소시킵니다. + +이 때 현재 블록의 기본 수수료는 이전 블록 수수료의 12.5% 범위 내에서만 변화할 수 있습니다. 만약 기본 수수료가 0이 되면 사실상 기존의 자유 경매 시스템과 가격 측정 메커니즘과 동일해집니다. + +더 빨리 블록에 포함되길 원하는 트랜잭션은 채굴자에게 우선순위 수수료(Priority Fee)를 지불하여 우선순위를 높일 수 있습니다. + +사용자는 지불할 의사가 있는 최대 가스량(Fee Cap)을 설정하며, 실제 지불 수수료는 기본 수수료와 우선순위 수수료의 합으로 이 최대 수수료 한도를 초과할 수 없습니다. 따라서 최대 수수료는 항상 기본 수수료보다 높아야 합니다. + +구체적인 baseFee를 결정하는 메커니즘은 다음 식과 같습니다. + + +![alt text](https://miro.medium.com/v2/resize:fit:1400/format:webp/0*VFnmkkz-JE8ibQZl) + +타겟 블록사이즈는 이전 블록의 최대 사이즈 / 2 이고, 이전 블록의 사이즈는 최소 0에서 최대 타겟 블록사이즈의 두배 이므로 다음과 같습니다. + +![alt text](https://miro.medium.com/v2/resize:fit:1400/format:webp/0*bdhMNpOOpd7vG-_Z) + +위 식에 의해 현재 블록의 baseFee는 아래의 범위 내에서 정해집니다. + +![alt text](https://miro.medium.com/v2/resize:fit:1400/format:webp/0*TWrvbTdGD5OR1dtv) + + +## Reference + +https://eips.ethereum.org/EIPS/eip-1559 + +https://medium.com/@mrclo0116/eip-1559%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-29e9da06fff2 + +https://consensys.io/blog/what-is-eip-1559-how-will-it-change-ethereum From b7165cea9c23fc2bae7a8ba6c6f69e616443e6af Mon Sep 17 00:00:00 2001 From: smin-k Date: Fri, 5 Apr 2024 17:36:50 +0900 Subject: [PATCH 08/23] 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 000000000000..fa8981b88c5a --- /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. From fb8d3fa4767c4b2ef74023e10e1261f461ea1584 Mon Sep 17 00:00:00 2001 From: smin-k Date: Fri, 5 Apr 2024 17:37:52 +0900 Subject: [PATCH 09/23] core/state_transition.go: eip-2 comment --- core/state_transition.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/state_transition.go b/core/state_transition.go index a52e24dc4395..1a684b3b3eec 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -71,6 +71,7 @@ func (result *ExecutionResult) Revert() []byte { 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 { From 6daa03cb448598613bec5730d9593a0bdd5766a3 Mon Sep 17 00:00:00 2001 From: smin-k Date: Fri, 5 Apr 2024 17:38:08 +0900 Subject: [PATCH 10/23] crypto/signature_nocgo.go: eip-2 comment --- crypto/signature_nocgo.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 989057442b6e..9a3c54912d38 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -99,6 +99,8 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { return sig, nil } + +//eip2: 서명 크기 확인 // VerifySignature checks that the given public key created signature over hash. // The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format. // The signature should have the 64 byte [R || S] format. From 668446a7919fac2e8b86c318d74bfada2b1e76eb Mon Sep 17 00:00:00 2001 From: smin-k Date: Fri, 5 Apr 2024 17:38:21 +0900 Subject: [PATCH 11/23] params/protocol_params.go: eip-2 comment --- params/protocol_params.go | 1 + 1 file changed, 1 insertion(+) diff --git a/params/protocol_params.go b/params/protocol_params.go index 32ce83f255ed..dd32dd7e0f9c 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -34,6 +34,7 @@ const ( CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero. CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior. TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions. + //eip2: 추가된 가스비 코드 TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation. From 6b4035c6b7bdb3e29fc328c1882ca5f538f6e4df Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Fri, 5 Apr 2024 19:52:00 +0900 Subject: [PATCH 12/23] EIPs: update eip-1559.md --- EIPs/eip-1559.md | 367 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 367 insertions(+) diff --git a/EIPs/eip-1559.md b/EIPs/eip-1559.md index b78c7ac4bfef..b4543c254306 100644 --- a/EIPs/eip-1559.md +++ b/EIPs/eip-1559.md @@ -48,6 +48,373 @@ EIP-1559에서는 이전 블록의 사이즈가 목표 블록 사이즈보다 ![alt text](https://miro.medium.com/v2/resize:fit:1400/format:webp/0*TWrvbTdGD5OR1dtv) +## 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 From 456d9ddbdfc501760e84c470d577418399c8f1eb Mon Sep 17 00:00:00 2001 From: smin-k Date: Fri, 5 Apr 2024 20:03:42 +0900 Subject: [PATCH 13/23] EIPs: update eip-2.md --- EIPs/eip-2.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/EIPs/eip-2.md b/EIPs/eip-2.md index fa8981b88c5a..1279a32e3eed 100644 --- a/EIPs/eip-2.md +++ b/EIPs/eip-2.md @@ -15,7 +15,7 @@ 트랜잭션을 보내고 받는 사람 주소가 빈 문자열인 경우 차감되는 초기 가스는 현재의 경우인 21,000이 아니라 53,000에 tx 데이터의 가스 비용을 더한 금액입니다. CREATE opcode를 사용한 계약 생성은 영향을 받지 않습니다. -스마트 계약을 생성하는 방식은 두개가 존재한다. +스마트 계약을 생성하는 방식은 두개가 존재합니다. 1. 트랜잭션 To 를 빈 주소(0x0)로 전송하는 방법: 21,000 gas @@ -106,11 +106,11 @@ func VerifySignature(pubkey, hash, signature []byte) bool { 최종 가스 수수료를 지불할 가스가 충분하지 않은 경우 계약 생성에 실패하면, 다음과 같은 이점이 있습니다. -(i) 현재의 "성공, 실패 또는 빈 계약"의 삼분법보다는 계약 생성 프로세스의 결과에 보다 직관적인 "성공 또는 실패" 구분을 생성합니다. +(i) 현재의 "성공, 실패 또는 빈 계약"의 결과 계약 생성 프로세스의 결과에 보다 직관적인 "성공 또는 실패" 결과만을 생성합니다. -(ii) 계약 생성이 완전히 성공하지 않으면 계약 계정이 전혀 생성되지 않으므로 실패를 더 쉽게 감지할 수 있습니다. 그리고 +(ii) 계약 생성이 완전히 성공하지 않으면 계약 계정이 전혀 생성되지 않으므로 생성 실패를 더 쉽게 감지할 수 있습니다. 그리고 -(iii) 전체 개시 프로세스가 발생하거나 거래가 실패하고 기부금이 환불된다는 보장이 있으므로 기부금이 있는 경우 계약 생성을 더 안전하게 만듭니다. +(iii) 거래가 실패하더라도, 가스가 환불된다는 보장이 있으므로 계약 생성을 더 안전하게 만듭니다. code ```go @@ -132,21 +132,22 @@ func VerifySignature(pubkey, hash, signature []byte) bool { #### 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) -$ +$$ +\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초의 블록 생성 시간을)을 가지는 블록들을 채굴하던 문제가 있었고, 이는 블록 시간 분포를 왜곡 시켰습니다. +기존의 난이도 알고리즘은 네트워크의 해시레이크가 급격하게 변하는 경우, 빠르게 이에 적응하는 것이 어렵습니다. 때문에 2015년 9월 이더리움 프로토콜에서 과도한 수의 채굴자가 $\text{parent\_timestamp} + 1$ 의 타임스탬프 값(1초의 블록 생성 시간을)을 가지는 블록들을 채굴하던 문제가 있었고, 이는 블록 시간 분포를 왜곡 시켰습니다. From c59345f65fb7291b7154aaf5c2b185a516b1455e Mon Sep 17 00:00:00 2001 From: Seungmin Kim Date: Fri, 5 Apr 2024 20:05:50 +0900 Subject: [PATCH 14/23] EIPs: Update eip-2.md --- EIPs/eip-2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPs/eip-2.md b/EIPs/eip-2.md index 1279a32e3eed..ce99a039fd97 100644 --- a/EIPs/eip-2.md +++ b/EIPs/eip-2.md @@ -147,7 +147,7 @@ $$ 로 변경합니다. 최소 난이도는 그대로 유지되며 최소 난이도 아래로는 변경되지 않습니다. -기존의 난이도 알고리즘은 네트워크의 해시레이크가 급격하게 변하는 경우, 빠르게 이에 적응하는 것이 어렵습니다. 때문에 2015년 9월 이더리움 프로토콜에서 과도한 수의 채굴자가 $\text{parent\_timestamp} + 1$ 의 타임스탬프 값(1초의 블록 생성 시간을)을 가지는 블록들을 채굴하던 문제가 있었고, 이는 블록 시간 분포를 왜곡 시켰습니다. +기존의 난이도 알고리즘은 네트워크의 해시레이크가 급격하게 변하는 경우, 빠르게 이에 적응하는 것이 어렵습니다. 때문에 2015년 9월 이더리움 프로토콜에서 과도한 수의 채굴자가 $\text{parent\\_timestamp} + 1$ 의 타임스탬프 값(1초의 블록 생성 시간을)을 가지는 블록들을 채굴하던 문제가 있었고, 이는 블록 시간 분포를 왜곡 시켰습니다. From f9c2cbfdc8cfc4a1c87c765f1094bc914821b40c Mon Sep 17 00:00:00 2001 From: Seungmin Kim Date: Fri, 5 Apr 2024 20:07:08 +0900 Subject: [PATCH 15/23] EIPs: Update eip-2.md --- EIPs/eip-2.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPs/eip-2.md b/EIPs/eip-2.md index ce99a039fd97..fc860590aa79 100644 --- a/EIPs/eip-2.md +++ b/EIPs/eip-2.md @@ -133,8 +133,8 @@ func VerifySignature(pubkey, hash, signature []byte) bool { #### 4. 현재 공식에서 난이도 조정 알고리즘을 변경합니다: $$ -\text{block\_diff} = \text{parent\_diff} + \frac{\text{parent\_diff}}{2048} \times \begin{cases} -1, & \text{if block\_timestamp} - \text{parent\_timestamp} < 13 \\ +\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) $$ @@ -142,7 +142,7 @@ $$ 를 $$ -\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) +\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) $$ 로 변경합니다. 최소 난이도는 그대로 유지되며 최소 난이도 아래로는 변경되지 않습니다. @@ -153,7 +153,7 @@ $$ 따라서 새로운 난이도 알고리즘은 이러한 문제를 해결하도록 제안되었습니다. 제안된 새로운 공식은 대략적으로 평균값을 목표로 하고 있으며, 이 공식은 24초보다 긴 평균 블록 시간이 수학적으로 불가능하다는 것을 증명할 수 있습니다. -시간 차이가 아닌 $\frac{block\_timestamp - parent\_timestamp}{10}$을 주요 입력 변수로 사용하는 것은 알고리즘의 대략적인 특성을 직접적으로 유지하는 역할을 합니다. +시간 차이가 아닌 $\frac{\text{block\\_timestamp} - \text{parent\\_timestamp}}{10}$을 주요 입력 변수로 사용하는 것은 알고리즘의 대략적인 특성을 직접적으로 유지하는 역할을 합니다. 이는 채굴자들이 약간 높은 난이도를 가진 블록을 생성하여 가능한 모든 포크를 확실히 이길 수 있도록 타임스탬프 차이를 정확히 $1$로 설정하는 과도한 유인을 방지합니다. From a21a5838052824e54b2525558fe2defc14cc5972 Mon Sep 17 00:00:00 2001 From: SangIlMo Date: Fri, 5 Apr 2024 22:23:26 +0900 Subject: [PATCH 16/23] EIPs: add erc-7291.md --- EIPs/erc-7291.md | 392 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 EIPs/erc-7291.md diff --git a/EIPs/erc-7291.md b/EIPs/erc-7291.md new file mode 100644 index 000000000000..00c45f40a290 --- /dev/null +++ b/EIPs/erc-7291.md @@ -0,0 +1,392 @@ +# PBM Technical Whitepaper + +## Background + +CDBC는 새로운 디지털 자산 생태계의 교환 매체(medium of exchange)로써 사용되어질 수 있다. + +CBDC와 같은 digital money의 가장 큰 장점은 Programmability Feature를 지원한다는 것이다. + +그러나, 이 Programmability로 인해 교환 매체\*로서의 기능을 잃어버려서는 안된다. 화폐의 단일 목적(Singleness)이 보존되어야 하며, Programmability가 화폐의 분배를 제한하거나 시스템의 유동성 조각화를 야기해서는 안된다. + +- 교환 매체 + In economics, a **medium of exchange** is any item that is widely acceptable in exchange for goods and services. + 현대시대에서 대표적인 교환 매체는 법정 화폐 라고 볼 수 있다. + +PBM - Purpose Bound Money: 화폐 자체가 Program될 필요 없이, 구체적인 목적을 위해 만들어진 화폐 + +다른 원장 기술과 화폐 형태에도 동작할 수 있도록 Common Protocol을 활용한다. 표준화된 포멧을 통해서, 사용자는 원하는 Wallet Provider로 Digital Money에 접근할 수 있다. + +## Motivation + +- Proliferation of markets and their fragmentation (시장 증식과 조각화) + + - 서로 다른 결제 채널과 방식을 사용함으로써, 상인이나 소비자들이 이에 적응하기위해 소비하는 노력과 자원이 발생함 + - ApplePay와 같은 페이먼트 시스템을 제공하기 위해서 해당 스펙의 프로토콜을 지원하는 포스단말기, 인앱서비스, 카드사 결제 시스템 등에 업데이트가 필요하다. + - 독립적이고 개별화된 시스템들을 하나의 플랫폼으로 구성하면 더 나은 UX와 디지털화의 잠재력을 발휘할 수 있음 + - 이에 여러 payment 시스템들에 대한 상호작용을 필요로 하게 되며 기업 및 소비자들에게 높은 유연성을 제공해야함 + +- Programmability and fungibility of money (자산의 프로그래밍 가능성과 대체 가능성) + - digital money의 Prgrammability는 큰 차별점이지만, **교환 매체로써의 역할을 상실할 위험**이 있음 + - 서비스에 따라 필요한 디지털 자산들이 많아지면서 모든 UseCase에 맞는 단일화된 Digital Money를 생성하기는 어려움 + - 새로운 UseCase를 얻기 위해 의존성에 의해 다시 programming 해야 함 + - Fungibility 또한 토큰 간의 거래가 자유롭게 이루어질 수 있는 목적에서 중요 + - 개별 서비스 별 digital money를 만드는 경우, Fungibility 상실 및 유동성이 축소될 수 있음 + +## Models of Programmability + +models-figure + +### Programmable payment + +- 미리 설정된 조건을 만족한 경우 결제를 자동화하는 모델 +- API Gateway 형태나 DB Trigger 형태로 구현되며 accounting ledger ↔ client application의 상호작용으로 발생함 + - 자동이체, 자동납부 등 +- 여러 형태의 화폐에 Programming Logic이나 조건을 적용할 수 있음 + +### Programmable money + +- 자산 자체에 정해진 규칙을 설정하고 사용을 제한하는 모델 + - 포인트, 쿠폰, 상품권 등 + - 토큰화된 은행 부채, CBDC +- Programming Logic을 화폐에 적용한 채로 전송됨 + +→ Programmble payment는 자산과 Programming Logic이 분리되어 있지만, money의 경우 하나로 묶여 자산 자체를 제한한다고 볼 수 있다. + +→ 각 국가별 중앙은행, 시중 은행, 서비스 제공자 들에 대해 각각의 CBDC, 부채, stablecoin 이 발생한다면, 더욱 복잡하고 다양한 금융 landsape이 형성됨 따라서, 하나로 통함할 수 있는 Framework의 필요성이 매우 중요 (서로 다른 digital money간의 상호작용과 현존하는 금융 인프라와 호환성을 가능하게 해야함) + +### Purpose Bound Money (PBM) + +- 자산이 사용되는 조건을 구체화 할 수 있는 모델 +- 따라서, payment와 money의 각 특징을 모두 구현 가능 +- digital money로서 내재 가치(intrinsic value)와 Programming Logic 을 포함할 수 있음 + - condition이 성립되면 digital money는 내재 가치가 보존되고, progrmming 조건에서 벗어나게 됨 +- 예시) 디지털 쿠폰 + - 상품이나 서비스와 교환할 수 있음 (Programmable Payment) + - 약관에 따라 양도가 가능함 (Programmable Money) + - 다른 점은, Payee가 지불받은 후 digital money로 전환되어 다른 목적으로 사용 가능 + +models-compare-table + +## System Architecture + +|Layer|Examples| +| --- | --- | +| Access Layer | Wallets, Applications, Portals | +| Service Layer | Lending, Borrowing, Derivatives, Purpose Bound Money | +| Asset Layer | CBDC, Stablecoin, Tokenised Bank Liability, Digital Money | +| Platform Layer | Execution, Storage, Addressing, Consensus | + +→ PBM 디자인은 다른 유형의 블록체인과 자산에서도 작동하며, 비 원장 시스템에서도 사용 가능하다. + +### PBM 요소 + +- Wrapper: 의도한 목적에 따른 역할 수행 + - 정해진 조건에 따라서 수행함 + - 조건 만족시 digital money로 전환되고 recipient에게 전송됨 + - ERC-1155로 구현 가능함 +- Store of Value: 내재가치를 지속적으로 보유 + - digital money로서의 가치를 저장함 + - 상품 가치, 계좌, 환전 매개체 + - CBDC 가능 + +pbm-component + +### 역할과 상호작용 + +- PBM Creator + → PBM 로직을 정의하고, 발행 및 분배를 담당함 +- PBM Holder + → PBM token을 사용하며, 기한이 만료되기 전 PBM 토큰을 상환 가능 +- PBM Redeemer + → PBM token의 역할이 완료된 후, digital money를 수령함 + +### Lifecycle + +pbm-lifecycle + +예시) + +1. Issue Stage + - PBM 초기화 + - PBM Token 생성 + - PBM Token 발행 +2. Distribute | Transfer + - PBM 분배 및 거래(전송) +3. Redemption Stage + - PBM 상환 +4. Expired Stage + - Redeem expired PBM Token - 만기로 인한, PBM 사용(전송)불가 + - Revoke PBM - 만기로 인한, PBM 상환 + +### components + +- PBM Wrapper (Actions) + - Mint | Burn | Transfer PBM + - Interact with PBM Logic and PBM Token Manager +- PBM Logic → create complex business conditions + - add or remove from whitelist / blacklist + - check if PBM can be transferred / unwrapped +- PBM Token Manager (Type and Balance Management) + - create PBM token types + - get details of each PBM token type + - increase/decrease supply balance + - validate PBM token expiry + +pbm-smart-contract + +## Interface + +ERC-1155를 기반으로 PBM-Wrapper를 통해 PBM Token을 생성한다. + +ERC-1155는 multiple tokens를 지원하고 각 토큰에 ID 부여가 가능하여 Token Type을 구체적으로 설정할 수 있다. + +### PBM Token Details (PBM Token Manager) + +- 모든 필수 비즈니스 로직이 TokenType 별로 반드시 기재되어야 함 + +PBMToken structure에서 다음 요소를 필수로 지정하고 있다. (**MUST**) + +- name - token name +- faceValue - value of underlying token + - Wrapping한 Token 수량을 기록 +- expiry - 만료기간 +- uri - metadata uri (display purpose) +- 이외 모두 Optional이며 필요한 사항은 추가 가능 (**MAY**) + - PBM Token이 각 서비스 목적에 따라 사용 될 수 있도록 하기 위해 자율성을 부과 +- PBMToken struct + + ```solidity + abstractcontract IPBMRC1_TokenManager { + /// @dev Mapping of each ERC-1155 tokenId to its corresponding PBM Token details. + mapping (uint256=> PBMToken)internal tokenTypes ; + + /// @notice A PBM token MUST include compulsory state variables (name, faceValue, expiry, and uri) to adhere to this standard. + /// @dev Represents all the details corresponding to a PBM tokenId. + struct PBMToken { + // Name of the token. + string name; + + // Value of the underlying wrapped ERC20-compatible sovToken. Additional information on the `faceValue` can be specified by + // adding the optional variables: `currencySymbol` or `tokenSymbol` as indicated below + uint256 faceValue; + + // Time after which the token will be rendered useless (expressed in Unix Epoch time). + uint256 expiry; + + // Metadata URI for ERC-1155 display purposes. + string uri; + + // OPTIONAL: Indicates if the PBM token can be transferred to a non merchant/redeemer wallet. + bool isTransferable; + + // OPTIONAL: Determines whether the PBM will be burned or revoked upon expiry, under certain predefined conditions, or at the owner's discretion. + bool burnable; + + // OPTIONAL: Number of decimal places for the token. + uint8 decimals; + + // OPTIONAL: The address of the creator of this PBM type on this smart contract. This field is optional because the creator is msg.sender by default. + address creator; + + // OPTIONAL: The smart contract address of the sovToken. + address tokenAddress; + + // OPTIONAL: The running balance of the PBM Token type that has been minted. + uint256 totalSupply; + + // OPTIONAL: An ISO4217 three-character alphabetic code may be needed for the faceValue in multicurrency PBM use cases. + string currencySymbol; + + // OPTIONAL: An abbreviation for the PBM token name may be assigned. + string tokenSymbol; + + // Add other optional state variables below... + } + } + ``` + +PBMToken Type 생성 (**SHOULD**) + +- 필수 파라미터 (name, faceValue, expiry, uri) 전달 +- 해당 Token 정보에 대한 Event 발생 +- createPBMTokenType + + ```solidity + /// @notice Creates a new PBM Token type with the provided data. + /// @dev The caller of createPBMTokenType shall be responsible for setting the creator address. + /// Example of uri can be found in [`sample-uri`](/assets/eip-7291/sample-uri/stx-10-static) + /// Must emit {NewPBMTypeCreated} + /// @param _name Name of the token. + /// @param _faceValue Value of the underlying wrapped ERC20-compatible sovToken. + /// @param _tokenExpiry Time after which the token will be rendered useless (expressed in Unix Epoch time). + /// @param _tokenURI Metadata URI for ERC-1155 display purposes + function createPBMTokenType( + string memory _name, + uint256 _faceValue, + uint256 _tokenExpiry, + string memory _tokenURI + ) external virtual returns (uint256 tokenId_); + + /// @notice Emitted when a new Purpose-Bound Token (PBM) type is created within the contract. + /// @param tokenId The unique identifier for the newly created PBM token type. + /// @param tokenName A human-readable string representing the name of the newly created PBM token type. + /// @param amount The initial supply of the newly created PBM token type. + /// @param expiry The timestamp at which the newly created PBM token type will expire. + /// @param creator The address of the account that created the new PBM token type. + event NewPBMTypeCreated(uint256 tokenId, string tokenName, uint256 amount, uint256 expiry, address creator); + ``` + +PBM Token Info Details (**MUST**) + +- PBM 정보를 가져오기 위한 함수 +- getTokenDetails + ```solidity + /// @notice Retrieves the details of a PBM Token type given its tokenId. + /// @dev This function fetches the PBMToken struct associated with the tokenId and returns it. + /// @param tokenId The identifier of the PBM token type. + /// @return pbmToken_ A PBMToken struct containing all the details of the specified PBM token type. + function getTokenDetails(uint256 tokenId) external virtual view returns(PBMToken memory pbmToken_); + ``` + +### PBM Address List (PBM Logic) + +- PBM 사용 및 Release(Unwrap)이 가능한 Address 목록을 유지해야 함 +- 해당 인터페이스는, 추가적인 비즈니스 로직과 함께 사용되어질 수 있음 (**MUST**) + - isBlacklisted() + - Blacklist - event + - isMerchant() + - MerchantList - event +- IPBMAddressList + + ``` + pragma solidity^0.8.0; + + /// @title PBM Address list Interface. + /// @notice The PBM address list stores and manages whitelisted merchants/redeemers and blacklisted address for the PBMs + interface IPBMAddressList { + + /// @notice Checks if the address is one of the blacklisted addresses + /// @param _address The address to query + /// @return bool_ True if address is blacklisted, else false + function isBlacklisted(address _address)externalreturns (bool bool_) ; + + /// @notice Checks if the address is one of the whitelisted merchant/redeemer addresses + /// @param _address The address to query + /// @return bool_ True if the address is in merchant/redeemer whitelist and is NOT a blacklisted address, otherwise false. + function isMerchant(address _address)externalreturns (bool bool_) ; + + /// @notice Event emitted when the Merchant/Redeemer List is edited + /// @param action Tags "add" or "remove" for action type + /// @param addresses An array of merchant wallet addresses that was just added or removed from Merchant/Redeemer whitelist + /// @param metadata Optional comments or notes about the added or removed addresses. + event MerchantList(string action,address[] addresses,string metadata); + + /// @notice Event emitted when the Blacklist is edited + /// @param action Tags "add" or "remove" for action type + /// @param addresses An array of wallet addresses that was just added or removed from address blacklist + /// @param metadata Optional comments or notes about the added or removed addresses. + event Blacklist(string action,address[] addresses,string metadata); + } + ``` + +### PBMRC - Base Interface (PBM Wrapper) + +- Digital Money Wrapping을 통한 PBM Token 발행 +- mint | burn | transfer | revoke | unwrap PBM Lifecycle위한 Action 책임짐 +- IPBMRC1 + + ```solidity + /// LIST OF EVENTS TO BE EMITTED + /// A database or explorer may listen to events and be able to provide indexed and categorized searches + /// @title PBM Specification interface + /// @notice The PBM (purpose bound money) allows us to add logical requirements on the use of sovTokens. + /// The PBM acts as wrapper around the sovTokens and implements the necessary business logic. + /// @dev PBM deployer must assign an overall owner to the smart contract. If fine grain access controls are required, EIP-5982 can be used on top of ERC173 + interface IPBMRC1 is IERC173, IERC5679Ext1155 { + + // underlying ERC20 토큰의 정보와, Business Logic 컨트랙트 정보 등을 얻어 + // PBM Token으로 Wrapping하는 함수 + function initialise(address _sovToken, uint256 _expiry, address _pbmWrapperLogic) external; + + /// @notice Returns the uri metadata information for the PBM with the corresponding tokenId + function uri(uint256 tokenId) external view returns (string memory); + + function safeMint(address receiver, uint256 tokenId, uint256 amount, bytes calldata data) external; + function safeMintBatch(address receiver, uint256[] calldata tokenIds, uint256[] calldata amounts, bytes calldata data) external; + + function burn(address from, uint256 tokenId, uint256 amount, bytes calldata data) external; + function burnBatch(address from, uint256[] calldata tokenIds, uint256[] calldata amounts, bytes calldata data) external; + + // 1. buisiness logic check + // 2. unwrap function may be called within this function + // buisiness logic 조건 만족하는 경우, PBM Token 간 자유롭게 전송 가능해야 하며 + // 조건 만족시 underlying ERC20 토큰 release를 위해 unwrap 호출 해야 함 + function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) external; + function safeBatchTransferFrom(address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external; + + function unwrap(address from, address to, uint256 tokenId, uint256 amount, bytes memory data) internal; + + // PBM Token 만료시 Revoke + // 전송 되지 않고, unwrap 되어 underlying ERC20 release 됨 + function revokePBM(uint256 tokenId) external; + + event PBMrevokeWithdraw(address beneficiary, uint256 PBMTokenId, address sovToken, uint256 sovTokenValue); + event TokenUnwrapForTarget(address from, address to, uint256[] tokenIds, uint256[] amounts, address sovToken, uint256 sovTokenValue); + event TokenUnwrapForPBMBurn(address from, address to, uint256[] tokenIds, uint256[] amounts, address sovToken, uint256 sovTokenValue); + event TokenWrap(address from, uint256[] tokenIds, uint256[] amounts,address sovToken, uint256 sovTokenValue); + } + + ``` + +### Extension of PBMRC1 - Token Receiver + +- Token Receiver의 경우, PBM Token을 전송 받고 Unwrap(release) 과정에서 추가적인 로직을 수행할 수 있도록 한다. +- PBMRC1_TokenReceiver + + ```solidity + /// @notice Smart contracts MUST implement the ERC-165 `supportsInterface` function and signify support for the `PBMRC1_TokenReceiver` interface to accept callbacks. + /// It is optional for a receiving smart contract to implement the `PBMRC1_TokenReceiver` interface + /// @dev WARNING: Reentrancy guard procedure, Non delegate call, or the check-effects-interaction pattern must be adhere to when calling an external smart contract. + /// The interface functions MUST only be called at the end of the `unwrap` function. + interface PBMRC1_TokenReceiver { + + // PBMToken 수신 후, Unwrap 시에 추가적인 logic 호출 가능 + // ex) 구입 시 10% 할인 등? + function onPBMRC1Unwrap(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4); + function onPBMRC1BatchUnwrap(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4); + } + ``` + +### PBMRC2 + +- PBMRC1과 달리, non preloaded PBM으로 underlying ERC20 amount를 처음부터 할당 하지 않고, 이후에 할당할 수 있는 방식이다. +- IPBMRC1을 구현하고 있으며 추가적으로 다음 함수를 포함한다. + - load() - load underlying ERC20 amount into PBMtoken + - unload() - unload amount + - 네이버 포인트 등으로 사용 가능할 것 같음 +- PBMRC2_NonPreloadedPBM + + ```solidity + interface PBMRC2_NonPreloadedPBM is IPBMRC1 { + + ... + + function load(uint256 amount) external; + function unload(uint256 amount) external; + + event TokenLoad(address caller, address to, uint256 amount, address sovToken, uint256 sovTokenValue); + event TokenUnload(address caller, address from, uint256 amount, address sovToken, uint256 sovTokenValue); + } + ``` + +진행된 PoC - https://github.com/StraitsX/Orchid-PBM + +## reference + +- [ERC-7291](https://eips.ethereum.org/EIPS/eip-7291) +- [PBM poc Implementation](https://github.com/StraitsX/Orchid-PBM) +- [ERC-7291 Interface](https://github.com/ethereum/ERCs/tree/master/assets/erc-7291/contracts) +- [ERC-7291 Proposal](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7291.md) +- [PBM Technical Report](https://www.mas.gov.sg/-/media/mas-media-library/development/fintech/pbm/pbm-technical-whitepaper.pdf) +- [Ethereum Magician Discussion](https://ethereum-magicians.org/t/eip-7291-purpose-bound-money/14973) +- [RFC2119](https://datatracker.ietf.org/doc/html/rfc2119) From 25c65c196c9ae29d1d340ccf96511a8019197989 Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Fri, 5 Apr 2024 22:49:09 +0900 Subject: [PATCH 17/23] EIPs: update code explain eip-1559.md --- EIPs/eip-1559.md | 59 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/EIPs/eip-1559.md b/EIPs/eip-1559.md index b4543c254306..b6edfb522b32 100644 --- a/EIPs/eip-1559.md +++ b/EIPs/eip-1559.md @@ -50,11 +50,10 @@ EIP-1559에서는 이전 블록의 사이즈가 목표 블록 사이즈보다 ## Code -```python -from typing import Union, Dict, Sequence, List, Tuple, Literal -from dataclasses import dataclass, field -from abc import ABC, abstractmethod +### python implementation +legacy, 2930, 1559등 트랜잭션 별 dataclass를 정의합니다. +```python @dataclass class TransactionLegacy: signer_nonce: int = 0 @@ -149,19 +148,46 @@ class Account: balance: int = 0 storage_root: int = 0 code_hash: int = 0 +``` +초기 base fee, fork block number(London) 등 base fee 계산에 필요한 상수값을 정의합니다. + +```python INITIAL_BASE_FEE = 1000000000 INITIAL_FORK_BLOCK_NUMBER = 10 # TBD BASE_FEE_MAX_CHANGE_DENOMINATOR = 8 ELASTICITY_MULTIPLIER = 2 +``` + + +아래 코드는 eip 1559 이후 이더리움 블록의 유효성을 검증하는 핵심 로직을 구현한 것입니다. 주요 기능은 다음과 같습니다: + +1. 부모 블록의 가스 한도와 목표량 계산 +- 부모 블록의 가스 한도와 가스 목표량을 계산합니다. +- 포크 블록의 경우, 가스 목표량이 과도하게 줄어드는 것을 방지하기 위해 별도로 처리합니다. + +2. 블록의 가스 한도 검증 +- 블록의 실제 가스 사용량이 블록의 가스 한도 내에 있는지 확인합니다. +- 블록의 가스 한도가 부모 블록에 비해 너무 많이 증가/감소하지 않았는지 확인합니다. +- 블록의 가스 한도가 최소 가스 한도 이상인지 검증합니다. + +3. 블록의 base fee 검증 +- 부모 블록의 base fee와 가스 사용량을 기반으로 예상되는 base fee를 계산합니다. +- 블록의 실제 base fee가 예상 값과 일치하는지 확인합니다. +4. 트랜잭션 실행 및 가스 회계 수행 +- 트랜잭션 서명과 체인 ID를 먼저 검증한 후 트랜잭션을 정규화합니다. +- 트랜잭션 송신자가 연결된 가치와 가스 비용을 커버할 수 있는 이더 잔액이 있는지 확인합니다. +- 사용자가 최소한 base fee를 지불할 의사가 있는지 확인합니다. +- 트랜잭션 파라미터에 불가능할 정도로 큰 숫자가 포함되지 않도록 합니다. +- 트랜잭션을 실행하고, 실효 가스 가격(base fee + priority fee)을 송신자 잔액에서 차감하며, 사용되지 않은 가스를 환불합니다. +- priority fee를 채굴자 계정에 적립합니다. + +5. 총 가스 사용량 검증 +- 블록의 총 가스 사용량이 모든 트랜잭션의 가스 사용량 합계와 일치하는지 확인합니다. + +```python 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 @@ -271,8 +297,11 @@ class World(ABC): # 따라서 블록에 대한 유효성 검사를 수행할 때는 블록 헤더에 있는 상태 루트와 실제 계정의 상태를 비교하여 일치하는지 확인해야 함 # TODO: validate the rest of the block # 나머지 블록 검증 +``` + +여러 표준의 트랜잭션을 정규화합니다. - # 트랜잭션 정규화 +```python def normalize_transaction(self, transaction: Transaction, signer_address: int) -> NormalizedTransaction: # legacy transactions if isinstance(transaction, TransactionLegacy): @@ -337,6 +366,10 @@ class World(ABC): def account(self, address: int) -> Account: pass ``` +### geth implementation + +VerifyEIP1559Header 함수는 gas limit, basefee를 확인해서 EIP-1559이후 변경된 헤더 속성을 검증합니다. + ```go // VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559, // - gas limit check @@ -366,7 +399,11 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade } return nil } +``` +CalcBaseFee는 header의 basefee를 계산합니다. + +```go // CalcBaseFee calculates the basefee of the header. // CalcBaseFee는 header의 basefee를 계산한다. func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { From 530513726c367edbc8bbd4093c337ba070acba98 Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Sat, 6 Apr 2024 12:25:15 +0900 Subject: [PATCH 18/23] EIPs: add transact method EIP-1559.md --- EIPs/eip-1559.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/EIPs/eip-1559.md b/EIPs/eip-1559.md index b6edfb522b32..e2ac939e4e0b 100644 --- a/EIPs/eip-1559.md +++ b/EIPs/eip-1559.md @@ -453,6 +453,62 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { } ``` +transact는 실제 트랜잭션 호출을 실행하고, 누락된 authorization 필드를 도출한 다음 트랜잭션을 실행하도록 스케줄링합니다. + +```go +// transact executes an actual transaction invocation, first deriving any missing +// authorization fields, and then scheduling the transaction for execution. +// transact는 실제 트랜잭션 호출을 실행하고, 먼저 누락된 authorization 필드를 도출한 다음 트랜잭션을 실행하도록 스케줄링합니다. +func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { + if opts.GasPrice != nil && (opts.GasFeeCap != nil || opts.GasTipCap != nil) { + // 트랜잭션은 GasPrice 혹은 (GasFeeCap or GasTipCap) 중 하나는 지정되어 있어야 합니다. + return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") + } + // Create the transaction + var ( + rawTx *types.Transaction + err error + ) + if opts.GasPrice != nil { + // GasPrice가 설정되어 있으면 legacy transaction 실행을 실행합니다. + rawTx, err = c.createLegacyTx(opts, contract, input) + } else if opts.GasFeeCap != nil && opts.GasTipCap != nil { + // GasFeeCap, GasTipCap 모두 설정되어 있으면 EIP-1559 transaction을 실행합니다. + rawTx, err = c.createDynamicTx(opts, contract, input, nil) + } else { + // Only query for basefee if gasPrice not specified + // gasPrice가 지정되지 않으면 baseFee만 쿼리하고, baseFee 존재시 EIP-1559 transaction, 없으면 legacy transaction을 실행합니다. + // 사용자가 명시적으로 가스 관련한 field를 지정하지 않았을때 네트워크 config에 맞게 자동으로 트랜잭션 유형을 결정하기 위한 조건입니다. + if head, errHead := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil); errHead != nil { + return nil, errHead + } else if head.BaseFee != nil { + rawTx, err = c.createDynamicTx(opts, contract, input, head) + } else { + // Chain is not London ready -> use legacy transaction + rawTx, err = c.createLegacyTx(opts, contract, input) + } + } + if err != nil { + return nil, err + } + // Sign the transaction and schedule it for execution + if opts.Signer == nil { + return nil, errors.New("no signer to authorize the transaction with") + } + signedTx, err := opts.Signer(opts.From, rawTx) + if err != nil { + return nil, err + } + if opts.NoSend { + return signedTx, nil + } + if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil { + return nil, err + } + return signedTx, nil +} +``` + ## Reference https://eips.ethereum.org/EIPS/eip-1559 From 2e4825dc56f7683885490e0a059f971a40b775dc Mon Sep 17 00:00:00 2001 From: SangIlMo <156392700+SangIlMo@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:59:08 +0900 Subject: [PATCH 19/23] EIPs: fix format and add contents on erc-7291.md (#3) --- EIPs/erc-7291.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/EIPs/erc-7291.md b/EIPs/erc-7291.md index 00c45f40a290..3b17b94677e1 100644 --- a/EIPs/erc-7291.md +++ b/EIPs/erc-7291.md @@ -1,6 +1,6 @@ # PBM Technical Whitepaper -## Background +## Abstract CDBC는 새로운 디지털 자산 생태계의 교환 매체(medium of exchange)로써 사용되어질 수 있다. @@ -16,6 +16,10 @@ PBM - Purpose Bound Money: 화폐 자체가 Program될 필요 없이, 구체적 다른 원장 기술과 화폐 형태에도 동작할 수 있도록 Common Protocol을 활용한다. 표준화된 포멧을 통해서, 사용자는 원하는 Wallet Provider로 Digital Money에 접근할 수 있다. +## Motive For Research + +CBDC 인프라에서 사용되기 위해 제안된 토큰 형식으로, 서비스차원에서 토큰에 Programmability를 어떻게 적용하고 digital money의 내재가치를 보존할 수 있을 지에 대한 분석을 하고자 한다. + ## Motivation - Proliferation of markets and their fragmentation (시장 증식과 조각화) From 993d3cb01c210518019f5999cf90350d6c4e33c9 Mon Sep 17 00:00:00 2001 From: SangIlMo <156392700+SangIlMo@users.noreply.github.com> Date: Sat, 6 Apr 2024 17:31:50 +0900 Subject: [PATCH 20/23] README: add section "how to work" (#4) - add git snippet when forking repositroy - add git snippet when creating branch --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/README.md b/README.md index 011edc5873f8..f86a472a5540 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,55 @@ Golang execution layer implementation of the Ethereum protocol. Orakle open-source EIP team repository. +## How to Work + +### If fork + +the case for working on personal repository after fork (recommended) + +1. Setting for the first time + +``` +// add remote upstream +git remote add upstream https://github.com/orakle-opensource/EIP_opensource.git +``` +2. Working on personal repository +``` +// create branch to work +git checkout -b [branch_name] + +// rebase upstream commits into branch +git rebase upstream/master -i + +// staging and commit +git add . +git commit -m "message" + +// push +git push -u origin [branch_name] + +// go to upstream repo(https://github.com/orakle-opensource/EIP_opensource.git) and create pull request +``` +3. After merging pull request +``` +// checkout master and pull upstream commits +git checkout master +git pull upstream master +``` + +### If branch + +the case for working by creating branch on our repository + +``` +// create branch -> commit -> push +git checkout -b [branch_name] +git add . | git commit -m "message" +git push -u origin [branch_name] + +// go to repo and create pull request +``` + ## License The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the From 0f6d38b50fc80c500633f0fad0acb29973fbbba1 Mon Sep 17 00:00:00 2001 From: c0np4nn4 Date: Mon, 8 Apr 2024 23:33:59 +0900 Subject: [PATCH 21/23] EIPs: add eip-779.md (#5) --- EIPs/eip-779.md | 210 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 EIPs/eip-779.md diff --git a/EIPs/eip-779.md b/EIPs/eip-779.md new file mode 100644 index 000000000000..1ef24b192d63 --- /dev/null +++ b/EIPs/eip-779.md @@ -0,0 +1,210 @@ +# EIP-779: Hardfork Meta: DAO Fork + + +## 요약 +"`DAO Fork`"는 ***The DAO Hack*** 사건과 관련있는 *hard fork* 입니다. +다른 *hard fork* 들과 달리, `DAO Fork` 는 EVM opcode, 트랜잭션 형식, 블록 구조 등의 `Protocol` 자체에는 수정 사항이 없습니다. +대신에, `DAO Fork`는 계정 목록들("child DAO" contracts)로부터 특정 계정("WithdrawDAO" contract)으로 `ether` 잔액을 전송하는 *불규칙적인 상태 변화* 를 일으키는 *hard fork* 입니다. + +## EIP 제안 동기 +EIP-779는 The DAO Hack 사건으로 인해 드러난 이더리움의 보안 취약점과 그로 인한 커뮤니티의 신뢰 손상을 해결하기 위해 제안되었습니다. +수백만 달러 상당의 `Ether` 도난은 네트워크 안정성에 대한 우려를 촉발시켜, 커뮤니티는 효과적인 대응책을 강력히 요구했습니다. +EIP-779는 이러한 문제를 해결하고자 하드 포크(*hard fork*)를 통해 도난 자금을 회수하는 등 구체적인 기술적 조치를 제안함으로써, 이더리움 네트워크의 복원력을 강화하는 데 중요한 역할을 했습니다. + +## 선정 이유 +EVM Security 에 대해 공부할 때 흥미롭게 본 `Re-entrancy Attack`의 대표적인 사례가 바로 ***The DAO Hack*** 사건이었습니다. +해킹 사건 발생 후에 어떤 조치가 어떻게 일어났는지 알아보고 싶어 선정하게 되었습니다. +또, 평소 궁금하던 *hard fork* 적용에 대해서도 살펴보고 싶어 선정하게 되었습니다. + +## 본론 + +`geth` 클라이언트 프로그램에 구현된 `DAO Fork`에 관한 내용은 다음과 같습니다. + +**The DAO** 컨트랙트(`0xbb9bc244d798123fde783fcc1c72d3bb8c189413`), **extraBalance** 컨트랙트 (`0x807640a13483f8ac783c557fcdf27be11ea4ac7a`), +모든 **The DAO Creator** 컨트랙트의 *자식* 계정들(`0x4a574510c7014e4ae985403536074abe582adfc8`), 각각의 *자식* 계정들에 대한 *extraBalance* 계정 등이 모두 +$L$ 이라는 목록으로 인코딩되어 $1,880,000$ 번째 블록에 기록되었습니다. + +계정 목록 $L$ 은 [gist file](https://gist.github.com/gavofyork/af747a034fbee2920f862ed352d32347)에서 확인할 수 있습니다. + +$1,920,000$ 번째 블록의 시작 이후에 모든 `Ether` 잔액은 $L$ 로부터 특정 계정 $C$ (`0xbf4ed7b27f1d666546e30d74d50d173d20bca754`) 로 전송됩니다. +중요한 점은 트랜잭션을 통한 송금이 아니라 프로토콜 단에서 강제로 `Ether` 를 옮긴다는 것입니다. + +계정 $C$ 는 `WithdrawDAO` 라는 이름의 스마트 컨트랙트가 [구현](https://etherscan.io/address/0xbf4ed7b27f1d666546e30d74d50d173d20bca754#code)된 계정입니다. + +```solidity +/** + *Submitted for verification at Etherscan.io on 2016-07-14 +*/ + +contract DAO { + function balanceOf(address addr) returns (uint); + function transferFrom(address from, address to, uint balance) returns (bool); + uint public totalSupply; +} + +contract WithdrawDAO { + DAO constant public mainDAO = DAO(0xbb9bc244d798123fde783fcc1c72d3bb8c189413); + address public trustee = 0xda4a4626d3e16e094de3225a751aab7128e96526; + + function withdraw(){ + uint balance = mainDAO.balanceOf(msg.sender); + + if (!mainDAO.transferFrom(msg.sender, this, balance) || !msg.sender.send(balance)) + throw; + } + + function trusteeWithdraw() { + trustee.send((this.balance + mainDAO.balanceOf(this)) - mainDAO.totalSupply()); + } +} +``` + +이 중 `withdraw()` 함수를 자세히 살펴보겠습니다. + +```solidity +function withdraw(){ + uint balance = mainDAO.balanceOf(msg.sender); + + if (!mainDAO.transferFrom(msg.sender, this, balance) || !msg.sender.send(balance)) + throw; +} +``` + +우선은 `mainDAO` 컨트랙트에 존재하는 토큰의 수를 `balance` 변수에 저장합니다. +이후, if 절에서 ***토큰 이전 시도*** 와 ***이더 전송 시도*** 를 진행합니다. +만일 둘 중 하나라도 정상적으로 이뤄지지 않는다면, `throw`를 통해 예외 처리를 합니다. + +--- + +### Geth + +실제 `geth` 코드 내에서는 다음과 같은 코드들을 확인할 수 있었습니다. + +#### `params/dao.go` +- `DAO Fork`를 적용하기 위한 여러 *parameter* 값들을 기록한 파일입니다. +- 사고로 흩어진 `ether`를 모으기 위해 작성된 컨트랙트 ***DAORefundContract***, +해커로 인해 `ether`가 비정상적으로 모이게 된 계정들의 목록 ***DrainList*** 등을 명시하고 있습니다. +```go +// DAOForkBlockExtra is the block header extra-data field to set for the DAO fork +// point and a number of consecutive blocks to allow fast/light syncers to correctly +// pick the side they want ("dao-hard-fork"). +// EIP-779, DAO hard-fork 지점 이후 및 추가로 연속되는 블록들의 `extra-data` 필드에 +// "dao-hard-fork" 를 16진수 형태로 변환하여 기록합니다. +// 이를 통해, 빠른 동기화나 경량 클라이언트 같은 동기화 메커니즘들이 올바른 체인을 선택하도록 돕습니다. +var DAOForkBlockExtra = common.FromHex("0x64616f2d686172642d666f726b") + +// DAOForkExtraRange is the number of consecutive blocks from the DAO fork point +// to override the extra-data in to prevent no-fork attacks. +// EIP-779, `no-fork attack` 으로부터 체인을 보호하기 위해 얼마나 많은 +// DAO fork 지점 이후 연속되는 블록의 `extra-data`에 덮어쓰기를 할 것인지 명시합니다. +var DAOForkExtraRange = big.NewInt(10) + +// DAORefundContract is the address of the refund contract to send DAO balances to. +// EIP-779, 환불(refund)을 위해 사용할 refund contract 의 주소를 명시합니다. +var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d20bca754") + +// DAODrainList is the list of accounts whose full balances will be moved into a +// refund contract at the beginning of the dao-fork block. +// EIP-779, 돈을 회수할 계정을 명시합니다. +func DAODrainList() []common.Address { + return []common.Address{ + common.HexToAddress("0xd4fe7bc31cedb7bfb8a345f31e668033056b2728"), + common.HexToAddress("0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"), + common.HexToAddress("0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f"), + common.HexToAddress("0xecd135fa4f61a655311e86238c92adcd779555d2"), + common.HexToAddress("0x1975bd06d486162d5dc297798dfc41edd5d160a7"), + // ... 생략 + } +} + +``` + +#### `consensus/misc/dao.go` +- `params/dao.go` 에서의 값들을 바탕으로 `DAO Fork` 를 적용하는 함수가 정의된 파일입니다. +- `DAORefundContract` 의 존재 여부를 검사하고, `DAODrainList` 에 명시된 계정들로부터 +`DAORefundContract`로 `Ether` 를 강제로 옮기는 과정을 진행합니다. +```go +// ApplyDAOHardFork modifies the state database according to the DAO hard-fork +// rules, transferring all balances of a set of DAO accounts to a single refund +// contract. +// +// EIP-779, TheDAO hard-fork 에 따라 DB의 상태를 변경하는 함수입니다. +// EIP-779에서도 설명하듯이 DAODrainList 의 계정들로부터 하나의 DAORefundContract 에 +// 돈을 전송하게 됩니다. +func ApplyDAOHardFork(statedb *state.StateDB) { + // Retrieve the contract to refund balances into + // EIP-779, 돈을 받을 계정이 존재하지 않는다면 새로 하나 생성합니다. + // 참고로, 계정주소는 "common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d20bca754")" 입니다. + if !statedb.Exist(params.DAORefundContract) { + statedb.CreateAccount(params.DAORefundContract) + } + + // Move every DAO account and extra-balance account funds into the refund contract + // 모든 `DAODrainList` 의 계정으로부터 `refund contract`에 돈을 보냅니다. + for _, addr := range params.DAODrainList() { + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), tracing.BalanceIncreaseDaoContract) + statedb.SetBalance(addr, new(uint256.Int), tracing.BalanceDecreaseDaoAccount) + } +} +``` + +#### `core/chain_makers.go` +- `chain_makers.go` 파일은 블록체인에 블록을 생성하고 추가하는 기능과 관련된 유틸리티와 도구들을 정의합니다. +- `DAO fork` 와 같은 *hard fork* 를 적용하는 것도 아래 코드와 같이 구현되어 있습니다. +```go +// ... + // EIP-779, DAO fork 를 지원하고 Chain Config에 DAO fork 블록 넘버가 현재 블록 넘버와 동일하다면 + // TheDAO hard-fork 를 적용합니다. + if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 { + misc.ApplyDAOHardFork(statedb) + } +// ... +``` + +#### `core/state_processor.go` +- 이더리움의 핵심 기능 중 하나인 상태 전이(state transition) 을 구현합니다. +- `DAO fork`에 관한 코드도 구현되어 있는 것을 확인할 수 있습니다. +```go +// Process processes the state changes according to the Ethereum rules by running +// the transaction messages using the statedb and applying any rewards to both +// the processor (coinbase) and any included uncles. +// +// Process returns the receipts and logs accumulated during the process and +// returns the amount of gas that was used in the process. If any of the +// transactions failed to execute due to insufficient gas it will return an error. +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { + var ( + receipts types.Receipts + usedGas = new(uint64) + header = block.Header() + blockHash = block.Hash() + blockNumber = block.Number() + allLogs []*types.Log + gp = new(GasPool).AddGas(block.GasLimit()) + ) + + // Mutate the block and state according to any hard-fork specs + // EIP-779, DAO fork 를 지원하고 Chain Config에 DAO fork 블록 넘버가 현재 블록 넘버와 동일하다면 + // TheDAO hard-fork 를 적용합니다. + if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { + misc.ApplyDAOHardFork(statedb) + } +// ... +``` + +--- + +**The DAO 해킹 사건**에서는 해커가 탈취한 이더가 28일의 잠금 기간을 갖는 자식 DAO 계정에 입금되었기 때문에, 투자자들이 즉각적으로 자금을 잃는 상황은 발생하지 않았습니다. +이러한 잠금 기간은 이더리움 커뮤니티에 대응할 시간을 제공했고, 결국 `DAO hard fork` 를 통해 탈취된 자금의 대부분을 회수할 수 있었습니다. +그러나 모든 커뮤니티 구성원이 이 *hard fork* 를 지지한 것은 아니었으며, *hard fork* 를 반대하는 일부는 `이더리움 클래식`(`Ethereum Classic`, `ETC`)이라는 새로운 체인을 만들어 `이더리움`의 원래 체인과 분리되었습니다. +`이더리움 클래식`은 *hard fork* 를 반영하지 않고 **The DAO 해킹** 전의 원래 체인을 유지하고 있습니다. + + +## Reference +https://eips.ethereum.org/EIPS/eip-779 + +https://medium.com/swlh/the-story-of-the-dao-its-history-and-consequences-71e6a8a551ee + +https://ethereum.stackexchange.com/questions/3981/what-is-the-address-and-balance-of-the-daos-extrabalance-account + +https://www.gemini.com/cryptopedia/the-dao-hack-makerdao#section-the-response-to-the-dao-hack From 179f3f8185ef02bf18e108e23a00568f92a697b0 Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Wed, 10 Apr 2024 13:38:43 +0900 Subject: [PATCH 22/23] orakle EIP open-source team branch --- README.md | 352 +++++------------------------------------------------- 1 file changed, 30 insertions(+), 322 deletions(-) diff --git a/README.md b/README.md index 0d5b7872124a..f86a472a5540 100644 --- a/README.md +++ b/README.md @@ -2,351 +2,59 @@ Golang execution layer implementation of the Ethereum protocol. -[![API Reference]( -https://pkg.go.dev/badge/github.com/ethereum/go-ethereum -)](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc) -[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum) -[![Travis](https://app.travis-ci.com/ethereum/go-ethereum.svg?branch=master)](https://app.travis-ci.com/github/ethereum/go-ethereum) -[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/nthXNEv) +## Orakle -Automated builds are available for stable releases and the unstable master branch. Binary -archives are published at https://geth.ethereum.org/downloads/. +Orakle open-source EIP team repository. -## Building the source +## How to Work -For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). +### If fork -Building `geth` requires both a Go (version 1.21 or later) and a C compiler. You can install -them using your favourite package manager. Once the dependencies are installed, run +the case for working on personal repository after fork (recommended) -```shell -make geth -``` - -or, to build the full suite of utilities: - -```shell -make all -``` - -## Executables - -The go-ethereum project comes with several wrappers/executables found in the `cmd` -directory. - -| Command | Description | -| :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/fundamentals/command-line-options) for command line options. | -| `clef` | Stand-alone signing tool, which can be used as a backend signer for `geth`. | -| `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. | -| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings) page for details. | -| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | -| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | -| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | - -## Running `geth` - -Going through all the possible command line flags is out of scope here (please consult our -[CLI Wiki page](https://geth.ethereum.org/docs/fundamentals/command-line-options)), -but we've enumerated a few common parameter combos to get you up to speed quickly -on how you can run your own `geth` instance. - -### Hardware Requirements - -Minimum: - -* CPU with 2+ cores -* 4GB RAM -* 1TB free storage space to sync the Mainnet -* 8 MBit/sec download Internet service - -Recommended: - -* Fast CPU with 4+ cores -* 16GB+ RAM -* High-performance SSD with at least 1TB of free space -* 25+ MBit/sec download Internet service - -### Full node on the main Ethereum network - -By far the most common scenario is people wanting to simply interact with the Ethereum -network: create accounts; transfer funds; deploy and interact with contracts. For this -particular use case, the user doesn't care about years-old historical data, so we can -sync quickly to the current state of the network. To do so: - -```shell -$ geth console -``` - -This command will: - * Start `geth` in snap sync mode (default, can be changed with the `--syncmode` flag), - causing it to download more data in exchange for avoiding processing the entire history - of the Ethereum network, which is very CPU intensive. - * Start the built-in interactive [JavaScript console](https://geth.ethereum.org/docs/interacting-with-geth/javascript-console), - (via the trailing `console` subcommand) through which you can interact using [`web3` methods](https://github.com/ChainSafe/web3.js/blob/0.20.7/DOCUMENTATION.md) - (note: the `web3` version bundled within `geth` is very old, and not up to date with official docs), - as well as `geth`'s own [management APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc). - This tool is optional and if you leave it out you can always attach it to an already running - `geth` instance with `geth attach`. - -### A Full node on the Görli test network +1. Setting for the first time -Transitioning towards developers, if you'd like to play around with creating Ethereum -contracts, you almost certainly would like to do that without any real money involved until -you get the hang of the entire system. In other words, instead of attaching to the main -network, you want to join the **test** network with your node, which is fully equivalent to -the main network, but with play-Ether only. - -```shell -$ geth --goerli console ``` - -The `console` subcommand has the same meaning as above and is equally -useful on the testnet too. - -Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a bit: - - * Instead of connecting to the main Ethereum network, the client will connect to the Görli - test network, which uses different P2P bootnodes, different network IDs and genesis - states. - * Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth` - will nest itself one level deeper into a `goerli` subfolder (`~/.ethereum/goerli` on - Linux). Note, on OSX and Linux this also means that attaching to a running testnet node - requires the use of a custom endpoint since `geth attach` will try to attach to a - production node endpoint by default, e.g., - `geth attach /goerli/geth.ipc`. Windows users are not affected by - this. - -*Note: Although some internal protective measures prevent transactions from -crossing over between the main network and test network, you should always -use separate accounts for play and real money. Unless you manually move -accounts, `geth` will by default correctly separate the two networks and will not make any -accounts available between them.* - -### Configuration - -As an alternative to passing the numerous flags to the `geth` binary, you can also pass a -configuration file via: - -```shell -$ geth --config /path/to/your_config.toml -``` - -To get an idea of how the file should look like you can use the `dumpconfig` subcommand to -export your existing configuration: - -```shell -$ geth --your-favourite-flags dumpconfig +// add remote upstream +git remote add upstream https://github.com/orakle-opensource/EIP_opensource.git ``` - -*Note: This works only with `geth` v1.6.0 and above.* - -#### Docker quick start - -One of the quickest ways to get Ethereum up and running on your machine is by using -Docker: - -```shell -docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \ - -p 8545:8545 -p 30303:30303 \ - ethereum/client-go +2. Working on personal repository ``` +// create branch to work +git checkout -b [branch_name] -This will start `geth` in snap-sync mode with a DB memory allowance of 1GB, as the -above command does. It will also create a persistent volume in your home directory for -saving your blockchain as well as map the default ports. There is also an `alpine` tag -available for a slim version of the image. - -Do not forget `--http.addr 0.0.0.0`, if you want to access RPC from other containers -and/or hosts. By default, `geth` binds to the local interface and RPC endpoints are not -accessible from the outside. - -### Programmatically interfacing `geth` nodes - -As a developer, sooner rather than later you'll want to start interacting with `geth` and the -Ethereum network via your own programs and not manually through the console. To aid -this, `geth` has built-in support for a JSON-RPC based APIs ([standard APIs](https://ethereum.github.io/execution-apis/api-documentation/) -and [`geth` specific APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc)). -These can be exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based -platforms, and named pipes on Windows). - -The IPC interface is enabled by default and exposes all the APIs supported by `geth`, -whereas the HTTP and WS interfaces need to manually be enabled and only expose a -subset of APIs due to security reasons. These can be turned on/off and configured as -you'd expect. - -HTTP based JSON-RPC API options: - - * `--http` Enable the HTTP-RPC server - * `--http.addr` HTTP-RPC server listening interface (default: `localhost`) - * `--http.port` HTTP-RPC server listening port (default: `8545`) - * `--http.api` API's offered over the HTTP-RPC interface (default: `eth,net,web3`) - * `--http.corsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced) - * `--ws` Enable the WS-RPC server - * `--ws.addr` WS-RPC server listening interface (default: `localhost`) - * `--ws.port` WS-RPC server listening port (default: `8546`) - * `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`) - * `--ws.origins` Origins from which to accept WebSocket requests - * `--ipcdisable` Disable the IPC-RPC server - * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,txpool,web3`) - * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) - -You'll need to use your own programming environments' capabilities (libraries, tools, etc) to -connect via HTTP, WS or IPC to a `geth` node configured with the above flags and you'll -need to speak [JSON-RPC](https://www.jsonrpc.org/specification) on all transports. You -can reuse the same connection for multiple requests! - -**Note: Please understand the security implications of opening up an HTTP/WS based -transport before doing so! Hackers on the internet are actively trying to subvert -Ethereum nodes with exposed APIs! Further, all browser tabs can access locally -running web servers, so malicious web pages could try to subvert locally available -APIs!** +// rebase upstream commits into branch +git rebase upstream/master -i -### Operating a private network +// staging and commit +git add . +git commit -m "message" -Maintaining your own private network is more involved as a lot of configurations taken for -granted in the official networks need to be manually set up. +// push +git push -u origin [branch_name] -#### Defining the private genesis state - -First, you'll need to create the genesis state of your networks, which all nodes need to be -aware of and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`): - -```json -{ - "config": { - "chainId": , - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0 - }, - "alloc": {}, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x20000", - "extraData": "", - "gasLimit": "0x2fefd8", - "nonce": "0x0000000000000042", - "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x00" -} -``` - -The above fields should be fine for most purposes, although we'd recommend changing -the `nonce` to some random value so you prevent unknown remote nodes from being able -to connect to you. If you'd like to pre-fund some accounts for easier testing, create -the accounts and populate the `alloc` field with their addresses. - -```json -"alloc": { - "0x0000000000000000000000000000000000000001": { - "balance": "111111111" - }, - "0x0000000000000000000000000000000000000002": { - "balance": "222222222" - } -} +// go to upstream repo(https://github.com/orakle-opensource/EIP_opensource.git) and create pull request ``` - -With the genesis state defined in the above JSON file, you'll need to initialize **every** -`geth` node with it prior to starting it up to ensure all blockchain parameters are correctly -set: - -```shell -$ geth init path/to/genesis.json +3. After merging pull request ``` - -#### Creating the rendezvous point - -With all nodes that you want to run initialized to the desired genesis state, you'll need to -start a bootstrap node that others can use to find each other in your network and/or over -the internet. The clean way is to configure and run a dedicated bootnode: - -```shell -$ bootnode --genkey=boot.key -$ bootnode --nodekey=boot.key +// checkout master and pull upstream commits +git checkout master +git pull upstream master ``` -With the bootnode online, it will display an [`enode` URL](https://ethereum.org/en/developers/docs/networking-layer/network-addresses/#enode) -that other nodes can use to connect to it and exchange peer information. Make sure to -replace the displayed IP address information (most probably `[::]`) with your externally -accessible IP to get the actual `enode` URL. - -*Note: You could also use a full-fledged `geth` node as a bootnode, but it's the less -recommended way.* +### If branch -#### Starting up your member nodes +the case for working by creating branch on our repository -With the bootnode operational and externally reachable (you can try -`telnet ` to ensure it's indeed reachable), start every subsequent `geth` -node pointed to the bootnode for peer discovery via the `--bootnodes` flag. It will -probably also be desirable to keep the data directory of your private network separated, so -do also specify a custom `--datadir` flag. - -```shell -$ geth --datadir=path/to/custom/data/folder --bootnodes= ``` +// create branch -> commit -> push +git checkout -b [branch_name] +git add . | git commit -m "message" +git push -u origin [branch_name] -*Note: Since your network will be completely cut off from the main and test networks, you'll -also need to configure a miner to process transactions and create new blocks for you.* - -#### Running a private miner - - -In a private network setting a single CPU miner instance is more than enough for -practical purposes as it can produce a stable stream of blocks at the correct intervals -without needing heavy resources (consider running on a single thread, no need for multiple -ones either). To start a `geth` instance for mining, run it with all your usual flags, extended -by: - -```shell -$ geth --mine --miner.threads=1 --miner.etherbase=0x0000000000000000000000000000000000000000 +// go to repo and create pull request ``` -Which will start mining blocks and transactions on a single CPU thread, crediting all -proceedings to the account specified by `--miner.etherbase`. You can further tune the mining -by changing the default gas limit blocks converge to (`--miner.targetgaslimit`) and the price -transactions are accepted at (`--miner.gasprice`). - -## Contribution - -Thank you for considering helping out with the source code! We welcome contributions -from anyone on the internet, and are grateful for even the smallest of fixes! - -If you'd like to contribute to go-ethereum, please fork, fix, commit and send a pull request -for the maintainers to review and merge into the main code base. If you wish to submit -more complex changes though, please check up with the core devs first on [our Discord Server](https://discord.gg/invite/nthXNEv) -to ensure those changes are in line with the general philosophy of the project and/or get -some early feedback which can make both your efforts much lighter as well as our review -and merge procedures quick and simple. - -Please make sure your contributions adhere to our coding guidelines: - - * Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) - guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). - * Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) - guidelines. - * Pull requests need to be based on and opened against the `master` branch. - * Commit messages should be prefixed with the package(s) they modify. - * E.g. "eth, rpc: make trace configs optional" - -Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/geth-developer/dev-guide) -for more details on configuring your environment, managing project dependencies, and -testing procedures. - -### Contributing to geth.ethereum.org - -For contributions to the [go-ethereum website](https://geth.ethereum.org), please checkout and raise pull requests against the `website` branch. -For more detailed instructions please see the `website` branch [README](https://github.com/ethereum/go-ethereum/tree/website#readme) or the -[contributing](https://geth.ethereum.org/docs/developers/geth-developer/contributing) page of the website. - ## License The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the From 1b5b0b8b86f6bfd0d1181fd0bc568b5e311a1a1a Mon Sep 17 00:00:00 2001 From: siddharth0a Date: Fri, 26 Apr 2024 15:47:27 +0900 Subject: [PATCH 23/23] EIPs: add eip-4844.md --- EIPs/eip-4844.md | 236 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 EIPs/eip-4844.md diff --git a/EIPs/eip-4844.md b/EIPs/eip-4844.md new file mode 100644 index 000000000000..22504127068f --- /dev/null +++ b/EIPs/eip-4844.md @@ -0,0 +1,236 @@ +# EIP-4844: Shard Blob Transactions +샤드 블롭 트랜잭션은 이더리움의 데이터 가용성을 간단하고, 향후 호환가능한 방식으로 확장합니다. + +## Abstract +새로운 트랜잭션 형식인 "블롭-운반 트랜잭션(Blob-carrying transactions)"을 도입하였습니다. 이 트랜잭션은 EVM 실행에서 직접 접근할 수 없는 대량의 데이터를 포함하고 있으며, 완전한 샤딩(full sharding)과 호환되도록 설계되었습니다. + +## Motivation +이더리움은 현재 높은 트랜잭션 수수료로 인해 어려움을 겪고 있습니다. 이 문제를 해결하기 위한 가장 유망한 솔루션은 롤업(Rollup)이라는 기술입니다. + +롤업은 여러 트랜잭션을 하나로 묶어 이더리움 메인넷(L1)에 제출하는 방식으로 작동합니다. 이를 통해 트랜잭션 처리량을 늘리고 수수료를 낮출 수 있습니다. 대표적인 롤업 솔루션으로는 Optimism, Arbitrum, ZK롤업 등이 있습니다. 이들은 L1 대비 3~100배 가량 낮은 수수료를 제공합니다. + +그러나 롤업도 한계가 있습니다. 근본적인 확장성 문제를 해결하기 위해서는 데이터 샤딩이라는 기술이 필요합니다. 데이터 샤딩은 이더리움 블록체인을 여러 조각(샤드)으로 나누어 병렬 처리하는 것을 의미합니다. 각 샤드는 블록당 16MB의 데이터를 처리할 수 있어, 롤업이 사용할 수 있는 데이터 공간이 크게 늘어납니다. + +하지만 데이터 샤딩을 완벽하게 구현하려면 오랜 시간이 걸립니다. 그래서 이 글에서 언급된 EIP(이더리움 개선 제안)는 데이터 샤딩의 장점을 일부 가져오면서도, 빠르게 구현할 수 있는 절충안을 제시합니다. + +이 EIP는 샤딩에 사용될 새로운 트랜잭션 형식을 도입합니다. 이 트랜잭션은 실제로 샤딩되지는 않지만, 마치 샤딩된 것처럼 동작합니다. 트랜잭션 데이터는 비콘 체인에 포함되며, 모든 검증자 노드가 다운로드합니다. 다만 일정 시간이 지나면 삭제될 수 있습니다. + +이 방식을 통해 롤업은 완전한 데이터 샤딩에 준하는 효과를 얻을 수 있습니다. 다만 트랜잭션 크기에 제한이 있어, 0.375MB를 목표로 하고 최대 0.75MB까지 허용됩니다. + +이 EIP는 데이터 샤딩이 구현되기 전까지 이더리움 확장성 문제를 완화하는 데 도움이 될 것입니다. 롤업과 함께 사용될 경우, 사용자는 더 낮은 수수료로 더 많은 트랜잭션을 처리할 수 있게 됩니다. + + +## Theoretical explain +### 주요 변경사항 및 목표 +- Blob-carrying 트랜잭션 유형을 도입합니다. 이는 L2롤업 데이터를 더 저렴한 비용으로 이더리움 메인넷에 게시할 수 있도록 합니다. +- 블록당 포함된 블롭의 크기와 수를 제한하여, 이더리움 노드 계산 및 저장 요구사항이 급격하게 증가하지 않도록 하여 분산화를 유지합니ㅏ. + +### 더 저렴한 gas비로 트랜잭션을 처리할 수 있는 이유 +Blob 데이터는 EVM에 접근할 수 없기 떄문, blob 데이터에 대한 참조만 EVM에 액세스 할 수 있기 때문입니다. + +### 블롭 구조 +![alt text]() +블롭은 블록과 나란히 달리는 ‘사이드카’ 로 상상가능합니다. +블롭 자체는 블록에 들어가지 않지만, 관련 참조(각 블롭에 고유하고, 각 블롭을 블롭 운반 트랜잭션에 연결할 수 있는 참조)만 들어가고, fraud proof가 실행될때 calldata 형태로 전환되어 사용됩니다. + +각 블롭에 포함된 L2 트랜잭션은 EVM에서 실행될 수 없고, 이더리움의 consensus layer에서 4096에포크 혹은 18일 동안만 저장됩니다. + +### 블롭 마켓 +블록당 0~6개의 블롭 등록, 3개를 목표로 합니다. +블록에 3개이상의 블롭이 연결되면 블롭의 가격이 더 비싸지고, 반대의 경우블롭 가격은 더 저렴해집니다. + +### 블롭 만료 +블롭 데이터는 4096에포크 18일 동안 사용가능하고, 만료 후에는 블롭 내의 데이터를 consensus client에서 검색할 수 없습니다. 이전 존재에 대한 증거만 KZG형태로 메인넷에 남게 됩니다. + +### 블롭 크기 +블록에 연결된 각 블롭은 128Kb의 임시 데이터를 보유합니다. 블롭이 완전히 채워지지 않을 수 있으며 이때도 블롭의 크기는 항상 128kb를 유지합니다. +![alt text]() +현재 블록크기 1.875Mb => 블롭 6개 연결시 0.75Mb 추가 +=> 블록 크기 40% 늘릴 수 있습니다. + + +## Specification +### 블롭 트랜잭션 +EIP-4844에서는 EIP-2718의 새로운 타입 “blob transaction”을 제안하였습니다. + +Blob transaction의 TransactionPayloadBody: +[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_blob_gas, blob_versioned_hashes, y_parity, r, s] + +새롭게 추가된 항목: max_fee_per_blob_gas, blob_versioned_hashes(kzg_to_versioned_hash의 해시 결과 리스트) + +EIP-1559를 계승한 항목: Chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, value, data, access_list + +변경된 항목: to(nil이 되어서는 안되며, 반드시 20byte의 address) – blob transaction은 create transaction이 될 수 없음을 의미합니다. + +### 서명 +y_parity, r, s는 다음과 같이 secp256k1 서명으로 생성됩니다. + +keccak256(BLOB_TX_TYPE || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_blob_gas, blob_versioned_hashes])). + +### Header extension +현재 헤더 인코딩에 더해 두개의 새로운 64bit unsigned inter field가 추가됩니다. + +blob_gas_used: 블록 내의 트랜잭션에 의해 소모된 블롭가스의 총량 + +excess_blob_gas: 블록 이전에 목표를 초과하여 소비된 블롭 가스의 누적 총량. + +### Gas accounting +블롭 가스는 새로운 타입의 가스입니다. 기존의 가스와는 독립적이고, EIP-1559비슷하게 자체적인 targeting rule을 따릅니다. excess_blob_gas 헤더필드로 영구 데이터를 저장하고, 이를 사용해 blob base fee를 계산합니다. 현재, 블롭은 블롭 가스에 의해서만 가격이 결정됩니다. + +```python +def calc_blob_fee(header: Header, tx: Transaction) -> int: + return get_total_blob_gas(tx) * get_base_fee_per_blob_gas(header) + +def get_total_blob_gas(tx: Transaction) -> int: + return GAS_PER_BLOB * len(tx.blob_versioned_hashes) + +def get_base_fee_per_blob_gas(header: Header) -> int: + return fake_exponential( + MIN_BASE_FEE_PER_BLOB_GAS, + header.excess_blob_gas, + BLOB_BASE_FEE_UPDATE_FRACTION + ) +``` + +블록 유효성 조건에 블롭 가스 검사도 포함되었습니다. +calc_blob_fee로 계산된 실제 blob_fee는 거래 실행 전 보낸 사람 잔액에서 차감되어 소각되며, 거래 실패시 환불되지 않습니다. + +### Versioned hash를 위한 Opcode +BLOBHASH 명령어는 스택에서 버전 해시를 읽어오는 기능을 제공합니다. 이 명령어를 사용하면 블록체인에 저장된 블롭(Blob) 데이터의 해시값을 쉽게 얻을 수 있습니다. +명령어의 동작 방식은 다음과 같습니다: + +1. 스택의 맨 위에서 인덱스 값(index)을 빅 엔디언(Big-endian) 방식의 uint256 형식으로 읽어옵니다. +2. 읽어온 index가 현재 트랜잭션의 블롭 버전 해시 리스트(tx.blob_versioned_hashes)의 길이보다 작은 경우: +- tx.blob_versioned_hashes[index] 값을 스택의 맨 위에 놓습니다. +- 이는 해당 인덱스에 해당하는 블롭의 버전 해시값을 의미합니다. + +3. 읽어온 index가 블롭 버전 해시 리스트의 길이 이상인 경우: +- 0으로 채워진 bytes32 값을 스택의 맨 위에 놓습니다. +- 이는 해당 인덱스에 해당하는 블롭이 존재하지 않음을 나타냅니다. + +4. BLOBHASH 명령어를 실행하는 데에는 HASH_OPCODE_GAS만큼의 가스 비용이 소모됩니다. + +이 명령어를 통해 스마트 컨트랙트는 트랜잭션에 포함된 블롭 데이터의 버전 해시를 손쉽게 확인할 수 있습니다. 이는 블롭 데이터의 무결성을 검증하거나, 블롭 데이터를 참조하는 다른 연산에서 활용될 수 있습니다. + +### 포인트 평가 사전 컴파일 +POINT_EVALUATION_PRECOMPILE_ADDRESS라는 프리컴파일을 추가합니다. 이는 blob이 주어진 point에서 평가되었다고 주장하는 KZG proof를 검증합니다. 해당 사전 컴파일에는 POINT_EVALUATION_PRECOMPILE_GAS가 들고, 다음 함수가 실행됩니다. + +```python +def point_evaluation_precompile(input: Bytes) -> Bytes: + """ + Verify p(z) = y given commitment that corresponds to the polynomial p(x) and a KZG proof. + Also verify that the provided commitment matches the provided versioned_hash. + """ + # The data is encoded as follows: versioned_hash | z | y | commitment | proof | with z and y being padded 32 byte big endian values + assert len(input) == 192 + versioned_hash = input[:32] + z = input[32:64] + y = input[64:96] + commitment = input[96:144] + proof = input[144:192] + + # Verify commitment matches versioned_hash + assert kzg_to_versioned_hash(commitment) == versioned_hash + + # Verify KZG proof with z and y in big endian format + assert verify_kzg_proof(commitment, z, y, proof) + + # Return FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values + return Bytes(U256(FIELD_ELEMENTS_PER_BLOB).to_be_bytes32() + U256(BLS_MODULUS).to_be_bytes32()) +``` + +### 합의 레이어 검증 +Blobs는 비콘 블록 본문에 직접 포함되지 않고, 별도의 "sidecar"로 전파됩니다. 이를 통해 향후 데이터 증가에 대한 호환성을 유지할 수 있습니다. +is_data_available() 함수는 전체 샤딩 시스템에서 데이터 가용성 샘플링(DAS)으로 대체될 수 있어, 모든 비콘 노드가 모든 블롭을 다운로드하는 것을 피할 수 있습니다. +합의 계층은 데이터 가용성을 위해 블롭을 유지하는 역할을 담당하며, 실행 계층은 이에 관여하지 않습니다. + +ethereum/consensus-specs 저장소는 이 EIP와 관련된 다음과 같은 합의 계층 변경사항을 정의합니다: +• 비콘 체인: 업데이트된 비콘 블록을 처리하고 블롭의 가용성을 확인합니다. +• P2P 네트워크: 업데이트된 비콘 블록 유형과 새로운 블롭 사이드카를 전파하고 동기화합니다. +• 정직한 검증자: 블롭이 포함된 비콘 블록을 생성하고, 관련 블롭 사이드카에 서명하고 게시합니다. + +### 실행 레이어 검증 +```python +def validate_block(block: Block) -> None: + ... + + # check that the excess blob gas was updated correctly + assert block.header.excess_blob_gas == calc_excess_blob_gas(block.parent.header) + + blob_gas_used = 0 + + for tx in block.transactions: + ... + + # modify the check for sufficient balance + max_total_fee = tx.gas * tx.max_fee_per_gas + if get_tx_type(tx) == BLOB_TX_TYPE: + max_total_fee += get_total_blob_gas(tx) * tx.max_fee_per_blob_gas + assert signer(tx).balance >= max_total_fee + + ... + + # add validity logic specific to blob txs + if get_tx_type(tx) == BLOB_TX_TYPE: + # there must be at least one blob + assert len(tx.blob_versioned_hashes) > 0 + + # all versioned blob hashes must start with VERSIONED_HASH_VERSION_KZG + for h in tx.blob_versioned_hashes: + assert h[0] == VERSIONED_HASH_VERSION_KZG + + # ensure that the user was willing to at least pay the current blob base fee + assert tx.max_fee_per_blob_gas >= get_base_fee_per_blob_gas(block.header) + + # keep track of total blob gas spent in the block + blob_gas_used += get_total_blob_gas(tx) + + # ensure the total blob gas spent is at most equal to the limit + assert blob_gas_used <= MAX_BLOB_GAS_PER_BLOCK + + # ensure blob_gas_used matches header + assert block.header.blob_gas_used == blob_gas_used +``` + +### Networking + +블록 트랜잭션은 두가지 네트워크 표현을 가집니다. +1. 블록 트랜잭션 전파(트랜잭션이 아직 블록에 포함되지 않은 상태) +트랜잭션 전파(Transaction Gossip) 응답: PooledTransactions 에서는 EIP-2718의 TransactionPayload 가 다음과 같이 래핑됩니다. + +rlp([tx_payload_body, blobs, commitments, proofs]) + +tx_payload_body: 표준 EIP-2718 블록 트랜잭션의 TransactionPayloadBody + +blobs: Blob 항목의 리스트 + +commitments: 해당 blobs의 KZGCommitment 리스트 + +proofs: 해당 blobs와 commitments의 KZGProof 리스트 + + +즉 트랜잭션 데이터와 함께 추가적인 정보(blobs, commitments, proofs)를 같이 보내서, 받는 사람이 트랜잭션이 유효한지 확인할 수 있게 합니다. + +노드는 tx_payload_body를 검증하고, 래핑된 데이터를 확인해야합니다. 이를 위해 다음과 같이 확인합니다. + +• tx_payload_body.blob_versioned_hashes, blobs, commitments, proofs의 개수가 동일해야 합니다. + +• KZG commitments는 버전 해시로 해시되어야 합니다. 즉, kzg_to_versioned_hash(commitments[i]) == tx_payload_body.blob_versioned_hashes[i] + +• KZG commitments는 해당 blobs와 proofs와 일치해야 합니다. (참고: 이는 verify_blob_kzg_proof_batch를 사용하여 최적화할 수 있습니다.) + + +2. 블록 데이터 요청(새로운 블록이 만들어지면 노드들은 그 블록에 포함된 트랜잭션 데이터를 요청함) +블록 본문 검색 응답(BlockBodies)에서는 표준 EIP-2718 블록 트랜잭션 TransactionPayload가 사용됩니다. + +노드는 블록 트랜잭션을 피어에게 자동을 브로드캐스트 하지 않고, 대신 해당 트랜잭션은 NewPooledTransactionHashes 메시지로 알려지고, GetPooledTransactions로 수동으로 요청할 수 있습니다. + +쉽게 말해서, 1은 "새로운 트랜잭션을 알리는 단계"이고, 2는 "블록에 포함된 트랜잭션 데이터를 요청하는 단계"입니다. +1에서는 트랜잭션의 유효성을 확인하기 위해 추가 데이터가 필요하지만, 2에서는 이미 유효성을 검증하고, 블록에 포함된 트랜잭션이기 때문에 추가 데이터 없이 전송됩니다. + + +## Reference +공식문서: https://eips.ethereum.org/EIPS/eip-4844 +deneb module: https://github.com/ethereum/consensus-specs/tree/86fb82b221474cc89387fa6436806507b3849d88/specs/deneb +cancun module: https://github.com/ethereum/execution-spec-tests/tree/1983444bbe1a471886ef7c0e82253ffe2a4053e1/tests/cancun/eip4844_blobs +image 및 consensys report: https://consensys.io/blog/ethereum-evolved-dencun-upgrade-part-5-eip-4844 \ No newline at end of file