Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

I found an old USB "ASIC Miner Block Erupter" thing in my box of old hardware that waits for the day i find a new purpose for it. This crypto dongle does about 330 Megahashes per second. Not planning to use it to mine bitcoin, but it could be a nice proof-of-concept hardware for a blockchain thing i'm playing around with. No commercial purpose, just me playing around on how a blockchain could be integrated with a project that uses a PostgreSQL database. Basically, just me looking into how crypto blockchains work, but hating the idea of using a big-ass file when you could use SQL ;-)

I normally wouldn't even play with mining hardware devices because they waste tons of power and they are bad for the environment. But this little toy only uses about 2.5 Watts, so i figured i could experiment with it without boiling the oceans.

Before we can use that device for anything, we'd better find out how to communicate with it. There isn't much technical info on the internet about the hardware. Most articles are all about "yadayada blockchains are the future yadayada get rich quick yadayada bitcoin not a pyramid scheme yadayada". I found some very old discussions that mention it uses the Icarus protocol, whatever that is.

Another few minutes of googling found this old article. It describes the "Communication protocol V3". It's not very detailed, but it says what data to send and what data comes back. Except it only mentions "last 12 bytes of block header", whatever that entails.

Eventually, Google found me this post, which helped me in finding out what those mysterious 12 bytes are supposed to be. Timestamp and Nonce are easy, these are just basically 8 bytes i can play around with. The Difficulty target supposedly changes on how difficult it is for the hardware to find a matching block.

To be honest, i have absolutely no idea how that "difficulty" is encoded and what it does on my specific hardware. Changing the value doesn't seem to change on how fast i get the result on average, it just changes the results. I'm probably doing something wrong or i'm missing a step or something. So, if you have any ideas/bugfixes/patches or just want to shout at me for doing something incredibly stupid, feel free to write a comment :-)

Ok, here is the code i have. It's not pretty, it's full of debug stuff. And i'm doing quite a bit of data manipulation the hard way, just to make it easier for me to play around with the bits. But, as a proof of concept, it should be a decent start for you to play around with.

#!/usr/bin/env perl use strict; use warnings; use Crypt::Digest::SHA256 qw(sha256); use Device::SerialPort qw( :PARAM :STAT 0.07 ); use English; use Carp; use Time::HiRes qw(time); use Data::Dumper; my $miner = Device::SerialPort->new('/dev/ttyUSB0') or croak("Modem er +ror $ERRNO"); $miner->baudrate(115_200); $miner->parity('none'); $miner->databits(8); $miner->stopbits(1); # One cycle takes about 12 seconds and there seems no way to # reset the thing. Hardware was designed by crypto-currency people, # so naturally, it is decently fast, very inefficient and has a # very clunky, amateurish interface. # # So, just wait the length of a cycle and empty # the result bytes. initHardware(); my @times; for(my $i = 0; $i < 5; $i++) { my $starttime = time; my $hash; my $loopcount = 0; while(1) { $loopcount++; my $rawdata = getRandomData(); if(1) { # use random data and proper timestamps $hash = generateHash($rawdata, $starttime, $loopcount); } else { # Use fixed data for validation between multiple runs $hash = generateHash('BLA', $i, $loopcount); } if(defined($hash)) { last; } } my $endtime = time; my $elapsed = $endtime - $starttime; my $decodedhash = unpack("H*", $hash); print "Calculated result $i: $decodedhash in $elapsed seconds\n"; push @times, $elapsed; } print "\n"; my $total; foreach my $val (@times) { $total += $val; } $total /= scalar @times; print "Took on average $total seconds to calculate a result.\n"; exit(0); sub initHardware { # This "cleans out" the hardware by running one hash without any n +ew hashing request. # This has the effect of making sure any active loop has time to f +inish and we empty # out all result bytes from the buffer my $targettime = time + 13.5; print "Hardware initialization...\n"; # Remove previous results from queue (is any) while(time < $targettime) { my ($count, $data) = $miner->read(1); if(!$count) { next; } print "! ", ord($data), "\n"; } print "Ready for work!\n"; return; } sub generateHash { my ($data, $timestamp, $nonce) = @_; my $request = buildRequest($data, $timestamp, $nonce); $miner->write($request); my @resultbytes; my $targettime = time + 13.5; # Remove previous results from queue (is any) while(1) { my ($count, $data) = $miner->read(1); if(!$count) { last; } print "! ", ord($data), "\n"; } while(time < $targettime) { my ($count, $data) = $miner->read(1); if(!$count) { next; } my $bytecount = 0; #print "$bytecount > ", ord($data), "\n"; $bytecount++; push @resultbytes, $data; } if(scalar @resultbytes < 4) { # No result; return; } my $result = ''; for(1..4) { $result .= shift @resultbytes; } return $result; } sub buildRequest { my ($data, $timestamp, $nonce) = @_; my $source = sha256($data); # Add fill my $fill = "0" x 160; $fill = pack("B*", $fill); $source .= $fill; $source .= toBinary($timestamp); # timestamp # Difficulty target in "bits" encoding. No idea how that really wo +rks, though. # If i didn't do something stupid, i just copied the one used to m +ine the first bitcoin. $source .= toBitsBinary("1d00ffff"); $source .= toBinary($nonce); # Nonce return $source; } sub toBinary { my ($val) = @_; if(1) { return pack('N', $val); } else { # "shuffle bytes by hand" version for easier experimentation # compared to fiddling with the fast but confusing pack/unpack + function my @bytes; for(1..4) { unshift @bytes, chr($val & 0xff); $val >>= 8; } return join('', @bytes); } } sub toBitsBinary { my ($val) = @_; my @parts = unpack"(A2)*", $val; my @bytes; foreach my $part (@parts) { push @bytes, chr(hex($part)); } return join('', @bytes); } sub getRandomData { my @validchars = split//, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; my $token = 'XPD'; for(1..500) { $token .= $validchars[rand @validchars]; } $token .= 'VT'; return $token; }

So, if you have even a basic understanding about the internals of Bitcoin, i appreciate if you can show me on how to properly calculate the difficulty bits and verify that i have got a valid result. And if you see any error in my protocol implementation, i'd also be glad for any help you can give me.

perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'

In reply to Implementing the "Icarus" crypto mining protocol for some old hardware by cavac

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2024-03-29 12:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found