Permalink
Browse files

Refactored some classes for more modular mining.

  • Loading branch information...
1 parent 48ff0c2 commit 0d84f24c6926a1c6d236c1b2fbfdd5c721c83215 @travist committed Mar 4, 2014
View
@@ -10,19 +10,36 @@ void main() {
"host": "127.0.0.1",
"port": 18332,
"user": "bitcoinrpc",
- "pass": "123123123123"
+ "pass": "123123123123123"
});
- // Get work from the client.
- bitcoin.getwork().then((Map<String, String> work) {
+ // Mine for gold.
+ void mineForGold() {
- // Create the miner.
- Miner miner = new Miner(work);
-
- // Mine for gold!
- List<int> result = miner.mine();
-
- // Print the result!
- print(result);
- });
+ // Get work from the bitcoind.
+ bitcoin.getwork().then((Map<String, String> work) {
+
+ // Work.
+ print(work);
+
+ // Create the miner.
+ Miner miner = new Miner.fromJSON(work);
+
+ // Mine for gold!
+ Map<String, String> result = miner.mine();
+
+ // If the result isn't null, then
+ if (result != null) {
+ print('Gold!');
+ print(result);
+ bitcoin.getwork(params: [result['data']]);
+ }
+
+ // Mine for more gold.
+ mineForGold();
+ });
+ }
+
+ // Mine for gold.
+ mineForGold();
}
View
@@ -3,11 +3,13 @@ library dartminer;
import 'dart:async';
import 'dart:io';
import 'dart:convert';
+import 'dart:typed_data';
import 'package:utf/utf.dart' as UTF;
-import 'package:crypto/crypto.dart' as Crypto;
part 'src/util.dart';
+part 'src/block.dart';
part 'src/sha256.dart';
+part 'src/doublesha256.dart';
part 'src/bitcoin.dart';
part 'src/miner.dart';
part 'src/work.dart';
View
@@ -0,0 +1,187 @@
+part of dartminer;
+
+class Block {
+
+ // The block version.
+ int version;
+
+ // The previous block hash.
+ String previousblockhash;
+
+ // The merkle root of the transactions.
+ String merkleroot;
+
+ // The current time.
+ int time;
+
+ // The bits value.
+ String bits;
+
+ // The target array.
+ Uint32List target;
+
+ // The nonce for this block.
+ int nonce;
+
+ // The list of transactions in this block.
+ List<String> tx;
+
+ Block.fromJSON(dynamic block) {
+
+ // The version of the block.
+ version = block['version'];
+
+ // The previous block hash.
+ previousblockhash = block['previousblockhash'];
+
+ // The current time.
+ time = block['time'];
+
+ // The bits.
+ bits = block['bits'];
+
+ // The nonce for this block.
+ nonce = block['nonce'];
+
+ // Get the target from the bits.
+ target = bitsToTarget(bits);
+
+ // Set the list of transactions.
+ tx = block['tx'];
+
+ // Get the merkle root if not provided for us.
+ merkleroot = (block['merkleroot'] != null) ? block['merkleroot'] : merkleRoot();
+ }
+
+ /**
+ * Create a block header from data.
+ */
+ Block.fromData(String data) {
+
+ // Get the version.
+ int offset = 0;
+ int length = 8;
+ version = int.parse(data.substring(offset, offset + length), radix: 16);
+
+ // Set the previous block hash.
+ offset += length;
+ length = 64;
+ previousblockhash = data.substring(offset, offset + length);
+ previousblockhash = listToHex(hexToReversedList(previousblockhash));
+
+ // Set the merkle root.
+ offset += length;
+ length = 64;
+ merkleroot = data.substring(offset, offset + length);
+ merkleroot = listToHex(hexToReversedList(merkleroot));
+
+ // Set the time
+ offset += length;
+ length = 8;
+ time = int.parse(data.substring(offset, offset + length), radix: 16);
+
+ // Set the bits
+ offset += length;
+ length = 8;
+ bits = data.substring(offset, offset + length);
+ target = bitsToTarget(bits);
+
+ // Set the bits
+ offset += length;
+ length = 8;
+ nonce = int.parse(data.substring(offset, offset + length), radix: 16);
+ }
+
+ /**
+ * Convert the bits string to a target.
+ */
+ static Uint32List bitsToTarget(String bits) {
+ int bitsLength = int.parse(bits.substring(0, 2), radix: 16);
+ int numBits = ((bits.length ~/ 2) - 1);
+ int offset = 32 - bitsLength;
+
+ // Create the target.
+ Uint8List target = new Uint8List(32);
+ int bitpos = 2;
+ while ((bitpos + 2) <= bits.length) {
+ target[offset++] = int.parse(bits.substring(bitpos, (bitpos + 2)), radix: 16);
+ bitpos += 2;
+ }
+
+ // Get the little endian version of the target.
+ Uint32List target32 = new Uint32List.view(target.buffer);
+ for (int i = 0; i < target32.length; i++) {
+ target32[i] = reverseBytesInWord(target32[i]);
+ }
+
+ // Return the target.
+ return target32;
+ }
+
+ /**
+ * Convert this block to work.
+ */
+ Work toWork() {
+
+ // Return the work from header.
+ return new Work.fromHeader(getHeader(), target, reverseBytesInWord(nonce));
+ }
+
+ /**
+ * Form a block header from this block.
+ */
+ Uint32List getHeader() {
+ Uint32List header = new Uint32List(32);
+ header[0] = reverseBytesInWord(version);
+ header.setAll(1, hexToReversedList(previousblockhash));
+ header.setAll(9, hexToReversedList(merkleroot));
+ header[17] = reverseBytesInWord(time);
+ header[18] = reverseBytesInWord(int.parse(bits, radix: 16));
+ header[19] = reverseBytesInWord(nonce);
+ header[20] = 0x80000000;
+ return header;
+ }
+
+ /**
+ * Compute the merkle root provided a list of transactions.
+ */
+ String merkleRoot() {
+
+ // Get the init hashes.
+ List<Uint32List> intHashes = [];
+
+ // Convert each hash into a reversed list of ints.
+ for (int i = 0; i < tx.length; i++) {
+ intHashes.add(hexToReversedList(tx[i]));
+ }
+
+ // The hash.
+ Uint32List hash = new Uint32List(16);
+
+ // Create a new double sha256 object.
+ doubleSHA256 sha256 = new doubleSHA256();
+
+ // Iteratively compute the merkle root hash
+ while (intHashes.length > 1) {
+
+ // Duplicate last hash if the list is odd
+ if ((intHashes.length % 2) != 0) {
+ intHashes.add(intHashes[(intHashes.length - 1)]);
+ }
+
+ List<Uint32List> newHashes = [];
+ int pairLength = (intHashes.length ~/ 2);
+ for (int j = 0; j < pairLength; j++) {
+ hash.setAll(0, intHashes.removeAt(0));
+ hash.setAll(8, intHashes.removeAt(0));
+ sha256.update(hash, 16);
+ newHashes.add(new Uint32List.fromList(sha256.state.toList()));
+ }
+
+ intHashes = newHashes;
+ }
+
+ // Return the reverse string.
+ return listToReversedHex(intHashes[0]);
+ }
+}
View
@@ -0,0 +1,50 @@
+part of dartminer;
+
+// Finalized array for a 32 byte hash.
+List<int> hash32 = [0, 0, 0, 0, 0, 0, 0, 0, 0x80000000, 0, 0, 0, 0, 0, 0, 256];
+
+// Finalized array for a 64 byte hash.
+List<int> hash64 = [0x80000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 512];
+
+class doubleSHA256 extends SHA256 {
+
+ // The midstate.
+ Uint32List midstate = null;
+
+ // If they provide an initialize, then set the midstate.
+ doubleSHA256([Uint32List init = null]) {
+ if (init != null) {
+ super.update(init);
+ midstate = new Uint32List.fromList(state.toList());
+ }
+ }
+
+ /**
+ * Perform a double hash.
+ */
+ void update(List<int> data, [int length = 8]) {
+
+ // The data size must be either 64 or 32 bytes long.
+ assert((data.length == 16 || data.length == 8));
+
+ // Reset with the midstate.
+ reset(midstate);
+
+ // Update with the data.
+ super.update(data);
+
+ // If the data is 64 bytes long, then update with the finalized data.
+ if (length == 16) {
+ super.update(hash64);
+ }
+
+ // Add the 32 byte state to the 64 byte hash32.
+ hash32.setAll(0, state);
+
+ // Reset the sha256 hash.
+ reset();
+
+ // Update with the data from previous hash.
+ super.update(hash32);
+ }
+}
View
@@ -11,23 +11,47 @@ class Miner {
* @param Map work
* The JSON map of the work.
*/
- Miner(Map<String, String> work) {
- this.work = new Work(work);
+ Miner.fromJSON(Map<String, String> work, [int startNonce = 0]) {
+ this.work = new Work.fromJSON(work, startNonce);
}
/**
+ * Create a new miner from the header.
+ *
+ * @param Uint32List header
+ * The little-endian Uint32List header.
+ *
+ * @param Uint32List target
+ * The target.
+ *
+ * @param int startNonce
+ * The nonce to start with.
+ */
+ Miner.fromHeader(Uint32List header, Uint32List target, [int startNonce = 0]) {
+ this.work = new Work.fromHeader(header, target, startNonce);
+ }
+
+ /**
+ * Create a new miner from work.
+ */
+ Miner.fromWork(Work this.work);
+
+ /**
* Mine for the nonce.
*/
- List<int> mine([done]) {
+ Map<String, String> mine([done]) {
// Perform a hash check every 1M cycles.
int hashCheck = 1000000;
// Record the last time.
int lastTime = (new DateTime.now()).millisecondsSinceEpoch ~/ 1000;
- // Check the nonce value.
- while(!work.checkNonce()) {
+ // Iterate while there is more work to be done.
+ while(work.hasWork() && !work.checkNonce()) {
+
+ // Iterate the work nonce.
+ work.nonce++;
// Print an update...
if ((work.nonce % hashCheck) == 0) {
Oops, something went wrong.

0 comments on commit 0d84f24

Please sign in to comment.