Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env rdmd
- enum Target = ulong.max >> 12;
- struct Header {
- private:
- ulong prev;
- uint nonce;
- uint miner;
- public:
- @property minerId() const {
- return miner;
- }
- this(Chain c, uint miner) {
- this.miner = miner;
- this(c, this);
- }
- this(Chain c, Header h) {
- this.prev = c.getBestBlockhash();
- this.nonce = h.nonce;
- this.miner = h.miner;
- }
- ulong hash() const {
- import std.digest.murmurhash;
- MurmurHash3!(128, 64) hasher;
- hasher.put(*cast(ubyte[8]*) &prev);
- hasher.put(*cast(ubyte[4]*) &nonce);
- hasher.put(*cast(ubyte[4]*) &miner);
- auto r = hasher.finish();
- return *cast(ulong*) &r;
- }
- bool isValid() const {
- return hash() <= Target;
- }
- bool tryNextNonce() {
- nonce++;
- return isValid();
- }
- }
- struct Chain {
- private:
- const(Header)[] headers;
- public:
- @property height() const {
- return headers.length;
- }
- @property asHeaderArray() const {
- return headers;
- }
- bool maybeReorg(Chain newChain) {
- if (newChain.height <= height) {
- return false;
- }
- this = newChain;
- return true;
- }
- ulong getBestBlockhash() const {
- if (height == 0) {
- return 0;
- }
- return headers[$ - 1].hash();
- }
- void add(Header h) in {
- assert(h.prev == getBestBlockhash());
- } body {
- headers ~= h;
- }
- }
- Chain publicChain;
- struct Miner {
- private:
- Chain privateChain;
- Header nextHeader;
- uint blockFound;
- uint forkHeight;
- bool isHonest;
- public:
- @property id() const {
- return nextHeader.minerId;
- }
- this(uint id, bool isHonest) {
- privateChain = publicChain;
- nextHeader = Header(privateChain, id);
- blockFound = 0;
- forkHeight = 0;
- this.isHonest = isHonest;
- }
- private:
- void addHeader(Header h) {
- privateChain.add(h);
- nextHeader = Header(privateChain, h);
- }
- bool readPublicChain() {
- // We assume gamma = 0, so we never try to race.
- if (!privateChain.maybeReorg(publicChain)) {
- return false;
- }
- // We reorged, we need to prepare a new header.
- forkHeight = cast(uint) privateChain.height;
- nextHeader = Header(privateChain, nextHeader);
- return true;
- }
- bool publishPrivateChain() {
- if (!isHonest) {
- return publishSelfishChain();
- }
- // The honest miner publish blocks as soon one is found.
- return forcePublishPrivateChain();
- }
- bool publishSelfishChain() {
- // If we are leading by 1 block, and have a private chain of 2 blocks
- // or more, then we publish it, causing the honest miner to reorg.
- auto privateBlockCount = privateChain.height - forkHeight;
- auto leadBlockCount = privateChain.height - publicChain.height;
- if (privateBlockCount >= 2 && leadBlockCount == 1) {
- import std.stdio;
- writeln(
- "\tPublishing selfish chain of height ", privateChain.height,
- " vs public chain height ", publicChain.height,
- );
- if (publicChain.maybeReorg(privateChain)) {
- forkHeight = cast(uint) privateChain.height;
- return true;
- }
- }
- return false;
- }
- public:
- void round() {
- // Check the public chain and adjust.
- readPublicChain();
- if (!isHonest) {
- // We mayb be facing a situation where the
- // honest miner found a block and we need
- // to have it reorg in out chain.
- publishSelfishChain();
- }
- if (!nextHeader.tryNextNonce()) {
- // PoW failed, we are done.
- return;
- }
- blockFound++;
- addHeader(nextHeader);
- import std.stdio;
- writeln(
- "miner ", id,
- " found one block at height ", privateChain.height,
- " vs public chain height ", publicChain.height,
- );
- // We have a new header, we need to publish it.
- publishPrivateChain();
- }
- bool forcePublishPrivateChain() const {
- return publicChain.maybeReorg(privateChain);
- }
- void report() const {
- uint blockWon = 0;
- foreach (h; publicChain.asHeaderArray) {
- if (h.minerId == id) {
- blockWon++;
- }
- }
- import std.stdio;
- writeln(
- "Miner id: ", nextHeader.miner, '\t',
- "Block found: ", blockFound, '\t',
- "Block won: ", blockWon, '\t',
- );
- }
- }
- void main() {
- // Setup miners.
- auto honest = Miner(0, true);
- auto selfish = Miner(1, false);
- while (publicChain.height < 65536) {
- honest.round();
- selfish.round();
- honest.round();
- selfish.round();
- honest.round();
- }
- honest.forcePublishPrivateChain();
- selfish.forcePublishPrivateChain();
- import std.stdio;
- writeln("Total block found: ", publicChain.height);
- honest.report();
- selfish.report();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement