public void ConvertPubKeyTest() { byte[] input = Encoding.ASCII.GetBytes("abc"); List <PubKey> keys = BlockChainDataConversions.BytesToPubKeys(input); byte[] converted = BlockChainDataConversions.PubKeysToBytes(keys); Assert.Equal(converted[0], 0x61); Assert.Equal(converted[1], 0x62); Assert.Equal(converted[2], 0x63); }
public void ParseTransaction(Transaction tx, Network network) { var markerIndex = GetMarkerIndex(tx); if (markerIndex == -1) { throw new Exception("Missing Redstone registration marker from first transaction output"); } // Peek at first non-nulldata address to get the length information, // this indicates how many outputs have been used for encoding, and // by extension indicates if there will be a change address output PubKey[] tempPubKeyArray = tx.Outputs[markerIndex + 1].ScriptPubKey.GetDestinationPublicKeys(network); if (tempPubKeyArray.Length > 1) { // This can't have been generated by a server registration, we don't use // multiple signatures for the registration transaction outputs by design throw new Exception("Registration transaction output has too many PubKeys"); } byte[] secondOutputData = BlockChainDataConversions.PubKeyToBytes(tempPubKeyArray[0]); var protocolVersion = (int)secondOutputData[0]; var headerLength = (secondOutputData[2] << 8) + secondOutputData[1]; // 64 = number of bytes we can store per output int numPubKeys = headerLength / 64; // Is there a partially 'full' PubKey holding the remainder of the bytes? if (headerLength % 64 != 0) { numPubKeys++; } if (tx.Outputs.Count < numPubKeys + 1) { throw new Exception("Too few transaction outputs, registration transaction incomplete"); } PubKey[] tempPK; var pubKeyList = new List <PubKey>(); for (int i = markerIndex + 1; i < numPubKeys + markerIndex + 1; i++) { tempPK = tx.Outputs[i].ScriptPubKey.GetDestinationPublicKeys(network); if (tempPK.Length > 1) { // This can't have been generated by a server registration, we don't use // multiple signatures for the registration transaction outputs by design throw new Exception("Registration transaction output has too many PubKeys"); } pubKeyList.Add(tempPK[0]); } byte[] bitstream = BlockChainDataConversions.PubKeysToBytes(pubKeyList); // Need to consume X bytes at a time off the bitstream and convert them to various // data types, then set member variables to the retrieved values. // Skip over protocol version and header length bytes int position = 3; this.ProtocolVersion = protocolVersion; byte[] collateralPubKeyHashTemp = GetSubArray(bitstream, position, 20); this.CollateralPubKeyHash = new KeyId(collateralPubKeyHashTemp); position += 20; byte[] rewaredPubKeyHashTemp = GetSubArray(bitstream, position, 20); this.RewardPubKeyHash = new KeyId(rewaredPubKeyHashTemp); position += 20; // Either a valid IPv4 address, or all zero bytes bool allZeroes = true; byte[] ipv4temp = GetSubArray(bitstream, position, 4); for (int i = 0; i < ipv4temp.Length; i++) { if (ipv4temp[i] != 0) { allZeroes = false; } } if (!allZeroes) { this.Ipv4Addr = new IPAddress(ipv4temp); } else { this.Ipv4Addr = IPAddress.None; } position += 4; // Either a valid IPv6 address, or all zero bytes allZeroes = true; byte[] ipv6temp = GetSubArray(bitstream, position, 16); for (int i = 0; i < ipv6temp.Length; i++) { if (ipv6temp[i] != 0) { allZeroes = false; } } if (!allZeroes) { this.Ipv6Addr = new IPAddress(ipv6temp); } else { this.Ipv6Addr = IPAddress.IPv6None; } position += 16; // Either a valid onion address, or all zero bytes allZeroes = true; byte[] onionTemp = GetSubArray(bitstream, position, 16); for (int i = 0; i < onionTemp.Length; i++) { if (onionTemp[i] != 0) { allZeroes = false; } } if (!allZeroes) { this.OnionAddress = Encoding.ASCII.GetString(onionTemp); } else { this.OnionAddress = null; } position += 16; var temp = GetSubArray(bitstream, position, 2); this.Port = (temp[1] << 8) + temp[0]; position += 2; temp = GetSubArray(bitstream, position, 2); var servicEndpointLength = (temp[1] << 8) + temp[0]; position += 4; var serviceEndpointTemp = GetSubArray(bitstream, position, servicEndpointLength); this.ServiceEndpoint = new Uri(Encoding.ASCII.GetString(serviceEndpointTemp)); position += servicEndpointLength; temp = GetSubArray(bitstream, position, 2); var ecdsaLength = (temp[1] << 8) + temp[0]; position += 4; this.Signature = GetSubArray(bitstream, position, ecdsaLength); position += ecdsaLength; temp = GetSubArray(bitstream, position, 2); var ecdsaPubKeyLength = (temp[1] << 8) + temp[0]; position += 2; this.PubKey = new PubKey(GetSubArray(bitstream, position, ecdsaPubKeyLength)); position += ecdsaPubKeyLength; // TODO: Validate signatures }