/// <summary> /// Returns the data of an entry. /// </summary> /// <param name="entryHash">Entryhash of entry</param> /// <returns>The entry data</returns> public static DataStructs.EntryData GetEntryData(byte[] entryHash) { var req = new RestRequest("/entry-by-hash/{hash}", Method.GET); req.AddUrlSegment("hash", Arrays.ByteArrayToHex(entryHash)); var resp = StaticValues.clientWallet.Execute(req); var entryType = JsonConvert.DeserializeObject <DataStructs.EntryDataStringFormat>(resp.Content); return(DataStructs.ConvertStringFormatToByteFormat(entryType)); }
/// <summary> /// Returns an EntryBlock /// </summary> /// <param name="hash">String of KeyMr</param> /// <returns>EntryBlockData</returns> public static DataStructs.EntryBlockData GetEntryBlockByKeyMR(byte[] keyMR) { var req = new RestRequest("/entry-block-by-keymr/{hash}", Method.GET); var keyMRString = Arrays.ByteArrayToHex(keyMR); req.AddUrlSegment("hash", keyMRString); var resp = StaticValues.clientWallet.Execute(req); if (resp.Content == "EBlock not found") { throw new FactomEntryException("EBlock not Found, Zerohash looked up"); } var entryBlock = JsonConvert.DeserializeObject <DataStructs.EntryBlockDataStringFormat>(resp.Content); return(DataStructs.ConvertStringFormatToByteFormat(entryBlock)); }
/// <summary> /// Caculates the cost of an entry /// </summary> /// <param name="entry"></param> /// <returns></returns> public static sbyte EntryCost(DataStructs.EntryData entry) { var entryBinary = Entries.MarshalBinary(entry); var len = entryBinary.Length - 35; if (len > 10240) { //Error, cannot be larger than 10kb throw new ArgumentException("Parameter cannot exceed 10kb of content", nameof(entry)); } var r = len % 1024; var n = (sbyte)(len / 1024); // Capacity of Entry Payment if (r > 0) { n += 1; } if (n < 1) { n = 1; } return n; }
/// <summary> /// Takes in an entry chain hash and returns Key MR of the first entry. Can be used to /// get all the entries /// </summary> /// <param name="hash">ChainID of chain</param> /// <returns>KeyMR of first entry (last in list)</returns> public static DataStructs.ChainHeadData GetChainHead(byte[] hash) { var hashString = Arrays.ByteArrayToHex(hash); var req = new RestRequest("/chain-head/{hash}", Method.GET); // var x = Arrays.ByteArrayToHex(hash); req.AddUrlSegment("hash", hashString); var resp = StaticValues.clientWallet.Execute(req); if (resp.Content.Contains("Chain not found")) { throw new FactomChainException("Chain not found"); } try { var chainHead = JsonConvert.DeserializeObject <DataStructs.ChainHeadDataStringFormat>(resp.Content); return(DataStructs.ConvertStringFormatToByteFormat(chainHead)); } catch (Exception) { throw new FactomEntryException("Error when serializing the chainhead. In GetChainHead: " + resp.Content); } }
/// <summary> /// Commits an entry to the Factom blockchain. Must wait 10 seconds if succeeds then call RevealEntry /// </summary> /// <param name="entry">Entry to be committed</param> /// <param name="name">Name of entry credit wallet</param> /// <returns>ChainID of commited Entry</returns> public static byte[] CommitEntry(DataStructs.EntryData entry, string name) { var byteList = new List<byte>(); // 1 byte version byteList.Add(0); // 6 byte milliTimestamp (truncated unix time) byteList.AddRange(Times.MilliTime()); // 32 byte Entry Hash byteList.AddRange(Entries.HashEntry(entry)); // 1 byte number of entry credits to pay var cost = EntryCost(entry); // TODO: check errors byteList.Add(BitConverter.GetBytes(cost)[0]); var com = new WallerCommit(); com.Message = Arrays.ByteArrayToHex(byteList.ToArray()); //Hex encoded string on bytelist var json = JsonConvert.SerializeObject(com); Console.WriteLine("CE Json = " + json); //TODO: Remove var req = new RestRequest("/commit-entry/{name}", Method.POST); req.RequestFormat = DataFormat.Json; req.AddParameter("application/json", json, ParameterType.RequestBody); req.AddUrlSegment("name", name); var resp = StaticValues.clientD.Execute(req); if (resp.StatusCode != HttpStatusCode.OK) { throw new FactomEntryException("Entry Commit Failed. Message: " + resp.ErrorMessage); } //Console.WriteLine("CommitEntry Resp = " + resp.StatusCode + "|" + resp.StatusCode); if (entry.ExtIDs != null) { return Entries.ChainIdOfFirstEntry(entry); } return entry.ChainId; }
/// <summary> /// Helper function of MarshalBinary /// </summary> /// <param name="e"></param> /// <returns></returns> private static byte[] MarshalExtIDsSize(DataStructs.EntryData e) { if (e.ExtIDs == null) { short extLen = 0; var bytes = BitConverter.GetBytes(extLen); return Bytes.CheckEndian(bytes); } else { var totalSize = 0; foreach (var extElement in e.ExtIDs) { totalSize += extElement.Length + 2; } var extLen = Convert.ToInt16(totalSize); var bytes = BitConverter.GetBytes(extLen); return bytes; // return Bytes.CheckEndian(bytes); } }
/// <summary> /// Helper function of MarshalBinary /// </summary> /// <param name="e"></param> /// <returns></returns> private static byte[] MarshalExtIDsBinary(DataStructs.EntryData e) { var byteList = new List<byte>(); foreach (var exId in e.ExtIDs) { // 2 byte size of ExtID var extLen = Convert.ToInt16(exId.Length); var bytes = BitConverter.GetBytes(extLen); bytes = Bytes.CheckEndian(bytes); byteList.AddRange(bytes); var extIdStr = exId; byteList.AddRange(extIdStr); } return byteList.ToArray(); }
/// <summary> /// Marshals an entry into a byte[] to be sent to restAPI /// </summary> /// <param name="e">Entry to be marshaled</param> /// <returns>Marshaled entry</returns> public static byte[] MarshalBinary(DataStructs.EntryData e) { var entryBStruct = new List<byte>(); var idsSize = MarshalExtIDsSize(e); idsSize = Bytes.CheckEndian(idsSize); // Header // 1 byte version byte version = 0; entryBStruct.Add(version); // 32 byte chainid var chain = e.ChainId; entryBStruct.AddRange(chain); // Ext Ids Size entryBStruct.AddRange(idsSize); // Payload // ExtIDS if (e.ExtIDs != null) { var ids = MarshalExtIDsBinary(e); entryBStruct.AddRange(ids); } // Content var content = e.Content; entryBStruct.AddRange(content); return entryBStruct.ToArray(); }
/// <summary> /// Gets a hash of an entry /// </summary> /// <param name="entry">EntryData to be hashed</param> /// <returns>Hash of entry</returns> public static byte[] HashEntry(DataStructs.EntryData entry) { var data = MarshalBinary(entry); var h1 = SHA512.Create().ComputeHash(data); var h2 = new byte[h1.Length + data.Length]; h1.CopyTo(h2, 0); data.CopyTo(h2, h1.Length); var h3 = SHA256.Create().ComputeHash(h2); return h3; }
/// <summary> /// Passing the first entry of a Chain will get the chainId of that entry. Needs the ExtIDs to do this successfully /// </summary> /// <param name="entry">Entry object</param> /// <returns>ChainID</returns> public static byte[] ChainIdOfFirstEntry(DataStructs.EntryData entry) { var byteList = new List<byte>(); foreach (var ext in entry.ExtIDs) { byteList.AddRange(SHA256.Create().ComputeHash(ext)); } var b = byteList.ToArray(); var chainInfo = SHA256.Create().ComputeHash(b); return chainInfo; }
/// <summary> /// Returns an EntryBlock /// </summary> /// <param name="hash">Chainhead</param> /// <returns>EntryBlockData</returns> public static DataStructs.EntryBlockData GetEntryBlockByKeyMR(DataStructs.ChainHeadData chainHead) { return GetEntryBlockByKeyMR(chainHead.ChainHead); }
/// <summary> /// Second and final step in adding an entry to a chain on the factom blockchain /// </summary> /// <param name="entry">Entry to be added</param> /// <returns>Boolean true/false for success/failure</returns> public static bool RevealEntry(DataStructs.EntryData entry) { var rev = new Reveal(); var marshaledEntry = Entries.MarshalBinary(entry); rev.Entry = Arrays.ByteArrayToHex(marshaledEntry); var req = new RestRequest("/reveal-entry/", Method.POST); var json = JsonConvert.SerializeObject(rev); Console.WriteLine("RE Json = " + json); req.RequestFormat = DataFormat.Json; req.AddParameter("application/json", json, ParameterType.RequestBody); IRestResponse resp = StaticValues.clientWallet.Execute<RestRequest>(req); Console.WriteLine("RevealEntry Resp = " + resp.StatusCode + "|" + resp.StatusCode); if (resp.StatusCode != HttpStatusCode.OK) { throw new FactomEntryException("Entry Reveal Failed. Message: " + resp.ErrorMessage); } return true; }
/// <summary> /// Returns the data of an entry. /// </summary> /// <param name="hash">Entry hash as EntryBlockData.entry</param> /// <returns>EntryData object</returns> public static DataStructs.EntryData GetEntryData(DataStructs.EntryBlockData.EntryData entry) { return GetEntryData(entry.EntryHash); }
/// <summary> /// Returns all the entries in a Chain. Type of entry has timestamp and entryhash value /// </summary> /// <param name="chainHead">ChainHeadData type</param> /// <returns>List of all chain entries</returns> public static List<DataStructs.EntryBlockData.EntryData> GetAllChainEntries(DataStructs.ChainHeadData chainHead) { var block = Entry.GetEntryBlockByKeyMR(chainHead); var blockPointer = block; var dataList = new List<DataStructs.EntryBlockData.EntryData>(); while (!Bytes.Equality(blockPointer.Header.PrevKeyMr, StaticValues.ZeroHash)) { dataList.AddRange(blockPointer.EntryList); // Add all entries in current MR blockPointer = Entry.GetEntryBlockByKeyMR(blockPointer.Header.PrevKeyMr); } dataList.AddRange(blockPointer.EntryList); return dataList; }
/// <summary> /// Creates a new Chain /// </summary> /// <param name="entry">First entry in chain</param> /// <returns></returns> public static ChainType NewChain(DataStructs.EntryData entry) { var c = new ChainType(); c.FirstEntry = entry; var chainHash = new List<byte>(); if (entry.ExtIDs != null) { foreach (var extId in entry.ExtIDs) { var h = SHA256.Create().ComputeHash(extId); chainHash.AddRange(h); } } c.ChainId = SHA256.Create().ComputeHash(chainHash.ToArray()); c.FirstEntry.ChainId = c.ChainId; return c; }