//public TXInput( // byte[] tXIDOutput, // int outputIndex) //{ // TXIDOutput = tXIDOutput; // PrimaryKeyTXIDOutput = BitConverter.ToInt32(tXIDOutput, 0); // OutputIndex = outputIndex; //} public TXInput(byte[] buffer, ref int index) { TXIDOutput = new byte[HASH_BYTE_SIZE]; Array.Copy( buffer, index, TXIDOutput, 0, HASH_BYTE_SIZE); TXIDOutputShort = BitConverter.ToInt32( buffer, index); index += HASH_BYTE_SIZE; OutputIndex = BitConverter.ToInt32( buffer, index); index += 4; LengthScript = VarInt.GetInt32( buffer, ref index); StartIndexScript = index; index += LengthScript; index += 4; // sequence }
List <TX> ParseTXs( byte[] hashMerkleRoot) { List <TX> tXs = new List <TX>(); int tXCount = VarInt.GetInt32( Buffer, ref IndexBuffer); if (tXCount == 0) { } else if (tXCount == 1) { TX tX = ParseTX(isCoinbase: true); tXs.Add(tX); if (!tX.Hash.IsEqual(hashMerkleRoot)) { throw new ProtocolException( "Payload merkle root corrupted"); } } else { int tXsLengthMod2 = tXCount & 1; var merkleList = new byte[tXCount + tXsLengthMod2][]; TX tX = ParseTX(true); tXs.Add(tX); merkleList[0] = tX.Hash; for (int t = 1; t < tXCount; t += 1) { tX = ParseTX(false); tXs.Add(tX); merkleList[t] = tX.Hash; } if (tXsLengthMod2 != 0) { merkleList[tXCount] = merkleList[tXCount - 1]; } if (!GetRoot(merkleList).IsEqual(hashMerkleRoot)) { throw new ProtocolException( "Payload hash unequal with merkle root."); } } return(tXs); }
public AddressMessage(byte[] messagePayload) : base("addr", messagePayload) { int startIndex = 0; int addressesCount = VarInt.GetInt32( Payload, ref startIndex); for (int i = 0; i < addressesCount; i++) { NetworkAddresses.Add( NetworkAddress.ParseAddress( Payload, ref startIndex)); } }
public GetDataMessage(NetworkMessage message) : base("getdata", message.Payload) { int startIndex = 0; int inventoryCount = VarInt.GetInt32( Payload, ref startIndex); for (int i = 0; i < inventoryCount; i += 1) { Inventories.Add( Inventory.Parse( Payload, ref startIndex)); } }
public InvMessage(byte[] buffer) : base( "inv", buffer) { int startIndex = 0; int inventoryCount = VarInt.GetInt32( Payload, ref startIndex); for (int i = 0; i < inventoryCount; i++) { Inventories.Add( Inventory.Parse( Payload, ref startIndex)); } }
public TXOutput( byte[] buffer, ref int index) { Value = BitConverter.ToUInt64( buffer, index); index += 8; Buffer = buffer; LengthScript = VarInt.GetInt32( Buffer, ref index); StartIndexScript = index; index += LengthScript; }
void LoadCollisionData(byte[] buffer) { int index = 0; int uintLength; uint[] value; while (index < buffer.Length) { byte[] key = new byte[HASH_BYTE_SIZE]; Array.Copy(buffer, index, key, 0, HASH_BYTE_SIZE); index += HASH_BYTE_SIZE; int byteLength = VarInt.GetInt32(buffer, ref index); uintLength = byteLength >> 2; value = new uint[uintLength]; Buffer.BlockCopy(buffer, index, value, 0, byteLength); index += byteLength; CollisionTable.Add(key, value); } }
void LoadPrimaryData(byte[] buffer) { int index = 0; int key; int uintLength; uint[] value; while (index < buffer.Length) { key = BitConverter.ToInt32(buffer, index); index += 4; int byteLength = VarInt.GetInt32(buffer, ref index); uintLength = byteLength >> 2; value = new uint[uintLength]; Buffer.BlockCopy(buffer, index, value, 0, byteLength); index += byteLength; PrimaryTable.Add(key, value); } }
public GetHeadersMessage(NetworkMessage message) : base("getheaders", message.Payload) { int startIndex = 0; var protocolVersionRemote = BitConverter.ToUInt32(Payload, startIndex); startIndex += 4; int headersCount = VarInt.GetInt32(Payload, ref startIndex); for (int i = 0; i < headersCount; i++) { byte[] hash = new byte[32]; Array.Copy(Payload, startIndex, hash, 0, 32); ((List <byte[]>)HeaderLocator).Add(hash); startIndex += 32; } Array.Copy(Payload, startIndex, StopHash, 0, 32); startIndex += 32; }
public override bool TryParse() { StopwatchParse.Start(); try { BufferIndex = 0; BufferStartIndexesBlocks.Add(BufferIndex); HeaderHash = SHA256.ComputeHash( SHA256.ComputeHash( Buffer, BufferIndex, COUNT_HEADER_BYTES)); BufferIndex += COUNT_HEADER_BYTES; TXCount = VarInt.GetInt32(Buffer, ref BufferIndex); if (Header == null) { if (!Headerchain.TryReadHeader( HeaderHash, SHA256, out Header)) { throw new ChainException(string.Format( "Header hash {0} not in chain.", HeaderHash.ToHexString())); } } else { ValidateHeaderHash( HeaderHash, Header.HeaderHash); } Headers.Add(Header); HeaderPrevious = Header.HeaderPrevious; ParseBlock(OFFSET_INDEX_MERKLE_ROOT); BlockCount += 1; CountItems += TXCount; while (BufferIndex < Buffer.Length) { BufferStartIndexesBlocks.Add(BufferIndex); HeaderHash = SHA256.ComputeHash( SHA256.ComputeHash( Buffer, BufferIndex, COUNT_HEADER_BYTES)); int merkleRootIndex = BufferIndex + OFFSET_INDEX_MERKLE_ROOT; BufferIndex += COUNT_HEADER_BYTES; TXCount = VarInt.GetInt32(Buffer, ref BufferIndex); Header = Header.HeadersNext[0]; ValidateHeaderHash( HeaderHash, Header.HeaderHash); Headers.Add(Header); ParseBlock(merkleRootIndex); BlockCount += 1; CountItems += TXCount; } ConvertTablesToArrays(); } catch (Exception ex) { IsValid = false; Console.WriteLine( "Exception {0} loading archive {1}: {2}", ex.GetType().Name, Index, ex.Message); return(false); } StopwatchParse.Stop(); return(true); }
byte[] ParseTX(bool isCoinbase) { try { int tXStartIndex = BufferIndex; BufferIndex += BYTE_LENGTH_VERSION; bool isWitnessFlagPresent = Buffer[BufferIndex] == 0x00; if (isWitnessFlagPresent) { throw new NotImplementedException("Parsing of segwit txs not implemented"); //BufferIndex += 2; } int countInputs = VarInt.GetInt32(Buffer, ref BufferIndex); if (isCoinbase) { new TXInput(Buffer, ref BufferIndex); } else { for (int i = 0; i < countInputs; i += 1) { TXInput input = new TXInput(Buffer, ref BufferIndex); AddInput(input); } } int countTXOutputs = VarInt.GetInt32(Buffer, ref BufferIndex); for (int i = 0; i < countTXOutputs; i += 1) { BufferIndex += BYTE_LENGTH_OUTPUT_VALUE; int lengthLockingScript = VarInt.GetInt32(Buffer, ref BufferIndex); BufferIndex += lengthLockingScript; } //if (isWitnessFlagPresent) //{ //var witnesses = new TXWitness[countInputs]; //for (int i = 0; i < countInputs; i += 1) //{ // witnesses[i] = TXWitness.Parse(Buffer, ref BufferIndex); //} //} BufferIndex += BYTE_LENGTH_LOCK_TIME; int tXLength = BufferIndex - tXStartIndex; byte[] tXHash = SHA256.ComputeHash( SHA256.ComputeHash( Buffer, tXStartIndex, tXLength)); AddOutput( tXHash, countTXOutputs); return(tXHash); } catch (ArgumentOutOfRangeException) { throw new ChainException(); } }
public TX ParseTX( bool isCoinbase, byte[] buffer, ref int indexBuffer) { TX tX = new TX(); try { int tXStartIndex = indexBuffer; indexBuffer += 4; // BYTE_LENGTH_VERSION bool isWitnessFlagPresent = buffer[indexBuffer] == 0x00; if (isWitnessFlagPresent) { throw new NotImplementedException( "Parsing of segwit txs not implemented"); //BufferIndex += 2; } int countInputs = VarInt.GetInt32( buffer, ref indexBuffer); if (isCoinbase) { new TXInput(buffer, ref indexBuffer); } else { for (int i = 0; i < countInputs; i += 1) { tX.TXInputs.Add( new TXInput( buffer, ref indexBuffer)); } } int countTXOutputs = VarInt.GetInt32( buffer, ref indexBuffer); for (int i = 0; i < countTXOutputs; i += 1) { tX.TXOutputs.Add( new TXOutput( buffer, ref indexBuffer)); } //if (isWitnessFlagPresent) //{ //var witnesses = new TXWitness[countInputs]; //for (int i = 0; i < countInputs; i += 1) //{ // witnesses[i] = TXWitness.Parse(Buffer, ref BufferIndex); //} //} indexBuffer += 4; //BYTE_LENGTH_LOCK_TIME tX.Hash = SHA256.ComputeHash( SHA256.ComputeHash( buffer, tXStartIndex, indexBuffer - tXStartIndex)); tX.TXIDShort = BitConverter.ToInt32(tX.Hash, 0); int lengthUTXOBits = COUNT_NON_OUTPUT_BITS + countTXOutputs; return(tX); } catch (ArgumentOutOfRangeException) { throw new BitcoinException( "ArgumentOutOfRangeException thrown in ParseTX."); } }
public async Task StartMessageListener() { try { while (true) { await ReadMessage(Cancellation.Token); string.Format( "{0} received message {1}", GetID(), Command) .Log(LogFile); switch (Command) { case "ping": await SendMessage(new PongMessage( BitConverter.ToUInt64(Payload, 0))); break; case "addr": AddressMessage addressMessage = new AddressMessage(Payload); break; case "sendheaders": await SendMessage(new SendHeadersMessage()); break; case "feefilter": FeeFilterMessage feeFilterMessage = new FeeFilterMessage(Payload); FeeFilterValue = feeFilterMessage.FeeFilterValue; break; case "block": byte[] blockBytes = Payload .Take(PayloadLength) .ToArray(); Block block = BlockParser.ParseBlock(blockBytes); string.Format( "{0}: Receives block {1}.", GetID(), block.Header.Hash.ToHexString()) .Log(LogFile); if (IsStateIdle()) { // Received unsolicited block } else if (IsStateAwaitingBlock()) { BlockDownload.InsertBlock(block); if (BlockDownload.IsDownloadCompleted) { SignalProtocolTaskCompleted.Post(true); Cancellation = new CancellationTokenSource(); break; } Cancellation.CancelAfter( TIMEOUT_BLOCKDOWNLOAD_MILLISECONDS); } break; case "headers": Header header = null; int index = 0; int countHeaders = VarInt.GetInt32( Payload, ref index); string.Format( "{0}: Receiving {1} headers.", GetID(), countHeaders) .Log(LogFile); if (IsStateIdle()) { header = BlockParser.ParseHeader( Payload, ref index); index += 1; if (!Blockchain.TryLock()) { break; } try { string.Format( "Received unsolicited header {0}", header.Hash.ToHexString()) .Log(LogFile); if (Blockchain.ContainsHeader(header.Hash)) { Header headerContained = Blockchain.HeaderTip; var headerDuplicates = new List <byte[]>(); int depthDuplicateAcceptedMax = 3; int depthDuplicate = 0; while (depthDuplicate < depthDuplicateAcceptedMax) { if (headerContained.Hash.IsEqual(header.Hash)) { if (headerDuplicates.Any(h => h.IsEqual(header.Hash))) { throw new ProtocolException( string.Format( "Received duplicate header {0} more than once.", header.Hash.ToHexString())); } headerDuplicates.Add(header.Hash); if (headerDuplicates.Count > depthDuplicateAcceptedMax) { headerDuplicates = headerDuplicates.Skip(1) .ToList(); } break; } if (headerContained.HeaderPrevious != null) { break; } headerContained = header.HeaderPrevious; depthDuplicate += 1; } if (depthDuplicate == depthDuplicateAcceptedMax) { throw new ProtocolException( string.Format( "Received duplicate header {0} with depth greater than {1}.", header.Hash.ToHexString(), depthDuplicateAcceptedMax)); } } else if (header.HashPrevious.IsEqual( Blockchain.HeaderTip.Hash)) { header.HeaderPrevious = Blockchain.HeaderTip; Blockchain.ValidateHeaders(header); await Blockchain.Network .SynchronizeUTXO(header, this); Blockchain.ReleaseLock(); break; } else { IsSynchronized = false; } } catch (Exception ex) { Blockchain.ReleaseLock(); throw ex; } Blockchain.ReleaseLock(); } else if (IsStateAwaitingHeader()) { if (countHeaders > 0) { header = BlockParser.ParseHeader( Payload, ref index); index += 1; HeaderDownload.InsertHeader(header); while (index < PayloadLength) { header = BlockParser.ParseHeader( Payload, ref index); index += 1; HeaderDownload.InsertHeader(header); } } string.Format( "{0}: Signal getheaders task complete.", GetID()) .Log(LogFile); SignalProtocolTaskCompleted.Post(true); Cancellation = new CancellationTokenSource(); break; } break; case "notfound": Console.WriteLine( "Command notfound not implemented yet."); break; case "inv": var invMessage = new InvMessage(Payload); if (invMessage.Inventories.First().IsTX()) { throw new ProtocolException( "Received TX inv message despite TX-disable signaled."); } break; default: // Send message unknown break; } } } catch (Exception ex) { FlagDispose = true; Cancellation.Cancel(); string.Format( "Peer {0} experienced error " + "in message listener: \n{1}", GetID(), "message: " + ex.Message + "stack trace: " + ex.StackTrace) .Log(LogFile); } }