minesim

所属分类:加密货币
开发工具:GO
文件大小:12KB
下载次数:0
上传日期:2021-11-08 05:21:33
上 传 者sh-1993
说明:  加密货币POW挖矿模拟器
(cryptocurrency POW mining simulator)

文件列表:
blockint-count.py (545, 2021-11-08)
blockint.py (366, 2021-11-08)
minesim.go (12164, 2021-11-08)
network (413, 2021-11-08)

# minesim -- Cryptocurrency POW mining simulator This program simulates a POW mining network, such as Bitcoin or Zcash (or many others). ## License This software is released under the terms of the MIT license, see https://opensource.org/licenses/MIT. ## Acknowledgment This work has been supported by a Brink grant (https://brink.dev/). ## Introduction [TABConf2021 presentation slides](https://docs.google.com/presentation/d/e/2PACX-1vTvKsjLbYmbURJUkPiXq-u4rrSGcby6cdDGDxPGDILixRptlHcrqBWbHtSadtxjr-ki2sCgxkrLnf_N/pub) Like any simulator, this one abstracts away a huge amount of stuff (if it didn't, it wouldn't be a simulator, it would be the thing itself). It's a single executable written in Go. It can simulate the generation of many thousands of blocks per second of real CPU time. The purpose of this simulator is to investigate how block relay delays (network messages and block verification) can cause miners to not be mining on the best chain, as discussed here: - https://podcast.chaincode.com/2020/03/12/matt-corallo-6.html - https://youtu.be/RguZ0_nmSPw?t=752 It simulates: - the passage of time; the units of time are arbitrary (but seconds seems to work well) - random block discovery (mining) according to (realistic) Poisson distribution - a configurable set of peer mining nodes, each with a specified hash power - configurable peer network topology (not necessarily fully-connected) - simple block forwarding (relaying to peers) - message-passing latency from each peer to its peers - chain splits (reorgs, stale blocks) It does not simulate: - actual POW computation (hashing) - transactions - real block forwarding (https://bitcoin.org/en/p2p-network-guide#block-broadcasting) - Byzantine (faulty or malicious) behaviors - hard or soft forks (changing the validity rules) - initial block download (IBD, initial sync) - non-mining nodes - miners arriving and leaving - difficulty adjustment - variable block rewards over time (4-year halvings) - network message loss, network partitions, sybil or eclipse attacks - randomly-varying message latencies (this wouldn't be hard to do) - mining pools (although the "miner" entities here could be considered to be pools) ## Configuration file The configuration file consists of one line per miner with whitespace-separated tokens, specifying - miner identifier (string) - its hashrate (floating point) - a list of peers, each is a pair of: - miner id (string) - relay latency (floating point) Empty lines and lines beginning with `# ` are ignored. The miners' hashrate has arbitrary units; what matters is the value of each to the total network hashrate. In other words, you could scale all hashrates by a constant factor and the simulation wouldn't change. Peer specifications are one-way: If miner A lists miner B as a peer, A sends to B but that doesn't allow B to send to A; that must be specified explicitly. Each peer must have at least one *inbound* connection (another peer listing a connection to it), otherwise it won't receive any blocks and will mine on it's own chain for the entire run. This behaviour will manifest itself by returning `NaN` for the "blocks" and "stale" fields in the results table. ## Building, running, and startup To build: `go build minesim.go` To run: "`./minesim` _options_" or "`go run minesim.go` _options_" Available options (`./minesim -help`): - `-f` (string) File -- network configuration, default `./network` - `-t` (boolean) Tracing -- shows each execution step as a line to standard output - `-i` (integer32) Interval -- the average block interval, units are arbitrary but usually interpreted as seconds - `-h` (integer***) Height -- stop simulation at this height - `-s` (integer***) Seed -- for the random number generator; default is 0; specify -1 to use wall-clock time ## Block relay The only type of message that peers send to each other is block-forwarding. These happen automatically; there are no request messages. There are two sources of knowledge of a new block (which are always immediately forwarded to all known peers): blocks that the peer received from another peer, and blocks that the sending peer mined itself. Miners always act honestly. The miners begin mining on the "genesis" block, which has height zero. When a miner solves a block, it relays it to its peers by "sending" a message with the configured peer latency. When a miner hears about a block from a peer, it checks whether the block it's currently mining on has the same or higher height; if so, it ignores the received block (does not forward it, because it's already forwarded the as-good or better block that it's mining on). If, on the other hand, the received block is better than the one it's working on, it switches to it, that is, starts mining on top of it. It also immediately relays this block to its peers. Block verification is not modeled explicitly, but can be considered as part of the block relay latency. (If you want to model blocks that take a long time to verify, you may want to increase the peer latencies.) Peer connections are one-way; if you want two peers to be able to forward blocks to each other, each must list the other as a peer. The latency in each direction can be different. The network file in this repository shows an example of a configuration that models two groups of closely-connected miners, one group in *** and the other in Iceland. The latency within the groups is low, but between groups is high. The `-i` interval argument simulates the given block time, but it may end up greater because of losses due to chain splits (mined blocks that end up being stale blocks). The real Bitcoin network's difficulty adjustment algorithm corrects for this, but this simulator doesn't include difficulty adjustment. ## Default configuration The file `network` (included in the repo) has the default configuration: ``` # two groups of miners far apart (the times must include block verification) china-asic 500 china-gateway 0.5 china-gpu 0.2 china-gpu 80 china-gateway 0.5 china-asic 0.2 portable 60 china-gateway 0.5 china-gateway 20 china-asic 0.5 china-gpu 0.5 iceland-gw 12 portable 0.5 iceland-gw 500 china-gateway 15 iceland2 0.5 iceland2 600 iceland-gw 0.5 ``` This is a trivial, slightly realistic configuration, but illustrates the concepts. Each line described a miner (empty lines or those beginning with `# ` are ignored) and consists of whitespace-separated tokens. The first token is the name of the miner, the second is its relative hashrate. The remainder of the line consists of pairs of peer and latency to send to that peer. Again, the time units are arbitrary, but seconds works well. Two-way peer communication paths must be configured explicitly. This configuration imagines mining centers in *** and Iceland, and the block relay times are much less within each center than between centers. This is highly arbitrary and made-up; it would be interesting to create a configuration file that matches the real network. (The simulator scales well; it's reasonable to configure many thousands of miners.) ## Results At the end of the run, the simulator shows various statistics, for example, with the default network configuration: ``` $ go run minesim.go seed-arg 0 block-interval-arg 600 stopheight-arg 1000000 total-hashrate-arg 1760 mined-blocks 1011317 total-simtime 607746829.335 ave-block-time 607.747 stale-blocks 11318 stale-rate 1.12% max-reorg-depth 3 miner china-asic hashrate-arg 500 28.41% blocks 28.19% stale-rate 1.81% miner china-gpu hashrate-arg 80 4.55% blocks 4.55% stale-rate 1.89% miner portable hashrate-arg 60 3.41% blocks 3.38% stale-rate 1.90% miner china-gateway hashrate-arg 20 1.14% blocks 1.13% stale-rate 1.78% miner iceland-gw hashrate-arg 500 28.41% blocks 28.46% stale-rate 0.69% miner iceland2 hashrate-arg 600 34.09% blocks 34.28% stale-rate 0.70% ``` (The `*-arg` values are arguments to the simulation, not computed values.) The per-miner output shows the hashrate argument (just repeating what's in the network configuration file), the percentage of best-chain blocks that this miner earned, and the stale block rate, which is the percentage of blocks mined _by this miner_ that did not end up in the best chain. (This is not the fraction of overall stale blocks generated by this miner.) ## Motivations for writing this simulator This simulator hopes to make cryptocurrency developers aware of the dangers of reducing block interval or increasing block size. Doing either of these increases the "gravitational pull" that miners and pools experience to be near other centers of high hashrate. In physics, gravity is a weak force -- many other forces can overcome it -- but it is a force. Mining is an extremely competitive industry with low barriers to entry and razor-thin profit margins, so if a miner or a mining pool can physically locate near other miners, its 2 percent profit may double! Geographic centralization makes attacking the network easier by, for example, governments, who can shut down a large fraction of mining power that is within their jurisdiction. ## Trace output Specifying `-t` (enable tracing) on the command line causes the simulator to print a line for each execution step, and it's fun to see these details. Here's the beginning of the output using the default arguments: ``` $ go run minesim.go -t 0.000 china-asic start-on 1000 height 0 mined 0 credit 0 solve 1959.96 0.000 china-gpu start-on 1000 height 0 mined 0 credit 0 solve 37249.50 0.000 portable start-on 1000 height 0 mined 0 credit 0 solve 19224.70 0.000 china-gateway start-on 1000 height 0 mined 0 credit 0 solve 30399.34 0.000 iceland-gw start-on 1000 height 0 mined 0 credit 0 solve 1167.42 0.000 iceland2 start-on 1000 height 0 mined 0 credit 0 solve 2043.34 1167.419 iceland-gw mined-newid 1001 on 1000 height 1 1167.419 iceland-gw start-on 1001 height 1 mined 1 credit 0 solve 143.38 1167.919 iceland2 received-switch-to 1001 1167.919 iceland2 start-on 1001 height 1 mined 0 credit 0 solve 299.58 1182.419 china-gateway received-switch-to 1001 1182.419 china-gateway start-on 1001 height 1 mined 0 credit 0 solve 5385.55 1182.919 china-asic received-switch-to 1001 1182.919 china-asic start-on 1001 height 1 mined 0 credit 0 solve 756.05 1182.919 china-gpu received-switch-to 1001 1182.919 china-gpu start-on 1001 height 1 mined 0 credit 0 solve 9557.39 1182.919 portable received-switch-to 1001 1182.919 portable start-on 1001 height 1 mined 0 credit 0 solve 29569.32 1310.803 iceland-gw mined-newid 1002 on 1001 height 2 1310.803 iceland-gw start-on 1002 height 2 mined 2 credit 0 solve 509.28 ``` The first column is the simulated time. At time zero, all six miners start mining on top of block ID 1000 (which is the arbitrary ID of the "genesis block") which has height 0. So far, each miner has mined zero blocks and received credit for zero blocks. (A credit is received when it's certain that a block will be part of the final blockchain.) The number following `solve` is the time it will take for this miner to solve the next block (according to the random Poisson distribution). At time 1167.419, the miner `iceland-gw` mines the first block which gets the next ID (1001, the IDs just increment on each mined block; IDs are globally unique). `iceland-gw` begins mining on top of that block (`start-on 1001`). It also relays the new block to its peer miners. Its peer `iceland2` receives the block quickly and begins to mine on top of it. After about 15 seconds, `china-gateway` receives the block, starts mining on top of it, and relays it to its peers. Searching this trace output for `reorg` is interesting; this shows cases where a miner discovers that a better block that requires it to back up _more_ than one block to get on the best chain. As expected, as block relay times increase or the average block interval decreases in the configuration, deeper reorgs occur. ## Block-interval sample time generators This repository also includes two simple Python programs to generate simulated block intervals based on the Poisson distribution. They have equivalent functionality, but `blockint.py` is much more efficient. Its algorithm is used in the simulator. The other program, `blockint-count.py`, more closely simulates mining by repeatedly attempting to "solve" a block, not by hashing but by generating random numbers. ## Future improvements - Variable (random) message delays - Unreliable network (random dropped messages) - Automatic node creation and peer connection, not just a static network - Nodes dynamically joining and leaving the network - Dynamic network connections (network partitions and healing) - Difficulty adjustment - Forks (hard and soft), chain wipeout - Nonstandard behaviors such as selfish mining ## Exercises, discussion questions - Run minsim with the default configuration (`go run minesim`) - Do miners earn blocks in proportion to their hashrates? - If not, are the differences due to chance? Are the results different if you run with: - Longer simulation (for example, `-h 10000000`) - Different seeds (for example, random seed `-s -1`) - _Note_ The default configuration (the `network` file) sets up two geographic mining areas, *** and Iceland. Each area has some miners (or pools), with the network latency (block propagation delay) being small within each area, and much larger latencies between areas. - See what happens when you change the configuration (`network` file) so that: - All latencies are zero (infinitely fast network) - Latencies between geographic areas increases or decreases - Is lunar mining practical? Martian mining? - Latencies between geographic areas are larger than the block time - A miner is completely isolated from the rest of the network - Why these unexpected results? (Requires some understanding of the simulator implementation) - For each of the variations listed above: - What happens to the overall stale block rate? - How does each miner's blocks won differ from its hashrate? - What happens to the maximum reorg depth seen during the simulation run? - What are the effects of changing the block interval from the default 600 seconds (10 minutes)? - Based on these results, what's your opinion of shortening the block interval (sometimes suggested as a way to make confirmations faster)? - The default configuration file (`network`) specifies a miner called `portable` in *** - What happens to its efficiency (number of stale blocks and percentage of blocks won) if you move this miner from *** to Iceland? - If there are differences, how do you interpret them? - Is the advantage of moving from *** to Iceland affected by the block interval? - If so, what's the effect of block interval on geographic centralization? - Run the simulator with tracing enabled (`-t`, you'll want to pipe its output to a program like `less`) - _Note_ Remember that each block has a unique identifier (its block id), and these begin at 1000 (the genesis block); more than one block (id) can have the same height - Which miner mines the first block (block id 1001)? - How do the other miners react to receiving this block? - When does the first reorg happen? (_hint_ pipe to `less` and search for "reorg") - Briefly explain the sequence of events that caused the reorg - Are reorgs a network-wide phenomenon or a node-specific phenomenon? - Which kinds of miners are more likely to experience reorg events? - Auto-generate a network configuration file with hundreds or thousands of miners, see what happens and whether the simulator scales reasonably. - Does this simulator leave important things out of its model? - _Advanced exercises:_ - Modify the simulator to model the [selfish mining attack](https://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf). - Run the simulator with various network configurations, do you observe the effects of the attack? - Modify the simulator to implement the mitigation proposed by that paper. - Run the simulator, does the mitigation help? - Enhance the simulator to add configurable random "jitter" to the block relay latencies to more closely simulate real networks, see what the effects are.

近期下载者

相关文件


收藏者