public bool SubmitWork(IMiner miner, Work work, string comment) { return onWork(miner, work); }
/// <summary> /// Parses a <see cref="WebResponse"/> containing the results of a 'getwork' request. /// </summary> /// <param name="webResponse"></param> /// <returns></returns> Work ParseGetWork(WebResponse webResponse) { // obtain and update current block number uint blockNumber = 0; if (webResponse.Headers["X-Blocknum"] != null) CurrentBlockNumber = blockNumber = uint.Parse(webResponse.Headers["X-Blocknum"]); // parse and update long poll url value if present var longPollUrlStr = webResponse.Headers["X-Long-Polling"]; if (longPollUrlStr == null) longPollUrl = null; else if (longPollUrlStr == "") longPollUrl = url; else if (longPollUrlStr.StartsWith("http:") || longPollUrlStr.StartsWith("https:")) longPollUrl = new Uri(longPollUrlStr); else longPollUrl = new Uri(url, longPollUrlStr); // longPollUrl does not specify user info, but userinfo was required on initial url if (string.IsNullOrWhiteSpace(longPollUrl.UserInfo) && !string.IsNullOrWhiteSpace(url.UserInfo)) { var b = new UriBuilder(longPollUrl); var u = url.UserInfo .Split(':') .Select(i => HttpUtility.UrlDecode(i)) .ToArray(); if (u.Length >= 2) { b.UserName = u[0]; b.Password = u[1]; } longPollUrl = b.Uri; } // retrieve invocation response using (var txt = new StreamReader(webResponse.GetResponseStream())) using (var rdr = new JsonTextReader(txt)) { if (!rdr.MoveToContent() && rdr.Read()) throw new JsonException("Unexpected content from 'getwork'."); var response = JsonConvert.Import<JsonGetWork>(rdr); if (response == null) throw new JsonException("No response returned."); if (response.Error != null) Console.WriteLine("JSON-RPC: {0}", response.Error); var result = response.Result; if (result == null) return null; // decode data var data = Memory.Decode(result.Data); if (data.Length != 128) throw new InvalidDataException("Received data is not valid."); // extract only header portion var header = new byte[80]; Array.Copy(data, header, 80); // decode target var target = Memory.Decode(result.Target); if (target.Length != 32) throw new InvalidDataException("Received target is not valid."); // generate new work instance var work = new Work() { Pool = this, BlockNumber = blockNumber, Header = header, Target = target, }; // release connection webResponse.Close(); return work; } }
/// <summary> /// Parses a <see cref="WebResponse"/> containing the results of a 'getwork' request. /// </summary> /// <param name="webResponse"></param> /// <returns></returns> private Work ParseGetWork(WebResponse webResponse) { // obtain and update current block number uint blockNumber = 0; if (webResponse.Headers["X-Blocknum"] != null) CurrentBlockNumber = blockNumber = uint.Parse(webResponse.Headers["X-Blocknum"]); // parse and update long poll url value if present var longPollUrlStr = webResponse.Headers["X-Long-Polling"]; if (longPollUrlStr == null) longPollUrl = null; else if (longPollUrlStr == "") longPollUrl = url; else if (longPollUrlStr.StartsWith("http:") || longPollUrlStr.StartsWith("https:")) longPollUrl = new Uri(longPollUrlStr); else longPollUrl = new Uri(url, longPollUrlStr); // retrieve invocation response using (var txt = new StreamReader(webResponse.GetResponseStream())) using (var rdr = new JsonTextReader(txt)) { if (!rdr.MoveToContent() && rdr.Read()) throw new JsonException("Unexpected content from 'getwork'."); var response = JsonConvert.Import<JsonGetWork>(rdr); if (response == null) throw new JsonException("No response returned."); if (response.Error != null) Console.WriteLine("JSON-RPC: {0}", response.Error); var result = response.Result; if (result == null) return null; // decode data var data = Memory.Decode(result.Data); if (data.Length != 128) throw new InvalidDataException("Received data is not valid."); // extract only header portion var header = new byte[80]; Array.Copy(data, header, 80); // decode target var target = Memory.Decode(result.Target); if (target.Length != 32) throw new InvalidDataException("Received target is not valid."); // generate new work instance var work = new Work() { Pool = this, BlockNumber = blockNumber, Header = header, Target = target, }; // release connection webResponse.Close(); return work; } }
/// <summary> /// Invokes the 'getwork' JSON method, submitting the proposed work. Returns <c>true</c> if the service accepts /// the proposed work. /// </summary> /// <param name="work"></param> /// <returns></returns> public bool SubmitWorkRpc(IMiner miner, Work work, string comment) { var req = OpenRpc(miner, comment); if (req == null) return false; // header needs to have SHA-256 padding appended var data = Sha256.AllocateInputBuffer(80); // prepare header buffer with SHA-256 Sha256.Prepare(data, 80, 0); Sha256.Prepare(data, 80, 1); // dump header data on top of padding Array.Copy(work.Header, data, 80); // encode in proper format var solution = Memory.Encode(data); Console.WriteLine(); Console.WriteLine("SOLUTION: {0,10} {1}", miner.GetType().Name, Memory.Encode(work.Header)); Console.WriteLine(); Console.WriteLine(); using (var txt = new StreamWriter(req.GetRequestStream())) using (var wrt = new JsonTextWriter(txt)) { wrt.WriteStartObject(); wrt.WriteMember("id"); wrt.WriteString("json"); wrt.WriteMember("method"); wrt.WriteString("getwork"); wrt.WriteMember("params"); wrt.WriteStartArray(); wrt.WriteString(solution); wrt.WriteEndArray(); wrt.WriteEndObject(); wrt.Flush(); } using (var txt = new StreamReader(req.GetResponse().GetResponseStream())) using (var rdr = new JsonTextReader(txt)) { if (!rdr.MoveToContent() && rdr.Read()) throw new JsonException("Unexpected content from 'getwork <data>'."); var response = JsonConvert.Import<JsonSubmitWork>(rdr); if (response == null) throw new JsonException("No response returned."); if (response.Error != null) Console.WriteLine("JSON-RPC: {0}", response.Error); Console.WriteLine(); Console.WriteLine("{0}: {1,10} {2}", response.Result ? "ACCEPTED" : "REJECTED", miner.GetType().Name, Memory.Encode(work.Header)); Console.WriteLine(); Console.WriteLine(); return response.Result; } }
public unsafe void BlockHeaderHashTest() { // sample work with immediate solution var work = new Work() { BlockNumber = 0, Header = Memory.Decode("00000001d915b8fd2face61c6fe22ab76cad5f46c11cebab697dbd9e00000804000000008fe5f19cbdd55b40db93be7ef8ae249e0b21ec6e29c833b186404de0de205cc54e0022ac1a132185007d1adf000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"), Target = Memory.Decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000"), }; // allocate buffers to hold hashing work byte[] round1Blocks = Sha256.AllocateInputBuffer(80); uint[] round1State = Sha256.AllocateStateBuffer(); byte[] round2Blocks = Sha256.AllocateInputBuffer(Sha256.SHA256_HASH_SIZE); uint[] round2State = Sha256.AllocateStateBuffer(); byte[] hash = Sha256.AllocateHashBuffer(); fixed (byte* round1BlocksPtr = round1Blocks, round2BlocksPtr = round2Blocks, hashPtr = hash, targetPtr = work.Target) fixed (uint* round1StatePtr = round1State, round2StatePtr = round2State) { byte* round1Block1Ptr = round1BlocksPtr; byte* round1Block2Ptr = round1BlocksPtr + Sha256.SHA256_BLOCK_SIZE; byte* round2Block1Ptr = round2BlocksPtr; // header arrives in big endian, convert to host fixed (byte* workHeaderPtr = work.Header) Memory.ReverseEndian((uint*)workHeaderPtr, (uint*)round1BlocksPtr, 20); // prepare states and blocks Sha256.Initialize(round1StatePtr); Sha256.Initialize(round2StatePtr); Sha256.Prepare(round1Block1Ptr, 80, 0); Sha256.Prepare(round1Block2Ptr, 80, 1); Sha256.Prepare(round2BlocksPtr, Sha256.SHA256_HASH_SIZE, 0); // hash first half of header Sha256.Transform(round1StatePtr, round1Block1Ptr); Sha256.Transform(round1StatePtr, round1Block2Ptr, (uint*)round2Block1Ptr); Sha256.Transform(round2StatePtr, round2Block1Ptr); Sha256.Finalize(round2StatePtr, hashPtr); for (int i = 7; i >= 0; i--) Assert.IsFalse(((uint*)hashPtr)[i] > ((uint*)targetPtr)[i]); } }