Advertisement
Guest User

Untitled

a guest
Apr 9th, 2018
2,002
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 4.48 KB | None | 0 0
  1. #!/usr/bin/env rdmd
  2.  
  3. enum Target = ulong.max >> 12;
  4.  
  5. struct Header {
  6. private:
  7.     ulong prev;
  8.     uint nonce;
  9.     uint miner;
  10.    
  11. public:
  12.     @property minerId() const {
  13.         return miner;
  14.     }
  15.    
  16.     this(Chain c, uint miner) {
  17.         this.miner = miner;
  18.         this(c, this);
  19.     }
  20.    
  21.     this(Chain c, Header h) {
  22.         this.prev = c.getBestBlockhash();
  23.         this.nonce = h.nonce;
  24.         this.miner = h.miner;
  25.     }
  26.    
  27.     ulong hash() const {
  28.         import std.digest.murmurhash;
  29.         MurmurHash3!(128, 64) hasher;
  30.         hasher.put(*cast(ubyte[8]*) &prev);
  31.         hasher.put(*cast(ubyte[4]*) &nonce);
  32.         hasher.put(*cast(ubyte[4]*) &miner);
  33.         auto r = hasher.finish();
  34.         return *cast(ulong*) &r;
  35.     }
  36.    
  37.     bool isValid() const {
  38.         return hash() <= Target;
  39.     }
  40.    
  41.     bool tryNextNonce() {
  42.         nonce++;
  43.         return isValid();
  44.     }
  45. }
  46.  
  47. struct Chain {
  48. private:
  49.     const(Header)[] headers;
  50.    
  51. public:
  52.     @property height() const {
  53.         return headers.length;
  54.     }
  55.    
  56.     @property asHeaderArray() const {
  57.         return headers;
  58.     }
  59.    
  60.     bool maybeReorg(Chain newChain) {
  61.         if (newChain.height <= height) {
  62.             return false;
  63.         }
  64.        
  65.         this = newChain;
  66.         return true;
  67.     }
  68.    
  69.     ulong getBestBlockhash() const {
  70.         if (height == 0) {
  71.             return 0;
  72.         }
  73.        
  74.         return headers[$ - 1].hash();
  75.     }
  76.    
  77.     void add(Header h) in {
  78.         assert(h.prev == getBestBlockhash());
  79.     } body {
  80.         headers ~= h;
  81.     }
  82. }
  83.  
  84. Chain publicChain;
  85.  
  86. struct Miner {
  87. private:
  88.     Chain privateChain;
  89.     Header nextHeader;
  90.     uint blockFound;
  91.     uint forkHeight;
  92.    
  93.     bool isHonest;
  94.    
  95. public:
  96.     @property id() const {
  97.         return nextHeader.minerId;
  98.     }
  99.    
  100.     this(uint id, bool isHonest) {
  101.         privateChain = publicChain;
  102.         nextHeader = Header(privateChain, id);
  103.         blockFound = 0;
  104.         forkHeight = 0;
  105.        
  106.         this.isHonest = isHonest;
  107.     }
  108.    
  109. private:
  110.     void addHeader(Header h) {
  111.         privateChain.add(h);
  112.         nextHeader = Header(privateChain, h);
  113.     }
  114.    
  115.     bool readPublicChain() {
  116.         // We assume gamma = 0, so we never try to race.
  117.         if (!privateChain.maybeReorg(publicChain)) {
  118.             return false;
  119.         }
  120.        
  121.         // We reorged, we need to prepare a new header.
  122.         forkHeight = cast(uint) privateChain.height;
  123.         nextHeader = Header(privateChain, nextHeader);
  124.         return true;
  125.     }
  126.    
  127.     bool publishPrivateChain() {
  128.         if (!isHonest) {
  129.             return publishSelfishChain();
  130.         }
  131.        
  132.         // The honest miner publish blocks as soon one is found.
  133.         return forcePublishPrivateChain();
  134.     }
  135.    
  136.     bool publishSelfishChain() {
  137.         // If we are leading by 1 block, and have a private chain of 2 blocks
  138.         // or more, then we publish it, causing the honest miner to reorg.
  139.         auto privateBlockCount = privateChain.height - forkHeight;
  140.         auto leadBlockCount = privateChain.height - publicChain.height;
  141.         if (privateBlockCount >= 2 && leadBlockCount == 1) {
  142.             import std.stdio;
  143.             writeln(
  144.                 "\tPublishing selfish chain of height ", privateChain.height,
  145.                 " vs public chain height ", publicChain.height,
  146.             );
  147.             if (publicChain.maybeReorg(privateChain)) {
  148.                 forkHeight = cast(uint) privateChain.height;
  149.                 return true;
  150.             }
  151.         }
  152.        
  153.         return false;
  154.     }
  155.    
  156. public:
  157.     void round() {
  158.         // Check the public chain and adjust.
  159.         readPublicChain();
  160.        
  161.         if (!isHonest) {
  162.             // We mayb be facing a situation where the
  163.             // honest miner found a block and we need
  164.             // to have it reorg in out chain.
  165.             publishSelfishChain();
  166.         }
  167.        
  168.         if (!nextHeader.tryNextNonce()) {
  169.             // PoW failed, we are done.
  170.             return;
  171.         }
  172.        
  173.         blockFound++;
  174.         addHeader(nextHeader);
  175.        
  176.         import std.stdio;
  177.         writeln(
  178.             "miner ", id,
  179.             " found one block at height ", privateChain.height,
  180.             " vs public chain height ", publicChain.height,
  181.         );
  182.        
  183.         // We have a new header, we need to publish it.
  184.         publishPrivateChain();
  185.     }
  186.    
  187.     bool forcePublishPrivateChain() const {
  188.         return publicChain.maybeReorg(privateChain);
  189.     }
  190.    
  191.     void report() const {
  192.         uint blockWon = 0;
  193.         foreach (h; publicChain.asHeaderArray) {
  194.             if (h.minerId == id) {
  195.                 blockWon++;
  196.             }
  197.         }
  198.        
  199.         import std.stdio;
  200.         writeln(
  201.             "Miner id: ", nextHeader.miner, '\t',
  202.             "Block found: ", blockFound, '\t',
  203.             "Block won: ", blockWon, '\t',
  204.         );
  205.     }
  206. }
  207.  
  208. void main() {
  209.     // Setup miners.
  210.     auto honest = Miner(0, true);
  211.     auto selfish = Miner(1, false);
  212.    
  213.     while (publicChain.height < 65536) {
  214.         honest.round();
  215.         selfish.round();
  216.         honest.round();
  217.         selfish.round();
  218.         honest.round();
  219.     }
  220.    
  221.     honest.forcePublishPrivateChain();
  222.     selfish.forcePublishPrivateChain();
  223.    
  224.     import std.stdio;
  225.     writeln("Total block found: ", publicChain.height);
  226.     honest.report();
  227.     selfish.report();
  228. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement