Пример #1
0
        private unsafe bool Mine(BlockHeader block, int timeOffset, ParallelLoopState state, ParallelOptions options)
        {
            /*** Target ***/
            uint[] targetArr = block.NBits.ToUInt32Array();

            // Compute SHA256(SHA256(80_byte_header))
            // Convert to integer in little endian order
            // Finish if hash <= target

            // Double SHA256 of 80 bytes is:
            //    Compress 64 bytes              -> block1, hashState1
            //    Compress 16 bytes + pad + len  -> block2, hashState2
            //    Compress 32 bytes + pad + len  -> block3, hashState3

            using Sha256 sha = new Sha256();

            uint *buffer = stackalloc uint[64 + 64 + 64 + 64 + 8 + 8]; // 1088 bytes total
            uint *wPt    = buffer;
            uint *blkPt1 = buffer + 64;
            uint *blkPt2 = blkPt1 + 64;
            uint *blkPt3 = blkPt2 + 64;
            uint *hPt1   = blkPt3 + 64;
            uint *hPt3   = hPt1 + 8;

            fixed(uint *tarPt = &targetArr[0])
            fixed(byte *prvBlkH = &block.PreviousBlockHeaderHash[0], mrkl = &block.MerkleRootHash[0])
            {
                /*** First block (64 bytes) ***/
                // 4 byte block version
                blkPt1[0] = ((uint)block.Version).SwapEndian();

                // 32 byte previous block hash
                blkPt1[1] = (uint)(prvBlkH[0] << 24 | prvBlkH[1] << 16 | prvBlkH[2] << 8 | prvBlkH[3]);
                blkPt1[2] = (uint)(prvBlkH[4] << 24 | prvBlkH[5] << 16 | prvBlkH[6] << 8 | prvBlkH[7]);
                blkPt1[3] = (uint)(prvBlkH[8] << 24 | prvBlkH[9] << 16 | prvBlkH[10] << 8 | prvBlkH[11]);
                blkPt1[4] = (uint)(prvBlkH[12] << 24 | prvBlkH[13] << 16 | prvBlkH[14] << 8 | prvBlkH[15]);
                blkPt1[5] = (uint)(prvBlkH[16] << 24 | prvBlkH[17] << 16 | prvBlkH[18] << 8 | prvBlkH[19]);
                blkPt1[6] = (uint)(prvBlkH[20] << 24 | prvBlkH[21] << 16 | prvBlkH[22] << 8 | prvBlkH[23]);
                blkPt1[7] = (uint)(prvBlkH[24] << 24 | prvBlkH[25] << 16 | prvBlkH[26] << 8 | prvBlkH[27]);
                blkPt1[8] = (uint)(prvBlkH[28] << 24 | prvBlkH[29] << 16 | prvBlkH[30] << 8 | prvBlkH[31]);

                // 28/32 byte MerkleRoot
                blkPt1[9]  = (uint)(mrkl[0] << 24 | mrkl[1] << 16 | mrkl[2] << 8 | mrkl[3]);
                blkPt1[10] = (uint)(mrkl[4] << 24 | mrkl[5] << 16 | mrkl[6] << 8 | mrkl[7]);
                blkPt1[11] = (uint)(mrkl[8] << 24 | mrkl[9] << 16 | mrkl[10] << 8 | mrkl[11]);
                blkPt1[12] = (uint)(mrkl[12] << 24 | mrkl[13] << 16 | mrkl[14] << 8 | mrkl[15]);
                blkPt1[13] = (uint)(mrkl[16] << 24 | mrkl[17] << 16 | mrkl[18] << 8 | mrkl[19]);
                blkPt1[14] = (uint)(mrkl[20] << 24 | mrkl[21] << 16 | mrkl[22] << 8 | mrkl[23]);
                blkPt1[15] = (uint)(mrkl[24] << 24 | mrkl[25] << 16 | mrkl[26] << 8 | mrkl[27]);


                // Compress first block (the result should be reused for all nonces)
                sha.Init(hPt1);
                for (int i = 16; i < 64; i++)
                {
                    blkPt1[i] = SSIG1(blkPt1[i - 2]) + blkPt1[i - 7] + SSIG0(blkPt1[i - 15]) + blkPt1[i - 16];
                }
                sha.CompressBlock_WithWSet(hPt1, blkPt1);

                /*** Second block (16 bytes) ***/
                // (final 4 bytes) 32/32 byte MerkleRoot
                blkPt2[0] = (uint)(mrkl[28] << 24 | mrkl[29] << 16 | mrkl[30] << 8 | mrkl[31]);


                // 4 byte BlockTime (index at 1)
                // will be incremented inside the block time loop
                // BlockTime property should not change here since the same instance is being accessed from different threads
                blkPt2[1] = (block.BlockTime + (uint)timeOffset).SwapEndian();

                // 4 byte NBits
                blkPt2[2] = ((uint)block.NBits).SwapEndian();

                // 4 byte Nonce (index at 3)
                // will be set and incremented inside the nonce loop

                // append length and padding:
                blkPt2[4] = 0b10000000_00000000_00000000_00000000U;
                // from 5 to 14 are zeros and are already set
                blkPt2[15] = 640; // 80*8=640

                // Second block values set up to here won't change in the loop

                /*** Third block, second hash (32 bytes) ***/
                // Set values that don't change
                blkPt3[8] = 0b10000000_00000000_00000000_00000000U;
                // From 9 to 14 are zero, already set and won't change
                blkPt3[15] = 256; // 32*8=256

                // Nonce loop
                for (ulong nonce = block.Nonce.SwapEndian(); nonce <= uint.MaxValue; nonce++)
                {
                    if (state.IsStopped || options.CancellationToken.IsCancellationRequested)
                    {
                        return(false);
                    }

                    blkPt2[3] = (uint)nonce;

                    blkPt2[16] = SSIG0(blkPt2[1]) + blkPt2[0];
                    blkPt2[17] = 17825792 + SSIG0(blkPt2[2]) + blkPt2[1];
                    blkPt2[18] = SSIG1(blkPt2[16]) + SSIG0(blkPt2[3]) + blkPt2[2];
                    blkPt2[19] = SSIG1(blkPt2[17]) + 285220864 + blkPt2[3];
                    blkPt2[20] = SSIG1(blkPt2[18]) + 2147483648;
                    blkPt2[21] = SSIG1(blkPt2[19]);
                    blkPt2[22] = SSIG1(blkPt2[20]) + 640;
                    blkPt2[23] = SSIG1(blkPt2[21]) + blkPt2[16];
                    blkPt2[24] = SSIG1(blkPt2[22]) + blkPt2[17];
                    blkPt2[25] = SSIG1(blkPt2[23]) + blkPt2[18];
                    blkPt2[26] = SSIG1(blkPt2[24]) + blkPt2[19];
                    blkPt2[27] = SSIG1(blkPt2[25]) + blkPt2[20];
                    blkPt2[28] = SSIG1(blkPt2[26]) + blkPt2[21];
                    blkPt2[29] = SSIG1(blkPt2[27]) + blkPt2[22];
                    blkPt2[30] = SSIG1(blkPt2[28]) + blkPt2[23] + 10485845;
                    blkPt2[31] = SSIG1(blkPt2[29]) + blkPt2[24] + SSIG0(blkPt2[16]) + 640;
                    blkPt2[32] = SSIG1(blkPt2[30]) + blkPt2[25] + SSIG0(blkPt2[17]) + blkPt2[16];
                    blkPt2[33] = SSIG1(blkPt2[31]) + blkPt2[26] + SSIG0(blkPt2[18]) + blkPt2[17];
                    blkPt2[34] = SSIG1(blkPt2[32]) + blkPt2[27] + SSIG0(blkPt2[19]) + blkPt2[18];
                    blkPt2[35] = SSIG1(blkPt2[33]) + blkPt2[28] + SSIG0(blkPt2[20]) + blkPt2[19];
                    blkPt2[36] = SSIG1(blkPt2[34]) + blkPt2[29] + SSIG0(blkPt2[21]) + blkPt2[20];
                    blkPt2[37] = SSIG1(blkPt2[35]) + blkPt2[30] + SSIG0(blkPt2[22]) + blkPt2[21];
                    blkPt2[38] = SSIG1(blkPt2[36]) + blkPt2[31] + SSIG0(blkPt2[23]) + blkPt2[22];
                    blkPt2[39] = SSIG1(blkPt2[37]) + blkPt2[32] + SSIG0(blkPt2[24]) + blkPt2[23];
                    blkPt2[40] = SSIG1(blkPt2[38]) + blkPt2[33] + SSIG0(blkPt2[25]) + blkPt2[24];
                    blkPt2[41] = SSIG1(blkPt2[39]) + blkPt2[34] + SSIG0(blkPt2[26]) + blkPt2[25];
                    blkPt2[42] = SSIG1(blkPt2[40]) + blkPt2[35] + SSIG0(blkPt2[27]) + blkPt2[26];
                    blkPt2[43] = SSIG1(blkPt2[41]) + blkPt2[36] + SSIG0(blkPt2[28]) + blkPt2[27];
                    blkPt2[44] = SSIG1(blkPt2[42]) + blkPt2[37] + SSIG0(blkPt2[29]) + blkPt2[28];
                    blkPt2[45] = SSIG1(blkPt2[43]) + blkPt2[38] + SSIG0(blkPt2[30]) + blkPt2[29];
                    blkPt2[46] = SSIG1(blkPt2[44]) + blkPt2[39] + SSIG0(blkPt2[31]) + blkPt2[30];
                    blkPt2[47] = SSIG1(blkPt2[45]) + blkPt2[40] + SSIG0(blkPt2[32]) + blkPt2[31];
                    blkPt2[48] = SSIG1(blkPt2[46]) + blkPt2[41] + SSIG0(blkPt2[33]) + blkPt2[32];
                    blkPt2[49] = SSIG1(blkPt2[47]) + blkPt2[42] + SSIG0(blkPt2[34]) + blkPt2[33];
                    blkPt2[50] = SSIG1(blkPt2[48]) + blkPt2[43] + SSIG0(blkPt2[35]) + blkPt2[34];
                    blkPt2[51] = SSIG1(blkPt2[49]) + blkPt2[44] + SSIG0(blkPt2[36]) + blkPt2[35];
                    blkPt2[52] = SSIG1(blkPt2[50]) + blkPt2[45] + SSIG0(blkPt2[37]) + blkPt2[36];
                    blkPt2[53] = SSIG1(blkPt2[51]) + blkPt2[46] + SSIG0(blkPt2[38]) + blkPt2[37];
                    blkPt2[54] = SSIG1(blkPt2[52]) + blkPt2[47] + SSIG0(blkPt2[39]) + blkPt2[38];
                    blkPt2[55] = SSIG1(blkPt2[53]) + blkPt2[48] + SSIG0(blkPt2[40]) + blkPt2[39];
                    blkPt2[56] = SSIG1(blkPt2[54]) + blkPt2[49] + SSIG0(blkPt2[41]) + blkPt2[40];
                    blkPt2[57] = SSIG1(blkPt2[55]) + blkPt2[50] + SSIG0(blkPt2[42]) + blkPt2[41];
                    blkPt2[58] = SSIG1(blkPt2[56]) + blkPt2[51] + SSIG0(blkPt2[43]) + blkPt2[42];
                    blkPt2[59] = SSIG1(blkPt2[57]) + blkPt2[52] + SSIG0(blkPt2[44]) + blkPt2[43];
                    blkPt2[60] = SSIG1(blkPt2[58]) + blkPt2[53] + SSIG0(blkPt2[45]) + blkPt2[44];
                    blkPt2[61] = SSIG1(blkPt2[59]) + blkPt2[54] + SSIG0(blkPt2[46]) + blkPt2[45];
                    blkPt2[62] = SSIG1(blkPt2[60]) + blkPt2[55] + SSIG0(blkPt2[47]) + blkPt2[46];
                    blkPt2[63] = SSIG1(blkPt2[61]) + blkPt2[56] + SSIG0(blkPt2[48]) + blkPt2[47];

                    // HashState is the first block's hashState but it should remain the same for all nonces.
                    // After compressing this block hashState should be used as the next "block".
                    // So copy first block's hashState in third block
                    Buffer.MemoryCopy(hPt1, blkPt3, 32, 32);

                    // Compress second block
                    sha.CompressBlock_WithWSet(blkPt3, blkPt2);

                    // Compress third block
                    sha.Init(hPt3);

                    blkPt3[16] = SSIG0(blkPt3[1]) + blkPt3[0];
                    blkPt3[17] = 10485760 + SSIG0(blkPt3[2]) + blkPt3[1];
                    blkPt3[18] = SSIG1(blkPt3[16]) + SSIG0(blkPt3[3]) + blkPt3[2];
                    blkPt3[19] = SSIG1(blkPt3[17]) + SSIG0(blkPt3[4]) + blkPt3[3];
                    blkPt3[20] = SSIG1(blkPt3[18]) + SSIG0(blkPt3[5]) + blkPt3[4];
                    blkPt3[21] = SSIG1(blkPt3[19]) + SSIG0(blkPt3[6]) + blkPt3[5];
                    blkPt3[22] = SSIG1(blkPt3[20]) + 256 + SSIG0(blkPt3[7]) + blkPt3[6];
                    blkPt3[23] = SSIG1(blkPt3[21]) + blkPt3[16] + 285220864 + blkPt3[7];
                    blkPt3[24] = SSIG1(blkPt3[22]) + blkPt3[17] + 2147483648;
                    blkPt3[25] = SSIG1(blkPt3[23]) + blkPt3[18];
                    blkPt3[26] = SSIG1(blkPt3[24]) + blkPt3[19];
                    blkPt3[27] = SSIG1(blkPt3[25]) + blkPt3[20];
                    blkPt3[28] = SSIG1(blkPt3[26]) + blkPt3[21];
                    blkPt3[29] = SSIG1(blkPt3[27]) + blkPt3[22];
                    blkPt3[30] = SSIG1(blkPt3[28]) + blkPt3[23] + 4194338;
                    blkPt3[31] = SSIG1(blkPt3[29]) + blkPt3[24] + SSIG0(blkPt3[16]) + 256;
                    blkPt3[32] = SSIG1(blkPt3[30]) + blkPt3[25] + SSIG0(blkPt3[17]) + blkPt3[16];
                    blkPt3[33] = SSIG1(blkPt3[31]) + blkPt3[26] + SSIG0(blkPt3[18]) + blkPt3[17];
                    blkPt3[34] = SSIG1(blkPt3[32]) + blkPt3[27] + SSIG0(blkPt3[19]) + blkPt3[18];
                    blkPt3[35] = SSIG1(blkPt3[33]) + blkPt3[28] + SSIG0(blkPt3[20]) + blkPt3[19];
                    blkPt3[36] = SSIG1(blkPt3[34]) + blkPt3[29] + SSIG0(blkPt3[21]) + blkPt3[20];
                    blkPt3[37] = SSIG1(blkPt3[35]) + blkPt3[30] + SSIG0(blkPt3[22]) + blkPt3[21];
                    blkPt3[38] = SSIG1(blkPt3[36]) + blkPt3[31] + SSIG0(blkPt3[23]) + blkPt3[22];
                    blkPt3[39] = SSIG1(blkPt3[37]) + blkPt3[32] + SSIG0(blkPt3[24]) + blkPt3[23];
                    blkPt3[40] = SSIG1(blkPt3[38]) + blkPt3[33] + SSIG0(blkPt3[25]) + blkPt3[24];
                    blkPt3[41] = SSIG1(blkPt3[39]) + blkPt3[34] + SSIG0(blkPt3[26]) + blkPt3[25];
                    blkPt3[42] = SSIG1(blkPt3[40]) + blkPt3[35] + SSIG0(blkPt3[27]) + blkPt3[26];
                    blkPt3[43] = SSIG1(blkPt3[41]) + blkPt3[36] + SSIG0(blkPt3[28]) + blkPt3[27];
                    blkPt3[44] = SSIG1(blkPt3[42]) + blkPt3[37] + SSIG0(blkPt3[29]) + blkPt3[28];
                    blkPt3[45] = SSIG1(blkPt3[43]) + blkPt3[38] + SSIG0(blkPt3[30]) + blkPt3[29];
                    blkPt3[46] = SSIG1(blkPt3[44]) + blkPt3[39] + SSIG0(blkPt3[31]) + blkPt3[30];
                    blkPt3[47] = SSIG1(blkPt3[45]) + blkPt3[40] + SSIG0(blkPt3[32]) + blkPt3[31];
                    blkPt3[48] = SSIG1(blkPt3[46]) + blkPt3[41] + SSIG0(blkPt3[33]) + blkPt3[32];
                    blkPt3[49] = SSIG1(blkPt3[47]) + blkPt3[42] + SSIG0(blkPt3[34]) + blkPt3[33];
                    blkPt3[50] = SSIG1(blkPt3[48]) + blkPt3[43] + SSIG0(blkPt3[35]) + blkPt3[34];
                    blkPt3[51] = SSIG1(blkPt3[49]) + blkPt3[44] + SSIG0(blkPt3[36]) + blkPt3[35];
                    blkPt3[52] = SSIG1(blkPt3[50]) + blkPt3[45] + SSIG0(blkPt3[37]) + blkPt3[36];
                    blkPt3[53] = SSIG1(blkPt3[51]) + blkPt3[46] + SSIG0(blkPt3[38]) + blkPt3[37];
                    blkPt3[54] = SSIG1(blkPt3[52]) + blkPt3[47] + SSIG0(blkPt3[39]) + blkPt3[38];
                    blkPt3[55] = SSIG1(blkPt3[53]) + blkPt3[48] + SSIG0(blkPt3[40]) + blkPt3[39];
                    blkPt3[56] = SSIG1(blkPt3[54]) + blkPt3[49] + SSIG0(blkPt3[41]) + blkPt3[40];
                    blkPt3[57] = SSIG1(blkPt3[55]) + blkPt3[50] + SSIG0(blkPt3[42]) + blkPt3[41];
                    blkPt3[58] = SSIG1(blkPt3[56]) + blkPt3[51] + SSIG0(blkPt3[43]) + blkPt3[42];
                    blkPt3[59] = SSIG1(blkPt3[57]) + blkPt3[52] + SSIG0(blkPt3[44]) + blkPt3[43];
                    blkPt3[60] = SSIG1(blkPt3[58]) + blkPt3[53] + SSIG0(blkPt3[45]) + blkPt3[44];
                    blkPt3[61] = SSIG1(blkPt3[59]) + blkPt3[54] + SSIG0(blkPt3[46]) + blkPt3[45];
                    blkPt3[62] = SSIG1(blkPt3[60]) + blkPt3[55] + SSIG0(blkPt3[47]) + blkPt3[46];
                    blkPt3[63] = SSIG1(blkPt3[61]) + blkPt3[56] + SSIG0(blkPt3[48]) + blkPt3[47];

                    sha.CompressBlock_WithWSet(hPt3, blkPt3);

                    // Check to see if the hash result is smaller than target
                    if (CompareTarget(hPt3, tarPt))
                    {
                        block.Nonce = ((uint)nonce).SwapEndian();
                        // Block time should also be set here since it is different for each thread
                        block.BlockTime += (uint)timeOffset;
                        state.Stop();
                        return(true);
                    }
                }

                return(false);
            }
        }