Dev (#271)
* Fix ethereum explorer links * Refactored-out chain specific share DTOs * Moved ShareRecorder and ShareRelay to more fitting namespace * Greatly reduce the number of threads for external stratum monitoring * Add payload-type-flag-frame to share publisher/subscriber * ProtoBuf Share Relay & Recorder * Do not require monero wallet daemon config if payment processing is disabled * Reconnect to share relay on receive timeout * Cryptonote Tests * Monero v7
This commit is contained in:
parent
df5ecf205e
commit
f511dd6736
|
@ -117,3 +117,4 @@ recovered-shares.json
|
|||
|
||||
|
||||
src/MiningCore/config\.json
|
||||
/src/MiningCore/config2.json
|
||||
|
|
|
@ -47,12 +47,12 @@ namespace MiningCore.Tests.Blockchain.Bitcoin
|
|||
// set clock to submission time
|
||||
clock.CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869907).UtcDateTime;
|
||||
|
||||
var share = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a");
|
||||
var (share, blockHex) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a");
|
||||
|
||||
Assert.NotNull(share);
|
||||
Assert.True(share.IsBlockCandidate);
|
||||
Assert.Equal(share.BlockHash, "000000000fccf11cd0b7d9057441e430c320384b95b034bd28092c4553594b4a");
|
||||
Assert.Equal(share.BlockHex, "00000020bb76da6422b707a90831c421798123293bc5fd377bbeb51985570909000000008677145722cbe6f1ebec19fecc724cab5487f3292a69f6908bd512f645bb0635f286ef59ffff7f206aae848d0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff295e0c0b2f454231362f414431322f04f286ef590801000058010000000c2f4d696e696e67436f72652f000000000100f2052a010000001976a9142ebb5cccf9a6bb927661d2953655c43c04accc3788ac00000000");
|
||||
Assert.Equal(share.BlockHash, "601ed85039804bcecbbdb53e0ca358aeb8dabef2366fb64c216aac3aba02b716");
|
||||
Assert.Equal(blockHex, "00000020bb76da6422b707a90831c421798123293bc5fd377bbeb5198557090900000000fd5418fe788ef961678e4bacdd1fe3903185b9ec63865bb3d2d279bb0eb48c0bf286ef59ffff7f206aae848d0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff295e0c0b2f454231362f414431322f04f286ef590001000058010000000c2f4d696e696e67436f72652f000000000100f2052a010000001976a9142ebb5cccf9a6bb927661d2953655c43c04accc3788ac00000000");
|
||||
Assert.Equal(share.BlockHeight, 14);
|
||||
Assert.Equal(share.BlockReward, 50);
|
||||
Assert.Equal(share.Difficulty, 0.5);
|
||||
|
@ -87,14 +87,14 @@ namespace MiningCore.Tests.Blockchain.Bitcoin
|
|||
Assert.Throws<StratumException>(() => job.ProcessShare(worker, "02000000", "59ef86f2", "8d84ae6a"));
|
||||
|
||||
// make sure we don't accept case-sensitive duplicate shares as basically 0xdeadbeaf = 0xDEADBEAF.
|
||||
var share = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a");
|
||||
var (share, blockHex) = job.ProcessShare(worker, "01000000", "59ef86f2", "8d84ae6a");
|
||||
Assert.Throws<StratumException>(() => job.ProcessShare(worker, "01000000", "59ef86f2", "8D84AE6A"));
|
||||
|
||||
// invalid time
|
||||
Assert.Throws<StratumException>(() => job.ProcessShare(worker, "01000000", "69ef86f2", "8d84ae6a"));
|
||||
|
||||
// invalid nonce
|
||||
Assert.Throws<StratumException>(() => job.ProcessShare(worker, "01000000", "59ef86f2", "ad84be6a"));
|
||||
Assert.Throws<StratumException>(() => job.ProcessShare(worker, "01000000", "59ef86f2", "4a84be6a"));
|
||||
|
||||
// valid share data but invalid submission time
|
||||
clock.CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1408869907).UtcDateTime;
|
||||
|
|
|
@ -26,12 +26,12 @@ namespace MiningCore.Tests.Blockchain.Monero
|
|||
"{\"blocktemplate_blob\":\"0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d00000000019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c0208000000000000000000\",\"Difficulty\":2,\"Height\":224,\"prev_hash\":\"8234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d\",\"reserved_offset\":322,\"Status\":\"OK\"}");
|
||||
|
||||
var job = new MoneroJob(bt, "d150da".HexToByteArray(), "1", poolConfig, clusterConfig);
|
||||
var share = job.ProcessShare("040100a4", 1, "f29c7fbf57d97eeedb61555857d7a34314250da20742b8157f96e0be89530a00", worker);
|
||||
var (share, blobHex, blobHash) = job.ProcessShare("040100a4", 1, "f29c7fbf57d97eeedb61555857d7a34314250da20742b8157f96e0be89530a00", worker);
|
||||
|
||||
Assert.NotNull(share);
|
||||
Assert.True(share.IsBlockCandidate);
|
||||
Assert.Equal(share.BlobHash, "9258faf2dff5daf026681b5fa5d94a34dbb5bade1d9e2070865ba8c68f8f0454");
|
||||
Assert.Equal(share.BlobHex, "0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d040100a4019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c02080000000001d150da00");
|
||||
Assert.Equal(blobHash, "9258faf2dff5daf026681b5fa5d94a34dbb5bade1d9e2070865ba8c68f8f0454");
|
||||
Assert.Equal(blobHex, "0106e7eabdcf058234351e2e6ea901a56b33bb531587424321873072d80a9e97295b6c43152b9d040100a4019c0201ffe00106e3a1a0cc010275d92c0a057aa5f073079694a153d426f837f49fdb9654da10a5364e79a2086280a0d9e61d028b46dca0d04998500b40b046fd6f8bb33229e6380fd465dbb1327aa6f813d8bd80c0fc82aa0202372f076459e769116d604d30aabff7160782acc0d20e0c5cdc8963ed4e16372f8090cad2c60e02f009504ce65538bbb684b466b21be3a90e3740f185d7089d37b75f0cf62b6e7680e08d84ddcb0102cf01b85c0b592bb6e508e20b5d317052b75de121908390363201abff3476ef0180c0caf384a302024b81076c8ad0cfe84cc32fe0813d63cdd0f7d8d0e56d82aa3f58cbbe49d4c61e2b017aaf3074be7ecb30a769595758e4da7c7c87ead864baf89b679b73153dfa352c02080000000001d150da00");
|
||||
Assert.Equal(share.BlockHeight, 224);
|
||||
Assert.Equal(share.Difficulty, 1000);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using MiningCore.Extensions;
|
||||
using MiningCore.Native;
|
||||
using Xunit;
|
||||
|
||||
namespace MiningCore.Tests.Crypto
|
||||
{
|
||||
public class CrytonoteTests : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void Crytonote_Hash_Slow()
|
||||
{
|
||||
var blobConverted = "0106a2aaafd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b42580100a4b1e2f4baf6ab7109071ab59bc52dba740d1de99fa0ae0c4afd6ea9f40c5d87ec01".HexToByteArray();
|
||||
var result = LibCryptonote.CryptonightHashSlow(blobConverted, 0).ToHexString();
|
||||
|
||||
Assert.Equal("a845ffbdf83ae9a8ffa504a1011efbd5ed2294bb9da591d3b583740568402c00", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_SlowHash_Should_Throw_On_Null_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => LibCryptonote.CryptonightHashSlow(null, 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Crytonote_Hash_Fast()
|
||||
{
|
||||
var blobConverted = "0106a2aaafd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b42580100a4b1e2f4baf6ab7109071ab59bc52dba740d1de99fa0ae0c4afd6ea9f40c5d87ec01".HexToByteArray();
|
||||
var result = LibCryptonote.CryptonightHashFast(blobConverted).ToHexString();
|
||||
|
||||
Assert.Equal("ddc0e3a33b605ce39fa2d16a98d7634e33399ab1e4b56b3bdd3414b655fe9a98", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_FastHash_Should_Throw_On_Null_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => LibCryptonote.CryptonightHashFast(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Crytonote_Hash_Slow_Lite()
|
||||
{
|
||||
var blobConverted = "0106f1adafd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b42597710c48c6d885e2622f40f82ecd9b9fd538f28df9b0557e07cd3237a31c76569ada98001".HexToByteArray();
|
||||
var result = LibCryptonote.CryptonightHashSlowLite(blobConverted).ToHexString();
|
||||
|
||||
Assert.Equal("0769caee428a232cffb76fa200f174ff962734f24e7b3bf8d1b0d4e8ba6ceebf", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Crytonote_ConvertBlob()
|
||||
{
|
||||
var blob = "0106e5b3afd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b421c0300a401d90101ff9d0106d6d6a88702023c62e43372a58cb588147e20be53a27083f5c522f33c722b082ab7518c48cda280b4c4c32102609ec96e2499ee267d70efefc49f26e330526d3ef455314b7b5ba268a6045f8c80c0fc82aa0202fe5cc0fa56c4277d1a47827edce4725571529d57f33c73ada481ef84c323f30a8090cad2c60e02d88bf5e72a611c8b8464ce29e3b1adbfe1ae163886d9150fe511171cada98fcb80e08d84ddcb0102441915aaf9fbaf70ff454c701a6ae2bd59bb94dc0b888bf7e5d06274ee9238ca80c0caf384a302024078526e2132def44bde2806242652f5944e632f7d94290dd6ee5dda1929f5ee2b016e29f25f07ec2a8df59f0e118a6c9a4b769b745dc0c729071f6e0399d2585745020800000000012e7f76000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".HexToByteArray();
|
||||
var result = LibCryptonote.ConvertBlob(blob, 330).ToHexString();
|
||||
|
||||
Assert.Equal("0106e5b3afd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b421c0300a4487286e262e95b8d2163a0c8b73527e8c9425adbdc4e532cf0ef4241f9ffbe9e01", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_ConvertBlob_Should_Throw_On_Null_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => LibCryptonote.ConvertBlob(null, 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Crytonote_DecodeAddress()
|
||||
{
|
||||
var address = "48nhyWcSey31ngSEhV8j8NPm6B8PistCQJBjjDjmTvRSTWYg6iocAw131vE2JPh3ps33vgQDKLrUx3fcErusYWcMJBxpm1d";
|
||||
var result = LibCryptonote.DecodeAddress(address);
|
||||
|
||||
Assert.Equal(18ul, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_DecodeAddress_Should_Throw_On_Null_Or_Empty_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => LibCryptonote.DecodeAddress(null));
|
||||
Assert.Throws<ArgumentException>(() => LibCryptonote.DecodeAddress(""));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Crytonote_DecodeIntegratedAddress()
|
||||
{
|
||||
var address = "4BrL51JCc9NGQ71kWhnYoDRffsDZy7m1HUU7MRU4nUMXAHNFBEJhkTZV9HdaL4gfuNBxLPc3BeMkLGaPbF5vWtANQsGwTGg55Kq4p3ENE7";
|
||||
var result = LibCryptonote.DecodeIntegratedAddress(address);
|
||||
|
||||
Assert.Equal(19ul, result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace MiningCore.Tests.Crypto
|
|||
private static readonly byte[] testValue2 = Enumerable.Repeat((byte)0x80, 80).ToArray();
|
||||
|
||||
[Fact]
|
||||
public void Blake_Hash_Should_Match()
|
||||
public void Blake_Hash()
|
||||
{
|
||||
var hasher = new Blake();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -34,7 +34,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Blake2s_Hash_Should_Match()
|
||||
public void Blake2s_Hash()
|
||||
{
|
||||
var hasher = new Blake2s();
|
||||
var result = hasher.Digest(testValue2).ToHexString();
|
||||
|
@ -50,7 +50,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Groestl_Hash_Should_Match()
|
||||
public void Groestl_Hash()
|
||||
{
|
||||
var hasher = new Groestl();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -66,7 +66,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Kezzak_Hash_Should_Match()
|
||||
public void Kezzak_Hash()
|
||||
{
|
||||
var hasher = new Kezzak();
|
||||
var result = hasher.Digest(testValue, 0ul).ToHexString();
|
||||
|
@ -82,7 +82,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Scrypt_Hash_Should_Match()
|
||||
public void Scrypt_Hash()
|
||||
{
|
||||
var hasher = new Scrypt(1024, 1);
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -98,7 +98,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void NeoScrypt_Hash_Should_Match()
|
||||
public void NeoScrypt_Hash()
|
||||
{
|
||||
var hasher = new NeoScrypt(0);
|
||||
var result = hasher.Digest(testValue2).ToHexString();
|
||||
|
@ -114,7 +114,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void ScryptN_Hash_Should_Match()
|
||||
public void ScryptN_Hash()
|
||||
{
|
||||
var clock = new MockMasterClock { CurrentTime = new DateTime(2017, 10, 16) };
|
||||
var hasher = new ScryptN(clock, new []{ Tuple.Create(2048L, 1389306217L) });
|
||||
|
@ -132,7 +132,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Lyra2Rev2_Hash_Should_Match()
|
||||
public void Lyra2Rev2_Hash()
|
||||
{
|
||||
var hasher = new Lyra2Rev2();
|
||||
var result = hasher.Digest(Enumerable.Repeat((byte) 5, 80).ToArray()).ToHexString();
|
||||
|
@ -155,7 +155,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Sha256D_Hash_Should_Match()
|
||||
public void Sha256D_Hash()
|
||||
{
|
||||
var hasher = new Sha256D();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -171,7 +171,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Sha256S_Hash_Should_Match()
|
||||
public void Sha256S_Hash()
|
||||
{
|
||||
var hasher = new Sha256S();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -187,7 +187,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void X11_Hash_Should_Match()
|
||||
public void X11_Hash()
|
||||
{
|
||||
var hasher = new X11();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -203,7 +203,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void X17_Hash_Should_Match()
|
||||
public void X17_Hash()
|
||||
{
|
||||
var hasher = new X17();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -219,7 +219,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Skein_Hash_Should_Match()
|
||||
public void Skein_Hash()
|
||||
{
|
||||
var hasher = new Skein();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -235,7 +235,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Qubit_Hash_Should_Match()
|
||||
public void Qubit_Hash()
|
||||
{
|
||||
var hasher = new Qubit();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -251,7 +251,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void GroestlMyriad_Hash_Should_Match()
|
||||
public void GroestlMyriad_Hash()
|
||||
{
|
||||
var hasher = new GroestlMyriad();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -267,7 +267,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void DigestReverser_Hash_Should_Match()
|
||||
public void DigestReverser_Hash()
|
||||
{
|
||||
var hasher = new DigestReverser(new Sha256S());
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -317,7 +317,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Sha3_256_Hash_Should_Match()
|
||||
public void Sha3_256_Hash()
|
||||
{
|
||||
var hasher = new Sha3_256();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
@ -333,7 +333,7 @@ namespace MiningCore.Tests.Crypto
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Sha3_512_Hash_Should_Match()
|
||||
public void Sha3_512_Hash()
|
||||
{
|
||||
var hasher = new Sha3_512();
|
||||
var result = hasher.Digest(testValue).ToHexString();
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MiningCore.Extensions;
|
||||
using MiningCore.Native;
|
||||
using Xunit;
|
||||
|
||||
namespace MiningCore.Tests.Native
|
||||
{
|
||||
public class HashinLibCryptonoteTestsgTests : TestBase
|
||||
{
|
||||
private static readonly byte[] testValue = Enumerable.Repeat((byte)0x80, 128).ToArray();
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_SlowHash_Should_Match()
|
||||
{
|
||||
var result = LibCryptonote.CryptonightHashSlow(testValue).ToHexString();
|
||||
|
||||
Assert.Equal("9a267e32aefcc40ab12a906fd3f2de45a24a5ccde9e8b84528e656577f14e0fe", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_SlowHash_Should_Throw_On_Null_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => LibCryptonote.CryptonightHashSlow(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_FastHash_Should_Match()
|
||||
{
|
||||
var result = LibCryptonote.CryptonightHashFast(testValue).ToHexString();
|
||||
|
||||
Assert.Equal("80ad002b1c333a29913d9edb5340412b121c0e9045e59fa9b2aabb53f9dcc92d", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_FastHash_Should_Throw_On_Null_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => LibCryptonote.CryptonightHashFast(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_DecodeAddress_Should_Match()
|
||||
{
|
||||
var result = LibCryptonote.DecodeAddress("9wviCeWe2D8XS82k2ovp5EUYLzBt9pYNW2LXUFsZiv8S3Mt21FZ5qQaAroko1enzw3eGr9qC7X1D7Geoo2RrAotYPwq9Gm8");
|
||||
Assert.Equal(53u, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_DecodeAddress_Should_Throw_On_Null_Or_Empty_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => LibCryptonote.DecodeAddress(null));
|
||||
Assert.Throws<ArgumentException>(() => LibCryptonote.DecodeAddress(""));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_ConvertBlob_Should_Match()
|
||||
{
|
||||
var blob = "0105bfdfcecd05583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b420000000001d90101ff9d0106d6d6a88702020a79e36c5f5ac69abb68daa616b70e4dc911ed2edf50133fc121447cc403cd6780b4c4c32102b3adc5521c68a35e2dd1934e30b5fada872b384dbbf8c4e8130e43bd0097b8b680c0fc82aa0202b186f6745517ec23a87df7811849d71914a222c937da3e3a39c7bde6f27d2dc98090cad2c60e02df3a6eed49d05b0163986888ebe7da3fae808a72f3beec97346e0a18a960a7b180e08d84ddcb0102f37220a0c601e2dfe78cfab584cabeecf59079b3b2ee045561fb83ebf67941ba80c0caf384a30202b5e50c62333f3237d497eac37b26bd1217b6996eeb7d45e099b71b0f0b5399162b011c2515730ca7e8bb9b79e177557a1fa8b41e9aee544b25d69dc46f12f66b13f102080000000001ff0d7500".HexToByteArray();
|
||||
var result = LibCryptonote.ConvertBlob(blob, blob.Length).ToHexString();
|
||||
var expected = "0105bfdfcecd05583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b4200000000f262fa431f692fa1d8a6e89fb809487a2133dd6fd999d95c664b964df354ac4701";
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cryptonote_ConvertBlob_Should_Throw_On_Null_Argument()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => LibCryptonote.ConvertBlob(null, 0));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,9 +34,9 @@ namespace MiningCore
|
|||
//////////////////////
|
||||
// outgoing mappings
|
||||
|
||||
CreateMap<IShare, Share>();
|
||||
CreateMap<Blockchain.Share, Persistence.Model.Share>();
|
||||
|
||||
CreateMap<IShare, Block>()
|
||||
CreateMap<Blockchain.Share, Block>()
|
||||
.ForMember(dest => dest.Reward, opt => opt.MapFrom(src => src.BlockReward))
|
||||
.ForMember(dest => dest.Hash, opt => opt.MapFrom(src => src.BlockHash))
|
||||
.ForMember(dest => dest.Status, opt => opt.Ignore());
|
||||
|
@ -69,7 +69,7 @@ namespace MiningCore
|
|||
CreateMap<WorkerPerformanceStatsContainer, Api.Responses.WorkerPerformanceStatsContainer>();
|
||||
|
||||
// PostgreSQL
|
||||
CreateMap<Share, Persistence.Postgres.Entities.Share>();
|
||||
CreateMap<Persistence.Model.Share, Persistence.Postgres.Entities.Share>();
|
||||
CreateMap<Block, Persistence.Postgres.Entities.Block>();
|
||||
CreateMap<Balance, Persistence.Postgres.Entities.Balance>();
|
||||
CreateMap<Payment, Persistence.Postgres.Entities.Payment>();
|
||||
|
@ -82,7 +82,7 @@ namespace MiningCore
|
|||
// incoming mappings
|
||||
|
||||
// PostgreSQL
|
||||
CreateMap<Persistence.Postgres.Entities.Share, Share>();
|
||||
CreateMap<Persistence.Postgres.Entities.Share, Persistence.Model.Share>();
|
||||
CreateMap<Persistence.Postgres.Entities.Block, Block>();
|
||||
CreateMap<Persistence.Postgres.Entities.Balance, Balance>();
|
||||
CreateMap<Persistence.Postgres.Entities.Payment, Payment>();
|
||||
|
|
|
@ -37,84 +37,4 @@ namespace MiningCore.Blockchain
|
|||
{
|
||||
string Next();
|
||||
}
|
||||
|
||||
public interface IShare
|
||||
{
|
||||
/// <summary>
|
||||
/// The pool originating this share from
|
||||
/// </summary>
|
||||
string PoolId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Who mined it (wallet address)
|
||||
/// </summary>
|
||||
string Miner { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Who mined it
|
||||
/// </summary>
|
||||
string Worker { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Extra information for payout processing
|
||||
/// </summary>
|
||||
string PayoutInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mining Software
|
||||
/// </summary>
|
||||
string UserAgent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// From where was it submitted
|
||||
/// </summary>
|
||||
string IpAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Submission source (pool, external stratum etc)
|
||||
/// </summary>
|
||||
string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stratum difficulty assigned to the miner at the time the share was submitted/accepted (used for payout
|
||||
/// calculations)
|
||||
/// </summary>
|
||||
double Difficulty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block this share refers to
|
||||
/// </summary>
|
||||
long BlockHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block reward after deducting pool fee and donations
|
||||
/// </summary>
|
||||
decimal BlockReward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block hash
|
||||
/// </summary>
|
||||
string BlockHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If this share presumably resulted in a block
|
||||
/// </summary>
|
||||
bool IsBlockCandidate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Arbitrary data to be interpreted by the payment processor specialized
|
||||
/// in this coin to verify this block candidate was accepted by the network
|
||||
/// </summary>
|
||||
string TransactionConfirmationData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Network difficulty at the time the share was submitted (used for some payout schemes like PPLNS)
|
||||
/// </summary>
|
||||
double NetworkDifficulty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the share was found
|
||||
/// </summary>
|
||||
DateTime Created { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,15 +99,12 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
|
||||
protected virtual void BuildCoinbase()
|
||||
{
|
||||
var extraNoncePlaceHolderLengthByte = (byte) extraNoncePlaceHolderLength;
|
||||
|
||||
// generate script parts
|
||||
var sigScriptInitial = GenerateScriptSigInitial();
|
||||
var sigScriptInitialBytes = sigScriptInitial.ToBytes();
|
||||
|
||||
var sigScriptLength = (uint) (
|
||||
sigScriptInitial.Length +
|
||||
1 + // for extranonce-placeholder length after sigScriptInitial
|
||||
extraNoncePlaceHolderLength +
|
||||
scriptSigFinalBytes.Length);
|
||||
|
||||
|
@ -138,9 +135,6 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
bs.ReadWriteAsVarInt(ref sigScriptLength);
|
||||
bs.ReadWrite(ref sigScriptInitialBytes);
|
||||
|
||||
// emit a simulated OP_PUSH(n) just without the payload (which is filled in by the miner: extranonce1 and extranonce2)
|
||||
bs.ReadWrite(ref extraNoncePlaceHolderLengthByte);
|
||||
|
||||
// done
|
||||
coinbaseInitial = stream.ToArray();
|
||||
coinbaseInitialHex = coinbaseInitial.ToHexString();
|
||||
|
@ -235,6 +229,9 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
// push timestamp
|
||||
ops.Add(Op.GetPushOp(now));
|
||||
|
||||
// push placeholder
|
||||
ops.Add(Op.GetPushOp((uint) 0));
|
||||
|
||||
return new Script(ops);
|
||||
}
|
||||
|
||||
|
@ -289,7 +286,7 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
return blockHeader.ToBytes();
|
||||
}
|
||||
|
||||
protected virtual BitcoinShare ProcessShareInternal(StratumClient worker, string extraNonce2, uint nTime, uint nonce)
|
||||
protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumClient worker, string extraNonce2, uint nTime, uint nonce)
|
||||
{
|
||||
var context = worker.GetContextAs<BitcoinWorkerContext>();
|
||||
var extraNonce1 = context.ExtraNonce1;
|
||||
|
@ -330,24 +327,26 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
|
||||
}
|
||||
|
||||
var result = new BitcoinShare
|
||||
var result = new Share
|
||||
{
|
||||
BlockHeight = BlockTemplate.Height,
|
||||
BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC),
|
||||
NetworkDifficulty = Difficulty * shareMultiplier,
|
||||
Difficulty = stratumDifficulty,
|
||||
};
|
||||
|
||||
var blockBytes = SerializeBlock(headerBytes, coinbase);
|
||||
|
||||
if (isBlockCandidate)
|
||||
{
|
||||
result.IsBlockCandidate = true;
|
||||
result.BlockHex = blockBytes.ToHexString();
|
||||
result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC);
|
||||
result.BlockHash = blockHasher.Digest(headerBytes, nTime).ToHexString();
|
||||
|
||||
var blockBytes = SerializeBlock(headerBytes, coinbase);
|
||||
var blockHex = blockBytes.ToHexString();
|
||||
|
||||
return (result, blockHex);
|
||||
}
|
||||
|
||||
return result;
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
protected virtual byte[] SerializeCoinbase(string extraNonce1, string extraNonce2)
|
||||
|
@ -479,7 +478,7 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
return jobParams;
|
||||
}
|
||||
|
||||
public virtual BitcoinShare ProcessShare(StratumClient worker,
|
||||
public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker,
|
||||
string extraNonce2, string nTime, string nonce)
|
||||
{
|
||||
Contract.RequiresNonNull(worker, nameof(worker));
|
||||
|
|
|
@ -20,6 +20,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reactive.Linq;
|
||||
|
@ -269,23 +270,25 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
BlockchainStats.ConnectedPeers = networkInfoResponse.Connections;
|
||||
}
|
||||
|
||||
protected virtual async Task<(bool Accepted, string CoinbaseTransaction)> SubmitBlockAsync(BitcoinShare share)
|
||||
protected virtual async Task<(bool Accepted, string CoinbaseTransaction)> SubmitBlockAsync(Share share, string blockHex)
|
||||
{
|
||||
// execute command batch
|
||||
var results = await daemon.ExecuteBatchAnyAsync(
|
||||
hasSubmitBlockMethod
|
||||
? new DaemonCmd(BitcoinCommands.SubmitBlock, new[] { share.BlockHex })
|
||||
: new DaemonCmd(BitcoinCommands.GetBlockTemplate, new { mode = "submit", data = share.BlockHex }),
|
||||
? new DaemonCmd(BitcoinCommands.SubmitBlock, new[] { blockHex })
|
||||
: new DaemonCmd(BitcoinCommands.GetBlockTemplate, new { mode = "submit", data = blockHex }),
|
||||
new DaemonCmd(BitcoinCommands.GetBlock, new[] { share.BlockHash }));
|
||||
|
||||
// did submission succeed?
|
||||
var submitResult = results[0];
|
||||
var submitError = submitResult.Error?.Message ?? submitResult.Response?.ToString();
|
||||
var submitError = submitResult.Error?.Message ??
|
||||
submitResult.Error?.Code.ToString(CultureInfo.InvariantCulture) ??
|
||||
submitResult.Response?.ToString();
|
||||
|
||||
if (!string.IsNullOrEmpty(submitError))
|
||||
{
|
||||
logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} submission failed with: {submitError}");
|
||||
notificationService.NotifyAdmin("Block submission failed", $"Block {share.BlockHeight} submission failed with: {submitError}");
|
||||
notificationService.NotifyAdmin($"[{share.PoolId.ToUpper()}]-[{share.Source}] Block submission failed", $"[{share.PoolId.ToUpper()}]-[{share.Source}] Block {share.BlockHeight} submission failed with: {submitError}");
|
||||
|
||||
return (false, null);
|
||||
}
|
||||
|
@ -298,7 +301,7 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
if (!accepted)
|
||||
{
|
||||
logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission");
|
||||
notificationService.NotifyAdmin("Block submission failed", $"Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission");
|
||||
notificationService.NotifyAdmin($"[{share.PoolId.ToUpper()}]-[{share.Source}] Block submission failed", $"[{share.PoolId.ToUpper()}]-[{share.Source}] Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission");
|
||||
}
|
||||
|
||||
return (accepted, block?.Transactions.FirstOrDefault());
|
||||
|
@ -445,7 +448,7 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
return job.BlockTemplate.Transactions.Select(x => x.Data).ToArray();
|
||||
}
|
||||
|
||||
public virtual async Task<BitcoinShare> SubmitShareAsync(StratumClient worker, object submission,
|
||||
public virtual async Task<Share> SubmitShareAsync(StratumClient worker, object submission,
|
||||
double stratumDifficultyBase)
|
||||
{
|
||||
Contract.RequiresNonNull(worker, nameof(worker));
|
||||
|
@ -484,14 +487,23 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
var workerName = split.Length > 1 ? split[1] : null;
|
||||
|
||||
// validate & process
|
||||
var share = job.ProcessShare(worker, extraNonce2, nTime, nonce);
|
||||
var (share, blockHex) = job.ProcessShare(worker, extraNonce2, nTime, nonce);
|
||||
|
||||
// enrich share with common data
|
||||
share.PoolId = poolConfig.Id;
|
||||
share.IpAddress = worker.RemoteEndpoint.Address.ToString();
|
||||
share.Miner = minerName;
|
||||
share.Worker = workerName;
|
||||
share.UserAgent = context.UserAgent;
|
||||
share.Source = clusterConfig.ClusterName;
|
||||
share.Created = clock.Now;
|
||||
|
||||
// if block candidate, submit & check if accepted by network
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight} [{share.BlockHash}]");
|
||||
|
||||
var acceptResponse = await SubmitBlockAsync(share);
|
||||
var acceptResponse = await SubmitBlockAsync(share, blockHex);
|
||||
|
||||
// is it still a block candidate?
|
||||
share.IsBlockCandidate = acceptResponse.Accepted;
|
||||
|
@ -512,15 +524,6 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
}
|
||||
}
|
||||
|
||||
// enrich share with common data
|
||||
share.PoolId = poolConfig.Id;
|
||||
share.IpAddress = worker.RemoteEndpoint.Address.ToString();
|
||||
share.Miner = minerName;
|
||||
share.Worker = workerName;
|
||||
share.UserAgent = context.UserAgent;
|
||||
share.Source = clusterConfig.ClusterName;
|
||||
share.Created = clock.Now;
|
||||
|
||||
return share;
|
||||
}
|
||||
|
||||
|
@ -666,7 +669,8 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
else
|
||||
networkType = daemonInfoResponse.Testnet ? BitcoinNetworkType.Test : BitcoinNetworkType.Main;
|
||||
|
||||
ConfigureRewards();
|
||||
if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
|
||||
ConfigureRewards();
|
||||
|
||||
// update stats
|
||||
BlockchainStats.NetworkType = networkType.ToString();
|
||||
|
|
|
@ -40,7 +40,7 @@ using NLog;
|
|||
|
||||
namespace MiningCore.Blockchain.Bitcoin
|
||||
{
|
||||
public class BitcoinPoolBase<TJob, TBlockTemplate> : PoolBase<BitcoinShare>
|
||||
public class BitcoinPoolBase<TJob, TBlockTemplate> : PoolBase
|
||||
where TBlockTemplate : BlockTemplate
|
||||
where TJob : BitcoinJob<TBlockTemplate>, new()
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
private static readonly IHashAlgorithm qubit = new Qubit();
|
||||
private static readonly IHashAlgorithm groestlMyriad = new GroestlMyriad();
|
||||
private static readonly IHashAlgorithm neoScryptProfile1 = new NeoScrypt(0x80000620);
|
||||
private static readonly IHashAlgorithm vergeBlockHasher = new DigestReverser(scrypt_1024_1);
|
||||
|
||||
private static readonly BitcoinCoinProperties sha256Coin =
|
||||
new BitcoinCoinProperties(1, sha256D, sha256D, sha256DReverse, "Sha256");
|
||||
|
@ -79,16 +80,19 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
new BitcoinCoinProperties(Math.Pow(2, 16), sha256D, neoScryptProfile1, new DigestReverser(neoScryptProfile1), "Neoscrypt");
|
||||
|
||||
private static readonly BitcoinCoinProperties vergeLyraCoin =
|
||||
new BitcoinCoinProperties(Math.Pow(2, 8), sha256D, lyra2Rev2, new DigestReverser(scrypt_1024_1), "Lyra2re2");
|
||||
new BitcoinCoinProperties(Math.Pow(2, 8), sha256D, lyra2Rev2, vergeBlockHasher, "Lyra2re2");
|
||||
|
||||
private static readonly BitcoinCoinProperties vergeBlake2sCoin =
|
||||
new BitcoinCoinProperties(1, sha256D, blake2s, new DigestReverser(scrypt_1024_1), "Blake2s");
|
||||
new BitcoinCoinProperties(1, sha256D, blake2s, vergeBlockHasher, "Blake2s");
|
||||
|
||||
private static readonly BitcoinCoinProperties vergeX17Coin =
|
||||
new BitcoinCoinProperties(1, x17, blake2s, new DigestReverser(scrypt_1024_1), "X17");
|
||||
new BitcoinCoinProperties(1, sha256D, x17, vergeBlockHasher, "X17");
|
||||
|
||||
private static readonly BitcoinCoinProperties vergeScryptCoin =
|
||||
new BitcoinCoinProperties(Math.Pow(2, 16), sha256D, scrypt_1024_1, vergeBlockHasher, "Scrypt");
|
||||
|
||||
private static readonly BitcoinCoinProperties vergeGroestlCoin =
|
||||
new BitcoinCoinProperties(1, groestlMyriad, blake2s, new DigestReverser(scrypt_1024_1), "Groestl-Myriad");
|
||||
new BitcoinCoinProperties(1, sha256D, groestlMyriad, vergeBlockHasher, "Groestl-Myriad");
|
||||
|
||||
private static readonly Dictionary<CoinType, BitcoinCoinProperties> coinProperties = new Dictionary<CoinType, BitcoinCoinProperties>
|
||||
{
|
||||
|
@ -97,7 +101,7 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
{ CoinType.BCH, sha256Coin },
|
||||
{ CoinType.NMC, sha256Coin },
|
||||
{ CoinType.PPC, sha256Coin },
|
||||
{ CoinType.GLT, sha256Coin },
|
||||
{ CoinType.GLT, sha256Coin },
|
||||
|
||||
// Scrypt
|
||||
{ CoinType.LTC, scryptCoin },
|
||||
|
@ -145,9 +149,10 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
{
|
||||
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(algorithm), $"{nameof(algorithm)} must not be empty");
|
||||
|
||||
switch(algorithm.ToLower())
|
||||
switch (algorithm.ToLower())
|
||||
{
|
||||
case "sha256d":
|
||||
case "sha256":
|
||||
return sha256Coin;
|
||||
|
||||
case "skein":
|
||||
|
@ -184,7 +189,7 @@ namespace MiningCore.Blockchain.Bitcoin
|
|||
return vergeBlake2sCoin;
|
||||
|
||||
default: // scrypt
|
||||
return scryptCoin;
|
||||
return vergeScryptCoin;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 Coin Foundry (coinfoundry.org)
|
||||
Authors: Oliver Weichhold (oliver@weichhold.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace MiningCore.Blockchain.Bitcoin
|
||||
{
|
||||
public class BitcoinShare : ShareBase
|
||||
{
|
||||
public string BlockHex { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,150 +1,154 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MiningCore.Blockchain.Bitcoin;
|
||||
using MiningCore.Blockchain.Ethereum;
|
||||
using MiningCore.Configuration;
|
||||
|
||||
namespace MiningCore.Blockchain
|
||||
{
|
||||
public static class CoinMetaData
|
||||
{
|
||||
public const string BlockHeightPH = "$height$";
|
||||
public const string BlockHashPH = "$hash$";
|
||||
|
||||
public static readonly Dictionary<CoinType, Dictionary<string, string>> BlockInfoLinks = new Dictionary<CoinType, Dictionary<string, string>>
|
||||
{
|
||||
{ CoinType.ETH, new Dictionary<string, string>
|
||||
{
|
||||
{ string.Empty, $"https://etherscan.io/block/{BlockHeightPH}" },
|
||||
{ EthereumConstants.BlockTypeUncle, $"https://etherscan.io/uncle/{BlockHeightPH}" },
|
||||
}},
|
||||
|
||||
{ CoinType.ETC, new Dictionary<string, string>
|
||||
{
|
||||
{ string.Empty, $"https://gastracker.io/block/{BlockHeightPH}" },
|
||||
{ EthereumConstants.BlockTypeUncle, $"https://gastracker.io/uncle/{BlockHeightPH}" }
|
||||
}},
|
||||
|
||||
{ CoinType.XMR, new Dictionary<string, string> { { string.Empty, $"https://chainradar.com/xmr/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.ETN, new Dictionary<string, string> { { string.Empty, $"https://blockexplorer.electroneum.com/block/{BlockHeightPH}" } }},
|
||||
{ CoinType.LTC, new Dictionary<string, string> { { string.Empty, $"https://chainz.cryptoid.info/ltc/block.dws?{BlockHeightPH}.htm" } }},
|
||||
{ CoinType.BCH, new Dictionary<string, string> { { string.Empty, $"https://www.blocktrail.com/BCC/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.DASH, new Dictionary<string, string> { { string.Empty, $"https://chainz.cryptoid.info/dash/block.dws?{BlockHeightPH}.htm" }}},
|
||||
{ CoinType.BTC, new Dictionary<string, string> { { string.Empty, $"https://blockchain.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.DOGE, new Dictionary<string, string> { { string.Empty, $"https://dogechain.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.ZEC, new Dictionary<string, string> { { string.Empty, $"https://explorer.zcha.in/blocks/{BlockHashPH}" } }},
|
||||
{ CoinType.BTCP, new Dictionary<string, string> { { string.Empty, $"http://explorer.btcprivate.org/block/{BlockHashPH}" } }},
|
||||
{ CoinType.ZCL, new Dictionary<string, string> { { string.Empty, $"http://explorer.zclmine.pro/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.ZEN, new Dictionary<string, string> { { string.Empty, $"http://explorer.zensystem.io/block/{BlockHashPH}" } }},
|
||||
{ CoinType.DGB, new Dictionary<string, string> { { string.Empty, $"https://digiexplorer.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.NMC, new Dictionary<string, string> { { string.Empty, $"https://explorer.namecoin.info/b/{BlockHeightPH}" }}},
|
||||
{ CoinType.GRS, new Dictionary<string, string> { { string.Empty, $"https://groestlsight.groestlcoin.org/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.MONA, new Dictionary<string, string> { { string.Empty, $"https://bchain.info/MONA/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.GLT, new Dictionary<string, string> { { string.Empty, $"https://bchain.info/GLT/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.VTC, new Dictionary<string, string> { { string.Empty, $"https://bchain.info/VTC/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.BTG, new Dictionary<string, string> { { string.Empty, $"https://btg-bitcore2.trezor.io/block/{BlockHashPH}" } }},
|
||||
{ CoinType.ELLA, new Dictionary<string, string> { { string.Empty, $"https://explorer.ellaism.org/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.EXP, new Dictionary<string, string> { { string.Empty, $"http://www.gander.tech/blocks/{BlockHeightPH}" }}},
|
||||
{ CoinType.AEON, new Dictionary<string, string> { { string.Empty, $"https://chainradar.com/aeon/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.STAK, new Dictionary<string, string> { { string.Empty, $"https://straks.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.MOON, new Dictionary<string, string> { { string.Empty, $"https://chainz.cryptoid.info/moon/block.dws?{BlockHeightPH}.htm" }}},
|
||||
{ CoinType.XVG, new Dictionary<string, string> { { string.Empty, $"https://verge-blockchain.info/block/{BlockHashPH}" } }},
|
||||
};
|
||||
|
||||
public static readonly Dictionary<CoinType, string> TxInfoLinks = new Dictionary<CoinType, string>
|
||||
{
|
||||
{ CoinType.XMR, "https://chainradar.com/xmr/transaction/{0}" },
|
||||
{ CoinType.ETN, "https://blockexplorer.electroneum.com/tx/{0}" },
|
||||
{ CoinType.ETH, "https://etherscan.io/tx/{0}" },
|
||||
{ CoinType.ETC, "https://gastracker.io/tx/{0}" },
|
||||
{ CoinType.LTC, "https://chainz.cryptoid.info/ltc/tx.dws?{0}.htm" },
|
||||
{ CoinType.BCH, "https://www.blocktrail.com/BCC/tx/{0}" },
|
||||
{ CoinType.DASH, "https://chainz.cryptoid.info/dash/tx.dws?{0}.htm" },
|
||||
{ CoinType.BTC, "https://blockchain.info/tx/{0}" },
|
||||
{ CoinType.DOGE, "https://dogechain.info/tx/{0}" },
|
||||
{ CoinType.ZEC, "https://explorer.zcha.in/transactions/{0}" },
|
||||
{ CoinType.ZCL, "http://explorer.zclmine.pro/transactions/{0}" },
|
||||
{ CoinType.ZEN, "http://explorer.zensystem.io/transactions/{0}" },
|
||||
{ CoinType.BTCP, "https://explorer.btcprivate.org/transactions/{0}" },
|
||||
{ CoinType.DGB, "https://digiexplorer.info/tx/{0}" },
|
||||
{ CoinType.NMC, "https://explorer.namecoin.info/tx/{0}" },
|
||||
{ CoinType.GRS, "https://groestlsight.groestlcoin.org/tx/{0}" },
|
||||
{ CoinType.MONA, "https://bchain.info/MONA/tx/{0}" },
|
||||
{ CoinType.STAK, "https://straks.info/transaction/{0}" },
|
||||
{ CoinType.GLT, "https://bchain.info/GLT/tx/{0}" },
|
||||
{ CoinType.VTC, "https://bchain.info/VTC/tx/{0}" },
|
||||
{ CoinType.BTG, "https://btgexp.com/tx/{0}" },
|
||||
{ CoinType.ELLA, "https://explorer.ellaism.org/tx/{0}" },
|
||||
{ CoinType.EXP, "http://www.gander.tech/tx/{0}" },
|
||||
{ CoinType.AEON, "https://chainradar.com/aeon/transaction/{0}" },
|
||||
{ CoinType.MOON, "https://chainz.cryptoid.info/moon/tx.dws?{0}.htm" },
|
||||
{ CoinType.XVG, "https://verge-blockchain.info/tx/{0}" },
|
||||
{ CoinType.GBX, "http://gobyte.ezmine.io/tx/{0}" },
|
||||
{ CoinType.CRC, "http://explorer.cryptopros.us/tx/{0}" },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<CoinType, string> AddressInfoLinks = new Dictionary<CoinType, string>
|
||||
{
|
||||
{ CoinType.ETH, "https://etherscan.io/address/{0}" },
|
||||
{ CoinType.ETC, "https://gastracker.io/addr/{0}" },
|
||||
{ CoinType.LTC, "https://chainz.cryptoid.info/ltc/address.dws?{0}.htm" },
|
||||
{ CoinType.BCH, "https://www.blocktrail.com/BCC/address/{0}" },
|
||||
{ CoinType.DASH, "https://chainz.cryptoid.info/dash/address.dws?{0}.htm" },
|
||||
{ CoinType.BTC, "https://blockchain.info/address/{0}" },
|
||||
{ CoinType.DOGE, "https://dogechain.info/address/{0}" },
|
||||
{ CoinType.ZEC, "https://explorer.zcha.in/accounts/{0}" },
|
||||
{ CoinType.ZCL, "http://explorer.zclmine.pro/accounts/{0}" },
|
||||
{ CoinType.ZEN, "http://explorer.zensystem.io/accounts/{0}" },
|
||||
{ CoinType.DGB, "https://digiexplorer.info/address/{0}" },
|
||||
{ CoinType.NMC, "https://explorer.namecoin.info/a/{0}" },
|
||||
{ CoinType.GRS, "https://groestlsight.groestlcoin.org/address/{0}" },
|
||||
{ CoinType.MONA, "https://bchain.info/MONA/addr/{0}" },
|
||||
{ CoinType.STAK, "https://straks.info/address/{0}" },
|
||||
{ CoinType.GLT, "https://bchain.info/GLT/addr/{0}" },
|
||||
{ CoinType.VTC, "https://bchain.info/VTC/addr/{0}" },
|
||||
{ CoinType.BTG, "https://btgexp.com/address/{0}" },
|
||||
{ CoinType.ELLA, "https://explorer.ellaism.org/addr/{0}" },
|
||||
{ CoinType.EXP, "http://www.gander.tech/address/{0}" },
|
||||
{ CoinType.MOON, "https://chainz.cryptoid.info/moon/address.dws?{0}.htm" },
|
||||
{ CoinType.XVG, "https://verge-blockchain.info/address/{0}" },
|
||||
{ CoinType.GBX, "http://gobyte.ezmine.io/address/{0}" },
|
||||
{ CoinType.CRC, "http://explorer.cryptopros.us/address/{0}" },
|
||||
};
|
||||
|
||||
private const string Ethash = "Dagger-Hashimoto";
|
||||
private const string Cryptonight = "Cryptonight";
|
||||
private const string CryptonightLight = "Cryptonight-Light";
|
||||
|
||||
public static readonly Dictionary<CoinType, Func<CoinType, string, string>> CoinAlgorithm = new Dictionary<CoinType, Func<CoinType, string, string>>
|
||||
{
|
||||
{ CoinType.ETH, (coin, alg)=> Ethash },
|
||||
{ CoinType.ETC, (coin, alg)=> Ethash },
|
||||
{ CoinType.LTC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BCH, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.DASH, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BTC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.DOGE, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ZEC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ZCL, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BTCP, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ZEN, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.DGB, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.NMC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.GRS, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.MONA, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.STAK, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.GLT, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.VTC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BTG, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ELLA, (coin, alg)=> Ethash },
|
||||
{ CoinType.EXP, (coin, alg)=> Ethash },
|
||||
{ CoinType.MOON, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.XVG, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.XMR, (coin, alg)=> Cryptonight },
|
||||
{ CoinType.ETN, (coin, alg)=> Cryptonight },
|
||||
{ CoinType.AEON, (coin, alg)=> CryptonightLight },
|
||||
{ CoinType.GBX, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.CRC, BitcoinProperties.GetAlgorithm },
|
||||
};
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MiningCore.Blockchain.Bitcoin;
|
||||
using MiningCore.Blockchain.Ethereum;
|
||||
using MiningCore.Configuration;
|
||||
|
||||
namespace MiningCore.Blockchain
|
||||
{
|
||||
public static class CoinMetaData
|
||||
{
|
||||
public const string BlockHeightPH = "$height$";
|
||||
public const string BlockHashPH = "$hash$";
|
||||
|
||||
public static readonly Dictionary<CoinType, Dictionary<string, string>> BlockInfoLinks = new Dictionary<CoinType, Dictionary<string, string>>
|
||||
{
|
||||
{ CoinType.ETH, new Dictionary<string, string>
|
||||
{
|
||||
{ string.Empty, $"https://etherscan.io/block/{BlockHeightPH}" },
|
||||
{ EthereumConstants.BlockTypeUncle, $"https://etherscan.io/uncle/{BlockHeightPH}" },
|
||||
}},
|
||||
|
||||
{ CoinType.ETC, new Dictionary<string, string>
|
||||
{
|
||||
{ string.Empty, $"https://gastracker.io/block/{BlockHeightPH}" },
|
||||
{ EthereumConstants.BlockTypeUncle, $"https://gastracker.io/uncle/{BlockHeightPH}" }
|
||||
}},
|
||||
|
||||
{ CoinType.XMR, new Dictionary<string, string> { { string.Empty, $"https://chainradar.com/xmr/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.ETN, new Dictionary<string, string> { { string.Empty, $"https://blockexplorer.electroneum.com/block/{BlockHeightPH}" } }},
|
||||
{ CoinType.LTC, new Dictionary<string, string> { { string.Empty, $"https://chainz.cryptoid.info/ltc/block.dws?{BlockHeightPH}.htm" } }},
|
||||
{ CoinType.PPC, new Dictionary<string, string> { { string.Empty, $"https://chainz.cryptoid.info/ppc/block.dws?{BlockHeightPH}.htm" } }},
|
||||
{ CoinType.BCH, new Dictionary<string, string> { { string.Empty, $"https://www.blocktrail.com/BCC/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.DASH, new Dictionary<string, string> { { string.Empty, $"https://chainz.cryptoid.info/dash/block.dws?{BlockHeightPH}.htm" }}},
|
||||
{ CoinType.BTC, new Dictionary<string, string> { { string.Empty, $"https://blockchain.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.DOGE, new Dictionary<string, string> { { string.Empty, $"https://dogechain.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.ZEC, new Dictionary<string, string> { { string.Empty, $"https://explorer.zcha.in/blocks/{BlockHashPH}" } }},
|
||||
{ CoinType.BTCP, new Dictionary<string, string> { { string.Empty, $"http://explorer.btcprivate.org/block/{BlockHashPH}" } }},
|
||||
{ CoinType.ZCL, new Dictionary<string, string> { { string.Empty, $"http://explorer.zclmine.pro/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.ZEN, new Dictionary<string, string> { { string.Empty, $"http://explorer.zensystem.io/block/{BlockHashPH}" } }},
|
||||
{ CoinType.DGB, new Dictionary<string, string> { { string.Empty, $"https://digiexplorer.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.NMC, new Dictionary<string, string> { { string.Empty, $"https://explorer.namecoin.info/b/{BlockHeightPH}" }}},
|
||||
{ CoinType.GRS, new Dictionary<string, string> { { string.Empty, $"https://groestlsight.groestlcoin.org/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.MONA, new Dictionary<string, string> { { string.Empty, $"https://bchain.info/MONA/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.GLT, new Dictionary<string, string> { { string.Empty, $"https://bchain.info/GLT/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.VTC, new Dictionary<string, string> { { string.Empty, $"https://bchain.info/VTC/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.BTG, new Dictionary<string, string> { { string.Empty, $"https://btg-bitcore2.trezor.io/block/{BlockHashPH}" } }},
|
||||
{ CoinType.ELLA, new Dictionary<string, string> { { string.Empty, $"https://explorer.ellaism.org/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.EXP, new Dictionary<string, string> { { string.Empty, $"http://www.gander.tech/blocks/{BlockHeightPH}" }}},
|
||||
{ CoinType.AEON, new Dictionary<string, string> { { string.Empty, $"https://chainradar.com/aeon/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.STAK, new Dictionary<string, string> { { string.Empty, $"https://straks.info/block/{BlockHeightPH}" }}},
|
||||
{ CoinType.MOON, new Dictionary<string, string> { { string.Empty, $"https://chainz.cryptoid.info/moon/block.dws?{BlockHeightPH}.htm" }}},
|
||||
{ CoinType.XVG, new Dictionary<string, string> { { string.Empty, $"https://verge-blockchain.info/block/{BlockHashPH}" } }},
|
||||
};
|
||||
|
||||
public static readonly Dictionary<CoinType, string> TxInfoLinks = new Dictionary<CoinType, string>
|
||||
{
|
||||
{ CoinType.XMR, "https://chainradar.com/xmr/transaction/{0}" },
|
||||
{ CoinType.ETN, "https://blockexplorer.electroneum.com/tx/{0}" },
|
||||
{ CoinType.ETH, "https://etherscan.io/tx/{0}" },
|
||||
{ CoinType.ETC, "https://gastracker.io/tx/{0}" },
|
||||
{ CoinType.LTC, "https://chainz.cryptoid.info/ltc/tx.dws?{0}.htm" },
|
||||
{ CoinType.PPC, "https://chainz.cryptoid.info/ppc/tx.dws?{0}.htm" },
|
||||
{ CoinType.BCH, "https://www.blocktrail.com/BCC/tx/{0}" },
|
||||
{ CoinType.DASH, "https://chainz.cryptoid.info/dash/tx.dws?{0}.htm" },
|
||||
{ CoinType.BTC, "https://blockchain.info/tx/{0}" },
|
||||
{ CoinType.DOGE, "https://dogechain.info/tx/{0}" },
|
||||
{ CoinType.ZEC, "https://explorer.zcha.in/transactions/{0}" },
|
||||
{ CoinType.ZCL, "http://explorer.zclmine.pro/transactions/{0}" },
|
||||
{ CoinType.ZEN, "http://explorer.zensystem.io/transactions/{0}" },
|
||||
{ CoinType.BTCP, "https://explorer.btcprivate.org/transactions/{0}" },
|
||||
{ CoinType.DGB, "https://digiexplorer.info/tx/{0}" },
|
||||
{ CoinType.NMC, "https://explorer.namecoin.info/tx/{0}" },
|
||||
{ CoinType.GRS, "https://groestlsight.groestlcoin.org/tx/{0}" },
|
||||
{ CoinType.MONA, "https://bchain.info/MONA/tx/{0}" },
|
||||
{ CoinType.STAK, "https://straks.info/transaction/{0}" },
|
||||
{ CoinType.GLT, "https://bchain.info/GLT/tx/{0}" },
|
||||
{ CoinType.VTC, "https://bchain.info/VTC/tx/{0}" },
|
||||
{ CoinType.BTG, "https://btgexp.com/tx/{0}" },
|
||||
{ CoinType.ELLA, "https://explorer.ellaism.org/tx/{0}" },
|
||||
{ CoinType.EXP, "http://www.gander.tech/tx/{0}" },
|
||||
{ CoinType.AEON, "https://chainradar.com/aeon/transaction/{0}" },
|
||||
{ CoinType.MOON, "https://chainz.cryptoid.info/moon/tx.dws?{0}.htm" },
|
||||
{ CoinType.XVG, "https://verge-blockchain.info/tx/{0}" },
|
||||
{ CoinType.GBX, "http://gobyte.ezmine.io/tx/{0}" },
|
||||
{ CoinType.CRC, "http://explorer.cryptopros.us/tx/{0}" },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<CoinType, string> AddressInfoLinks = new Dictionary<CoinType, string>
|
||||
{
|
||||
{ CoinType.ETH, "https://etherscan.io/address/{0}" },
|
||||
{ CoinType.ETC, "https://gastracker.io/addr/{0}" },
|
||||
{ CoinType.LTC, "https://chainz.cryptoid.info/ltc/address.dws?{0}.htm" },
|
||||
{ CoinType.PPC, "https://chainz.cryptoid.info/ppc/address.dws?{0}.htm" },
|
||||
{ CoinType.BCH, "https://www.blocktrail.com/BCC/address/{0}" },
|
||||
{ CoinType.DASH, "https://chainz.cryptoid.info/dash/address.dws?{0}.htm" },
|
||||
{ CoinType.BTC, "https://blockchain.info/address/{0}" },
|
||||
{ CoinType.DOGE, "https://dogechain.info/address/{0}" },
|
||||
{ CoinType.ZEC, "https://explorer.zcha.in/accounts/{0}" },
|
||||
{ CoinType.ZCL, "http://explorer.zclmine.pro/accounts/{0}" },
|
||||
{ CoinType.ZEN, "http://explorer.zensystem.io/accounts/{0}" },
|
||||
{ CoinType.DGB, "https://digiexplorer.info/address/{0}" },
|
||||
{ CoinType.NMC, "https://explorer.namecoin.info/a/{0}" },
|
||||
{ CoinType.GRS, "https://groestlsight.groestlcoin.org/address/{0}" },
|
||||
{ CoinType.MONA, "https://bchain.info/MONA/addr/{0}" },
|
||||
{ CoinType.STAK, "https://straks.info/address/{0}" },
|
||||
{ CoinType.GLT, "https://bchain.info/GLT/addr/{0}" },
|
||||
{ CoinType.VTC, "https://bchain.info/VTC/addr/{0}" },
|
||||
{ CoinType.BTG, "https://btgexp.com/address/{0}" },
|
||||
{ CoinType.ELLA, "https://explorer.ellaism.org/addr/{0}" },
|
||||
{ CoinType.EXP, "http://www.gander.tech/address/{0}" },
|
||||
{ CoinType.MOON, "https://chainz.cryptoid.info/moon/address.dws?{0}.htm" },
|
||||
{ CoinType.XVG, "https://verge-blockchain.info/address/{0}" },
|
||||
{ CoinType.GBX, "http://gobyte.ezmine.io/address/{0}" },
|
||||
{ CoinType.CRC, "http://explorer.cryptopros.us/address/{0}" },
|
||||
};
|
||||
|
||||
private const string Ethash = "Dagger-Hashimoto";
|
||||
private const string Cryptonight = "Cryptonight";
|
||||
private const string CryptonightLight = "Cryptonight-Light";
|
||||
|
||||
public static readonly Dictionary<CoinType, Func<CoinType, string, string>> CoinAlgorithm = new Dictionary<CoinType, Func<CoinType, string, string>>
|
||||
{
|
||||
{ CoinType.ETH, (coin, alg)=> Ethash },
|
||||
{ CoinType.ETC, (coin, alg)=> Ethash },
|
||||
{ CoinType.LTC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.PPC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BCH, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.DASH, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BTC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.DOGE, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ZEC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ZCL, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BTCP, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ZEN, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.DGB, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.NMC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.GRS, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.MONA, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.STAK, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.GLT, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.VTC, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.BTG, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.ELLA, (coin, alg)=> Ethash },
|
||||
{ CoinType.EXP, (coin, alg)=> Ethash },
|
||||
{ CoinType.MOON, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.XVG, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.XMR, (coin, alg)=> Cryptonight },
|
||||
{ CoinType.ETN, (coin, alg)=> Cryptonight },
|
||||
{ CoinType.AEON, (coin, alg)=> CryptonightLight },
|
||||
{ CoinType.GBX, BitcoinProperties.GetAlgorithm },
|
||||
{ CoinType.CRC, BitcoinProperties.GetAlgorithm },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace MiningCore.Blockchain.Ethereum
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<EthereumShare> ProcessShareAsync(StratumClient worker, string nonce, EthashFull ethash)
|
||||
public async Task<(Share Share, string FullNonceHex, string HeaderHash, string MixHash)> ProcessShareAsync(StratumClient worker, string nonce, EthashFull ethash)
|
||||
{
|
||||
// duplicate nonce?
|
||||
lock(workerNonces)
|
||||
|
@ -98,25 +98,30 @@ namespace MiningCore.Blockchain.Ethereum
|
|||
}
|
||||
|
||||
// create share
|
||||
var share = new EthereumShare
|
||||
var share = new Share
|
||||
{
|
||||
BlockHeight = (long) BlockTemplate.Height,
|
||||
IpAddress = worker.RemoteEndpoint?.Address?.ToString(),
|
||||
Miner = context.MinerName,
|
||||
Worker = context.WorkerName,
|
||||
UserAgent = context.UserAgent,
|
||||
FullNonceHex = "0x" + fullNonceHex,
|
||||
HeaderHash = BlockTemplate.Header,
|
||||
MixHash = mixDigest.ToHexString(true),
|
||||
IsBlockCandidate = isBlockCandidate,
|
||||
Difficulty = stratumDifficulty * EthereumConstants.Pow2x32,
|
||||
BlockHash = mixDigest.ToHexString(true) // OW: is this correct?
|
||||
};
|
||||
|
||||
if (share.IsBlockCandidate)
|
||||
share.TransactionConfirmationData = $"{mixDigest.ToHexString(true)}:{share.FullNonceHex}";
|
||||
{
|
||||
fullNonceHex = "0x" + fullNonceHex;
|
||||
var headerHash = BlockTemplate.Header;
|
||||
var mixHash = mixDigest.ToHexString(true);
|
||||
|
||||
return share;
|
||||
share.TransactionConfirmationData = $"{mixDigest.ToHexString(true)}:{fullNonceHex}";
|
||||
|
||||
return (share, fullNonceHex, headerHash, mixHash);
|
||||
}
|
||||
|
||||
return (share, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,14 +291,14 @@ namespace MiningCore.Blockchain.Ethereum
|
|||
BlockchainStats.ConnectedPeers = peerCount;
|
||||
}
|
||||
|
||||
private async Task<bool> SubmitBlockAsync(EthereumShare share)
|
||||
private async Task<bool> SubmitBlockAsync(Share share, string fullNonceHex, string headerHash, string mixHash)
|
||||
{
|
||||
// submit work
|
||||
var response = await daemon.ExecuteCmdAnyAsync<object>(EC.SubmitWork, new[]
|
||||
{
|
||||
share.FullNonceHex,
|
||||
share.HeaderHash,
|
||||
share.MixHash
|
||||
fullNonceHex,
|
||||
headerHash,
|
||||
mixHash
|
||||
});
|
||||
|
||||
if (response.Error != null || (bool?) response.Response == false)
|
||||
|
@ -393,7 +393,7 @@ namespace MiningCore.Blockchain.Ethereum
|
|||
context.ExtraNonce1 = extraNonceProvider.Next();
|
||||
}
|
||||
|
||||
public async Task<EthereumShare> SubmitShareAsync(StratumClient worker,
|
||||
public async Task<Share> SubmitShareAsync(StratumClient worker,
|
||||
string[] request, double stratumDifficulty, double stratumDifficultyBase)
|
||||
{
|
||||
Contract.RequiresNonNull(worker, nameof(worker));
|
||||
|
@ -415,20 +415,7 @@ namespace MiningCore.Blockchain.Ethereum
|
|||
}
|
||||
|
||||
// validate & process
|
||||
var share = await job.ProcessShareAsync(worker, nonce, ethash);
|
||||
|
||||
// if block candidate, submit & check if accepted by network
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight}");
|
||||
|
||||
share.IsBlockCandidate = await SubmitBlockAsync(share);
|
||||
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} submitted by {context.MinerName}");
|
||||
}
|
||||
}
|
||||
var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, nonce, ethash);
|
||||
|
||||
// enrich share with common data
|
||||
share.PoolId = poolConfig.Id;
|
||||
|
@ -436,6 +423,19 @@ namespace MiningCore.Blockchain.Ethereum
|
|||
share.Source = clusterConfig.ClusterName;
|
||||
share.Created = clock.Now;
|
||||
|
||||
// if block candidate, submit & check if accepted by network
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight}");
|
||||
|
||||
share.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, mixHash);
|
||||
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} submitted by {context.MinerName}");
|
||||
}
|
||||
}
|
||||
|
||||
return share;
|
||||
}
|
||||
|
||||
|
@ -542,7 +542,8 @@ namespace MiningCore.Blockchain.Ethereum
|
|||
|
||||
EthereumUtils.DetectNetworkAndChain(netVersion, parityChain, out networkType, out chainType);
|
||||
|
||||
ConfigureRewards();
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
|
||||
ConfigureRewards();
|
||||
|
||||
// update stats
|
||||
BlockchainStats.RewardType = "POW";
|
||||
|
|
|
@ -42,7 +42,7 @@ using Newtonsoft.Json;
|
|||
namespace MiningCore.Blockchain.Ethereum
|
||||
{
|
||||
[CoinMetadata(CoinType.ETH, CoinType.ETC, CoinType.EXP, CoinType.ELLA)]
|
||||
public class EthereumPool : PoolBase<EthereumShare>
|
||||
public class EthereumPool : PoolBase
|
||||
{
|
||||
public EthereumPool(IComponentContext ctx,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 Coin Foundry (coinfoundry.org)
|
||||
Authors: Oliver Weichhold (oliver@weichhold.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace MiningCore.Blockchain.Ethereum
|
||||
{
|
||||
public class EthereumShare : ShareBase
|
||||
{
|
||||
public string FullNonceHex { get; set; }
|
||||
public string HeaderHash { get; set; }
|
||||
public string MixHash { get; set; }
|
||||
}
|
||||
}
|
|
@ -19,10 +19,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
|
||||
using MiningCore.Blockchain.Monero.DaemonResponses;
|
||||
using MiningCore.Buffers;
|
||||
using MiningCore.Configuration;
|
||||
|
@ -49,11 +46,15 @@ namespace MiningCore.Blockchain.Monero
|
|||
switch (poolConfig.Coin.Type)
|
||||
{
|
||||
case CoinType.AEON:
|
||||
hashSlow = LibCryptonote.CryptonightHashSlowLite;
|
||||
hashSlow = (buf, variant)=> LibCryptonote.CryptonightHashSlowLite(buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
hashSlow = LibCryptonote.CryptonightHashSlow;
|
||||
case CoinType.XMR:
|
||||
hashSlow = LibCryptonote.CryptonightHashSlow;
|
||||
break;
|
||||
|
||||
default:
|
||||
hashSlow = (buf, variant) => LibCryptonote.CryptonightHashSlow(buf, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -61,7 +62,7 @@ namespace MiningCore.Blockchain.Monero
|
|||
PrepareBlobTemplate(instanceId);
|
||||
}
|
||||
|
||||
private readonly Func<byte[], PooledArraySegment<byte>> hashSlow;
|
||||
private readonly Func<byte[], int, PooledArraySegment<byte>> hashSlow;
|
||||
|
||||
private byte[] blobTemplate;
|
||||
private uint extraNonce;
|
||||
|
@ -135,7 +136,7 @@ namespace MiningCore.Blockchain.Monero
|
|||
target = EncodeTarget(workerJob.Difficulty);
|
||||
}
|
||||
|
||||
public MoneroShare ProcessShare(string nonce, uint workerExtraNonce, string workerHash, StratumClient worker)
|
||||
public (Share Share, string BlobHex, string BlobHash) ProcessShare(string nonce, uint workerExtraNonce, string workerHash, StratumClient worker)
|
||||
{
|
||||
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty");
|
||||
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(workerHash), $"{nameof(workerHash)} must not be empty");
|
||||
|
@ -165,8 +166,11 @@ namespace MiningCore.Blockchain.Monero
|
|||
if (blobConverted == null)
|
||||
throw new StratumException(StratumError.MinusOne, "malformed blob");
|
||||
|
||||
// hash it
|
||||
using (var hashSeg = hashSlow(blobConverted))
|
||||
// PoW variant
|
||||
var hashVariant = blobConverted[0] >= 7 ? blobConverted[0] - 6 : 0;
|
||||
|
||||
// hash it
|
||||
using (var hashSeg = hashSlow(blobConverted, hashVariant))
|
||||
{
|
||||
var hash = hashSeg.ToHexString();
|
||||
if (hash != workerHash)
|
||||
|
@ -200,17 +204,18 @@ namespace MiningCore.Blockchain.Monero
|
|||
|
||||
using (var blockHash = ComputeBlockHash(blobConverted))
|
||||
{
|
||||
var result = new MoneroShare
|
||||
var result = new Share
|
||||
{
|
||||
BlockHeight = BlockTemplate.Height,
|
||||
IsBlockCandidate = isBlockCandidate,
|
||||
BlobHex = blob.ToHexString(),
|
||||
BlobHash = blockHash.ToHexString(),
|
||||
BlockHash = blockHash.ToHexString(),
|
||||
Difficulty = stratumDifficulty,
|
||||
};
|
||||
|
||||
return result;
|
||||
var blobHex = blob.ToHexString();
|
||||
var blobHash = blockHash.ToHexString();
|
||||
|
||||
return (result, blobHex, blobHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,15 +169,15 @@ namespace MiningCore.Blockchain.Monero
|
|||
BlockchainStats.ConnectedPeers = info.OutgoingConnectionsCount + info.IncomingConnectionsCount;
|
||||
}
|
||||
|
||||
private async Task<bool> SubmitBlockAsync(MoneroShare share)
|
||||
private async Task<bool> SubmitBlockAsync(Share share, string blobHex, string blobHash)
|
||||
{
|
||||
var response = await daemon.ExecuteCmdAnyAsync<SubmitResponse>(MC.SubmitBlock, new[] { share.BlobHex });
|
||||
var response = await daemon.ExecuteCmdAnyAsync<SubmitResponse>(MC.SubmitBlock, new[] { blobHex });
|
||||
|
||||
if (response.Error != null || response?.Response?.Status != "OK")
|
||||
{
|
||||
var error = response.Error?.Message ?? response.Response?.Status;
|
||||
|
||||
logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} [{share.BlobHash.Substring(0, 6)}] submission failed with: {error}");
|
||||
logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} [{blobHash.Substring(0, 6)}] submission failed with: {error}");
|
||||
notificationService.NotifyAdmin("Block submission failed", $"Block {share.BlockHeight} submission failed with: {error}");
|
||||
|
||||
return false;
|
||||
|
@ -204,13 +204,16 @@ namespace MiningCore.Blockchain.Monero
|
|||
.Where(x => string.IsNullOrEmpty(x.Category))
|
||||
.ToArray();
|
||||
|
||||
// extract wallet daemon endpoints
|
||||
walletDaemonEndpoints = poolConfig.Daemons
|
||||
.Where(x => x.Category?.ToLower() == MoneroConstants.WalletDaemonCategory)
|
||||
.ToArray();
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
|
||||
{
|
||||
// extract wallet daemon endpoints
|
||||
walletDaemonEndpoints = poolConfig.Daemons
|
||||
.Where(x => x.Category?.ToLower() == MoneroConstants.WalletDaemonCategory)
|
||||
.ToArray();
|
||||
|
||||
if (walletDaemonEndpoints.Length == 0)
|
||||
logger.ThrowLogPoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for monero-pools require an additional entry of category \'wallet' pointing to the wallet daemon)", LogCat);
|
||||
if (walletDaemonEndpoints.Length == 0)
|
||||
logger.ThrowLogPoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for monero-pools require an additional entry of category \'wallet' pointing to the wallet daemon)", LogCat);
|
||||
}
|
||||
|
||||
ConfigureDaemons();
|
||||
}
|
||||
|
@ -258,7 +261,7 @@ namespace MiningCore.Blockchain.Monero
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<MoneroShare> SubmitShareAsync(StratumClient worker,
|
||||
public async Task<Share> SubmitShareAsync(StratumClient worker,
|
||||
MoneroSubmitShareRequest request, MoneroWorkerJob workerJob, double stratumDifficultyBase)
|
||||
{
|
||||
Contract.RequiresNonNull(worker, nameof(worker));
|
||||
|
@ -272,28 +275,7 @@ namespace MiningCore.Blockchain.Monero
|
|||
throw new StratumException(StratumError.MinusOne, "block expired");
|
||||
|
||||
// validate & process
|
||||
var share = job?.ProcessShare(request.Nonce, workerJob.ExtraNonce, request.Hash, worker);
|
||||
|
||||
// if block candidate, submit & check if accepted by network
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight} [{share.BlobHash.Substring(0, 6)}]");
|
||||
|
||||
share.IsBlockCandidate = await SubmitBlockAsync(share);
|
||||
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} [{share.BlobHash.Substring(0, 6)}] submitted by {context.MinerName}");
|
||||
|
||||
share.TransactionConfirmationData = share.BlobHash;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// clear fields that no longer apply
|
||||
share.TransactionConfirmationData = null;
|
||||
}
|
||||
}
|
||||
var (share, blobHex, blobHash) = job.ProcessShare(request.Nonce, workerJob.ExtraNonce, request.Hash, worker);
|
||||
|
||||
// enrich share with common data
|
||||
share.PoolId = poolConfig.Id;
|
||||
|
@ -306,6 +288,27 @@ namespace MiningCore.Blockchain.Monero
|
|||
share.NetworkDifficulty = job.BlockTemplate.Difficulty;
|
||||
share.Created = clock.Now;
|
||||
|
||||
// if block candidate, submit & check if accepted by network
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight} [{blobHash.Substring(0, 6)}]");
|
||||
|
||||
share.IsBlockCandidate = await SubmitBlockAsync(share, blobHex, blobHash);
|
||||
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} [{blobHash.Substring(0, 6)}] submitted by {context.MinerName}");
|
||||
|
||||
share.TransactionConfirmationData = blobHash;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// clear fields that no longer apply
|
||||
share.TransactionConfirmationData = null;
|
||||
}
|
||||
}
|
||||
|
||||
return share;
|
||||
}
|
||||
|
||||
|
@ -322,9 +325,12 @@ namespace MiningCore.Blockchain.Monero
|
|||
daemon = new DaemonClient(jsonSerializerSettings);
|
||||
daemon.Configure(daemonEndpoints, MoneroConstants.DaemonRpcLocation);
|
||||
|
||||
// also setup wallet daemon
|
||||
walletDaemon = new DaemonClient(jsonSerializerSettings);
|
||||
walletDaemon.Configure(walletDaemonEndpoints, MoneroConstants.DaemonRpcLocation);
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
|
||||
{
|
||||
// also setup wallet daemon
|
||||
walletDaemon = new DaemonClient(jsonSerializerSettings);
|
||||
walletDaemon.Configure(walletDaemonEndpoints, MoneroConstants.DaemonRpcLocation);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<bool> AreDaemonsHealthyAsync()
|
||||
|
@ -340,15 +346,20 @@ namespace MiningCore.Blockchain.Monero
|
|||
if (!responses.All(x => x.Error == null))
|
||||
return false;
|
||||
|
||||
// test wallet daemons
|
||||
var responses2 = await walletDaemon.ExecuteCmdAllAsync<object>(MWC.GetAddress);
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
|
||||
{
|
||||
// test wallet daemons
|
||||
var responses2 = await walletDaemon.ExecuteCmdAllAsync<object>(MWC.GetAddress);
|
||||
|
||||
if (responses2.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException))
|
||||
.Select(x => (DaemonClientException) x.Error.InnerException)
|
||||
.Any(x => x.Code == HttpStatusCode.Unauthorized))
|
||||
logger.ThrowLogPoolStartupException($"Wallet-Daemon reports invalid credentials", LogCat);
|
||||
if (responses2.Where(x => x.Error?.InnerException?.GetType() == typeof(DaemonClientException))
|
||||
.Select(x => (DaemonClientException) x.Error.InnerException)
|
||||
.Any(x => x.Code == HttpStatusCode.Unauthorized))
|
||||
logger.ThrowLogPoolStartupException($"Wallet-Daemon reports invalid credentials", LogCat);
|
||||
|
||||
return responses2.All(x => x.Error == null);
|
||||
return responses2.All(x => x.Error == null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override async Task<bool> AreDaemonsConnectedAsync()
|
||||
|
@ -398,14 +409,18 @@ namespace MiningCore.Blockchain.Monero
|
|||
protected override async Task PostStartInitAsync()
|
||||
{
|
||||
var infoResponse = await daemon.ExecuteCmdAnyAsync(MC.GetInfo);
|
||||
var addressResponse = await walletDaemon.ExecuteCmdAnyAsync<GetAddressResponse>(MWC.GetAddress);
|
||||
|
||||
if (infoResponse.Error != null)
|
||||
logger.ThrowLogPoolStartupException($"Init RPC failed: {infoResponse.Error.Message} (Code {infoResponse.Error.Code})", LogCat);
|
||||
|
||||
// ensure pool owns wallet
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address)
|
||||
logger.ThrowLogPoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'", LogCat);
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
|
||||
{
|
||||
var addressResponse = await walletDaemon.ExecuteCmdAnyAsync<GetAddressResponse>(MWC.GetAddress);
|
||||
|
||||
// ensure pool owns wallet
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address)
|
||||
logger.ThrowLogPoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'", LogCat);
|
||||
}
|
||||
|
||||
var info = infoResponse.Response.ToObject<GetInfoResponse>();
|
||||
|
||||
|
@ -430,7 +445,8 @@ namespace MiningCore.Blockchain.Monero
|
|||
break;
|
||||
}
|
||||
|
||||
ConfigureRewards();
|
||||
if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true)
|
||||
ConfigureRewards();
|
||||
|
||||
// update stats
|
||||
BlockchainStats.RewardType = "POW";
|
||||
|
|
|
@ -43,7 +43,7 @@ using Newtonsoft.Json;
|
|||
namespace MiningCore.Blockchain.Monero
|
||||
{
|
||||
[CoinMetadata(CoinType.XMR, CoinType.AEON, CoinType.ETN)]
|
||||
public class MoneroPool : PoolBase<MoneroShare>
|
||||
public class MoneroPool : PoolBase
|
||||
{
|
||||
public MoneroPool(IComponentContext ctx,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 Coin Foundry (coinfoundry.org)
|
||||
Authors: Oliver Weichhold (oliver@weichhold.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace MiningCore.Blockchain.Monero
|
||||
{
|
||||
public class MoneroShare : ShareBase
|
||||
{
|
||||
public string BlobHex { get; set; }
|
||||
public string BlobHash { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
Copyright 2017 Coin Foundry (coinfoundry.org)
|
||||
Authors: Oliver Weichhold (oliver@weichhold.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace MiningCore.Blockchain
|
||||
{
|
||||
[ProtoContract]
|
||||
public class Share
|
||||
{
|
||||
/// <summary>
|
||||
/// The pool originating this share from
|
||||
/// </summary>
|
||||
[ProtoMember(1)]
|
||||
public string PoolId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Who mined it (wallet address)
|
||||
/// </summary>
|
||||
[ProtoMember(2)]
|
||||
public string Miner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Who mined it
|
||||
/// </summary>
|
||||
[ProtoMember(3)]
|
||||
public string Worker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extra information for payout processing
|
||||
/// </summary>
|
||||
[ProtoMember(4)]
|
||||
public string PayoutInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mining Software
|
||||
/// </summary>
|
||||
[ProtoMember(5)]
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// From where was it submitted
|
||||
/// </summary>
|
||||
[ProtoMember(6)]
|
||||
public string IpAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Submission source (pool, external stratum etc)
|
||||
/// </summary>
|
||||
[ProtoMember(7)]
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stratum difficulty assigned to the miner at the time the share was submitted/accepted (used for payout
|
||||
/// calculations)
|
||||
/// </summary>
|
||||
[ProtoMember(8)]
|
||||
public double Difficulty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block this share refers to
|
||||
/// </summary>
|
||||
[ProtoMember(9)]
|
||||
public long BlockHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block reward after deducting pool fee and donations
|
||||
/// </summary>
|
||||
[ProtoMember(10)]
|
||||
public decimal BlockReward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block hash
|
||||
/// </summary>
|
||||
[ProtoMember(11)]
|
||||
public string BlockHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If this share presumably resulted in a block
|
||||
/// </summary>
|
||||
[ProtoMember(12)]
|
||||
public bool IsBlockCandidate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Arbitrary data to be interpreted by the payment processor specialized
|
||||
/// in this coin to verify this block candidate was accepted by the network
|
||||
/// </summary>
|
||||
[ProtoMember(13)]
|
||||
public string TransactionConfirmationData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Network difficulty at the time the share was submitted (used for some payout schemes like PPLNS)
|
||||
/// </summary>
|
||||
[ProtoMember(14)]
|
||||
public double NetworkDifficulty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the share was found
|
||||
/// </summary>
|
||||
[ProtoMember(15)]
|
||||
public DateTime Created { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 Coin Foundry (coinfoundry.org)
|
||||
Authors: Oliver Weichhold (oliver@weichhold.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace MiningCore.Blockchain
|
||||
{
|
||||
public class ShareBase : IShare
|
||||
{
|
||||
public string PoolId { get; set; }
|
||||
public string Miner { get; set; }
|
||||
public string Worker { get; set; }
|
||||
public string PayoutInfo { get; set; }
|
||||
public string UserAgent { get; set; }
|
||||
public string IpAddress { get; set; }
|
||||
public string Source { get; set; }
|
||||
public double Difficulty { get; set; }
|
||||
public double NetworkDifficulty { get; set; }
|
||||
public long BlockHeight { get; set; }
|
||||
public decimal BlockReward { get; set; }
|
||||
public string BlockHash { get; set; }
|
||||
public bool IsBlockCandidate { get; set; }
|
||||
public string TransactionConfirmationData { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
}
|
||||
}
|
|
@ -20,11 +20,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using MiningCore.Blockchain.Bitcoin;
|
||||
using MiningCore.Blockchain.ZCash.DaemonResponses;
|
||||
using MiningCore.Configuration;
|
||||
|
@ -227,7 +225,7 @@ namespace MiningCore.Blockchain.ZCash
|
|||
|
||||
#endregion
|
||||
|
||||
public override BitcoinShare ProcessShare(StratumClient worker, string extraNonce2, string nTime, string solution)
|
||||
public override (Share Share, string BlockHex) ProcessShare(StratumClient worker, string extraNonce2, string nTime, string solution)
|
||||
{
|
||||
Contract.RequiresNonNull(worker, nameof(worker));
|
||||
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(extraNonce2), $"{nameof(extraNonce2)} must not be empty");
|
||||
|
@ -295,7 +293,7 @@ namespace MiningCore.Blockchain.ZCash
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual BitcoinShare ProcessShareInternal(StratumClient worker, string nonce,
|
||||
protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumClient worker, string nonce,
|
||||
uint nTime, string solution)
|
||||
{
|
||||
var context = worker.GetContextAs<BitcoinWorkerContext>();
|
||||
|
@ -341,22 +339,26 @@ namespace MiningCore.Blockchain.ZCash
|
|||
throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
|
||||
}
|
||||
|
||||
var result = new BitcoinShare
|
||||
var result = new Share
|
||||
{
|
||||
BlockHeight = BlockTemplate.Height,
|
||||
IsBlockCandidate = isBlockCandidate,
|
||||
Difficulty = stratumDifficulty
|
||||
NetworkDifficulty = Difficulty,
|
||||
Difficulty = stratumDifficulty,
|
||||
};
|
||||
|
||||
if (isBlockCandidate)
|
||||
{
|
||||
var blockBytes = SerializeBlock(headerBytes, coinbaseInitial, solutionBytes);
|
||||
result.BlockHex = blockBytes.ToHexString();
|
||||
result.BlockHash = headerHashReversed.ToHexString();
|
||||
result.IsBlockCandidate = true;
|
||||
result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC);
|
||||
result.BlockHash = headerHashReversed.ToHexString();
|
||||
|
||||
var blockBytes = SerializeBlock(headerBytes, coinbaseInitial, solutionBytes);
|
||||
var blockHex = blockBytes.ToHexString();
|
||||
|
||||
return (result, blockHex);
|
||||
}
|
||||
|
||||
return result;
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
protected bool RegisterSubmit(string nonce, string solution)
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace MiningCore.Blockchain.ZCash
|
|||
return result;
|
||||
}
|
||||
|
||||
public override async Task<BitcoinShare> SubmitShareAsync(StratumClient worker, object submission,
|
||||
public override async Task<Share> SubmitShareAsync(StratumClient worker, object submission,
|
||||
double stratumDifficultyBase)
|
||||
{
|
||||
Contract.RequiresNonNull(worker, nameof(worker));
|
||||
|
@ -148,14 +148,14 @@ namespace MiningCore.Blockchain.ZCash
|
|||
var workerName = split.Length > 1 ? split[1] : null;
|
||||
|
||||
// validate & process
|
||||
var share = job.ProcessShare(worker, extraNonce2, nTime, solution);
|
||||
var (share, blockHex) = job.ProcessShare(worker, extraNonce2, nTime, solution);
|
||||
|
||||
// if block candidate, submit & check if accepted by network
|
||||
if (share.IsBlockCandidate)
|
||||
{
|
||||
logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight} [{share.BlockHash}]");
|
||||
|
||||
var acceptResponse = await SubmitBlockAsync(share);
|
||||
var acceptResponse = await SubmitBlockAsync(share, blockHex);
|
||||
|
||||
// is it still a block candidate?
|
||||
share.IsBlockCandidate = acceptResponse.Accepted;
|
||||
|
|
|
@ -28,14 +28,14 @@ namespace MiningCore.Mining
|
|||
{
|
||||
public struct ClientShare
|
||||
{
|
||||
public ClientShare(StratumClient client, IShare share)
|
||||
public ClientShare(StratumClient client, Share share)
|
||||
{
|
||||
Client = client;
|
||||
Share = share;
|
||||
}
|
||||
|
||||
public StratumClient Client;
|
||||
public IShare Share;
|
||||
public Share Share;
|
||||
}
|
||||
|
||||
public interface IMiningPool
|
||||
|
|
|
@ -52,9 +52,8 @@ using Contract = MiningCore.Contracts.Contract;
|
|||
|
||||
namespace MiningCore.Mining
|
||||
{
|
||||
public abstract class PoolBase<TShare> : StratumServer,
|
||||
public abstract class PoolBase : StratumServer,
|
||||
IMiningPool
|
||||
where TShare: IShare
|
||||
{
|
||||
protected PoolBase(IComponentContext ctx,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
|
@ -139,107 +138,6 @@ namespace MiningCore.Mining
|
|||
});
|
||||
}
|
||||
|
||||
private void StartExternalStratumPublisherListeners()
|
||||
{
|
||||
foreach (var externalStratum in poolConfig.ExternalStratums)
|
||||
{
|
||||
var thread = new Thread(arg =>
|
||||
{
|
||||
var serializer = new JsonSerializer
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||
};
|
||||
|
||||
var currentHeight = 0L;
|
||||
var lastBlockTime = clock.Now;
|
||||
var config = (ZmqPubSubEndpointConfig) arg;
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var subSocket = new SubscriberSocket())
|
||||
{
|
||||
//subSocket.Options.ReceiveHighWatermark = 1000;
|
||||
subSocket.Connect(config.Url);
|
||||
subSocket.Subscribe(config.Topic);
|
||||
|
||||
logger.Info($"{LogCat}] Monitoring external stratum {config.Url}/{config.Topic}");
|
||||
|
||||
while (true)
|
||||
{
|
||||
var msg = subSocket.ReceiveMultipartMessage(2);
|
||||
var topic = msg.Pop().ConvertToString(Encoding.UTF8);
|
||||
var data = msg.Pop().ConvertToString(Encoding.UTF8);
|
||||
|
||||
// validate
|
||||
if (topic != config.Topic)
|
||||
{
|
||||
logger.Warn(() => $"{LogCat}] Received non-matching topic {topic} on ZeroMQ subscriber socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(data))
|
||||
{
|
||||
logger.Warn(() => $"{LogCat}] Received empty data on ZeroMQ subscriber socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
// deserialize
|
||||
TShare share;
|
||||
|
||||
using (var reader = new StringReader(data))
|
||||
{
|
||||
using (var jreader = new JsonTextReader(reader))
|
||||
{
|
||||
share = serializer.Deserialize<TShare>(jreader);
|
||||
}
|
||||
}
|
||||
|
||||
if (share == null)
|
||||
{
|
||||
logger.Error(() => $"{LogCat}] Unable to deserialize share received from ZeroMQ subscriber socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
// update network stats
|
||||
blockchainStats.BlockHeight = share.BlockHeight;
|
||||
blockchainStats.NetworkDifficulty = share.NetworkDifficulty;
|
||||
|
||||
if (currentHeight != share.BlockHeight)
|
||||
{
|
||||
blockchainStats.LastNetworkBlockTime = clock.Now;
|
||||
currentHeight = share.BlockHeight;
|
||||
lastBlockTime = clock.Now;
|
||||
}
|
||||
|
||||
else
|
||||
blockchainStats.LastNetworkBlockTime = lastBlockTime;
|
||||
|
||||
// fill in the blacks
|
||||
share.PoolId = poolConfig.Id;
|
||||
share.Created = clock.Now;
|
||||
|
||||
// re-publish
|
||||
shareSubject.OnNext(new ClientShare(null, share));
|
||||
|
||||
var source = !string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}]" : string.Empty;
|
||||
logger.Info(() => $"[{LogCat}] External {source} share accepted: D={Math.Round(share.Difficulty, 3)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex);
|
||||
}
|
||||
}
|
||||
}) {Name = $"{poolConfig.Id} external stratum listener"};
|
||||
|
||||
thread.Start(externalStratum);
|
||||
}
|
||||
}
|
||||
|
||||
#region VarDiff
|
||||
|
||||
protected void UpdateVarDiff(StratumClient client, bool isIdleUpdate = false)
|
||||
|
@ -414,7 +312,7 @@ Pool Fee: {(poolConfig.RewardRecipients?.Any() == true ? poolConfi
|
|||
Contract.RequiresNonNull(poolConfig, nameof(poolConfig));
|
||||
Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig));
|
||||
|
||||
logger = LogUtil.GetPoolScopedLogger(typeof(PoolBase<TShare>), poolConfig);
|
||||
logger = LogUtil.GetPoolScopedLogger(typeof(PoolBase), poolConfig);
|
||||
this.poolConfig = poolConfig;
|
||||
this.clusterConfig = clusterConfig;
|
||||
}
|
||||
|
@ -442,9 +340,6 @@ Pool Fee: {(poolConfig.RewardRecipients?.Any() == true ? poolConfi
|
|||
StartListeners(poolConfig.Id, ipEndpoints);
|
||||
}
|
||||
|
||||
if(poolConfig.ExternalStratums?.Length > 0)
|
||||
StartExternalStratumPublisherListeners();
|
||||
|
||||
logger.Info(() => $"[{LogCat}] Online");
|
||||
OutputPoolInfo();
|
||||
}
|
||||
|
|
|
@ -28,23 +28,29 @@ using System.Net.Sockets;
|
|||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using Autofac.Features.Metadata;
|
||||
using System.Threading;
|
||||
using AutoMapper;
|
||||
using MiningCore.Blockchain;
|
||||
using MiningCore.Configuration;
|
||||
using MiningCore.Extensions;
|
||||
using MiningCore.Mining;
|
||||
using MiningCore.Notifications;
|
||||
using MiningCore.Persistence;
|
||||
using MiningCore.Persistence.Model;
|
||||
using MiningCore.Persistence.Repositories;
|
||||
using MiningCore.Time;
|
||||
using MiningCore.Util;
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using NLog;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
using Polly;
|
||||
using Polly.CircuitBreaker;
|
||||
using ProtoBuf;
|
||||
using Contract = MiningCore.Contracts.Contract;
|
||||
using Share = MiningCore.Blockchain.Share;
|
||||
|
||||
namespace MiningCore.Payments
|
||||
namespace MiningCore.Mining
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously persist shares produced by all pools for processing by coin-specific payment processor(s)
|
||||
|
@ -54,6 +60,7 @@ namespace MiningCore.Payments
|
|||
public ShareRecorder(IConnectionFactory cf, IMapper mapper,
|
||||
JsonSerializerSettings jsonSerializerSettings,
|
||||
IShareRepository shareRepo, IBlockRepository blockRepo,
|
||||
IMasterClock clock,
|
||||
NotificationService notificationService)
|
||||
{
|
||||
Contract.RequiresNonNull(cf, nameof(cf));
|
||||
|
@ -61,11 +68,13 @@ namespace MiningCore.Payments
|
|||
Contract.RequiresNonNull(shareRepo, nameof(shareRepo));
|
||||
Contract.RequiresNonNull(blockRepo, nameof(blockRepo));
|
||||
Contract.RequiresNonNull(jsonSerializerSettings, nameof(jsonSerializerSettings));
|
||||
Contract.RequiresNonNull(clock, nameof(clock));
|
||||
Contract.RequiresNonNull(notificationService, nameof(notificationService));
|
||||
|
||||
this.cf = cf;
|
||||
this.mapper = mapper;
|
||||
this.jsonSerializerSettings = jsonSerializerSettings;
|
||||
this.clock = clock;
|
||||
this.notificationService = notificationService;
|
||||
|
||||
this.shareRepo = shareRepo;
|
||||
|
@ -74,16 +83,33 @@ namespace MiningCore.Payments
|
|||
BuildFaultHandlingPolicy();
|
||||
}
|
||||
|
||||
private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly IBlockRepository blockRepo;
|
||||
|
||||
private readonly IConnectionFactory cf;
|
||||
private readonly JsonSerializerSettings jsonSerializerSettings;
|
||||
private readonly IMasterClock clock;
|
||||
private readonly NotificationService notificationService;
|
||||
private ClusterConfig clusterConfig;
|
||||
private readonly IMapper mapper;
|
||||
private readonly BlockingCollection<IShare> queue = new BlockingCollection<IShare>();
|
||||
private readonly ConcurrentDictionary<string, PoolContext> pools = new ConcurrentDictionary<string, PoolContext>();
|
||||
private readonly BlockingCollection<Share> queue = new BlockingCollection<Share>();
|
||||
|
||||
class PoolContext
|
||||
{
|
||||
public PoolContext(IMiningPool pool, ILogger logger)
|
||||
{
|
||||
Pool = pool;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public IMiningPool Pool;
|
||||
public ILogger Logger;
|
||||
public DateTime? LastBlock;
|
||||
public long BlockHeight;
|
||||
}
|
||||
|
||||
private readonly int QueueSizeWarningThreshold = 1024;
|
||||
private readonly TimeSpan relayReceiveTimeout = TimeSpan.FromSeconds(60);
|
||||
private readonly IShareRepository shareRepo;
|
||||
private Policy faultPolicy;
|
||||
private bool hasLoggedPolicyFallbackFailure;
|
||||
|
@ -94,22 +120,20 @@ namespace MiningCore.Payments
|
|||
private const string PolicyContextKeyShares = "share";
|
||||
private bool notifiedAdminOnPolicyFallback = false;
|
||||
|
||||
private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private void PersistSharesFaulTolerant(IList<IShare> shares)
|
||||
private void PersistSharesFaulTolerant(IList<Share> shares)
|
||||
{
|
||||
var context = new Dictionary<string, object> { { PolicyContextKeyShares, shares } };
|
||||
|
||||
faultPolicy.Execute(() => { PersistShares(shares); }, context);
|
||||
}
|
||||
|
||||
private void PersistShares(IList<IShare> shares)
|
||||
private void PersistShares(IList<Share> shares)
|
||||
{
|
||||
cf.RunTx((con, tx) =>
|
||||
{
|
||||
foreach(var share in shares)
|
||||
{
|
||||
var shareEntity = mapper.Map<Share>(share);
|
||||
var shareEntity = mapper.Map<Persistence.Model.Share>(share);
|
||||
shareRepo.Insert(con, tx, shareEntity);
|
||||
|
||||
if (share.IsBlockCandidate)
|
||||
|
@ -136,7 +160,7 @@ namespace MiningCore.Payments
|
|||
|
||||
private void OnExecutePolicyFallback(Context context)
|
||||
{
|
||||
var shares = (IList<IShare>) context[PolicyContextKeyShares];
|
||||
var shares = (IList<Share>) context[PolicyContextKeyShares];
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -189,7 +213,7 @@ namespace MiningCore.Payments
|
|||
{
|
||||
using(var reader = new StreamReader(stream, new UTF8Encoding(false)))
|
||||
{
|
||||
var shares = new List<IShare>();
|
||||
var shares = new List<Share>();
|
||||
var lastProgressUpdate = DateTime.UtcNow;
|
||||
|
||||
while(!reader.EndOfStream)
|
||||
|
@ -207,7 +231,7 @@ namespace MiningCore.Payments
|
|||
// parse
|
||||
try
|
||||
{
|
||||
var share = JsonConvert.DeserializeObject<ShareBase>(line, jsonSerializerSettings);
|
||||
var share = JsonConvert.DeserializeObject<Share>(line, jsonSerializerSettings);
|
||||
shares.Add(share);
|
||||
}
|
||||
|
||||
|
@ -289,10 +313,167 @@ namespace MiningCore.Payments
|
|||
}
|
||||
}
|
||||
|
||||
private void StartExternalStratumPublisherListeners()
|
||||
{
|
||||
var stratumsByUrl = clusterConfig.Pools.Where(x => x.ExternalStratums?.Any() == true)
|
||||
.SelectMany(x => x.ExternalStratums)
|
||||
.Where(x => x.Url != null && x.Topic != null)
|
||||
.GroupBy(x =>
|
||||
{
|
||||
var tmp = x.Url.Trim();
|
||||
return !tmp.EndsWith("/") ? tmp : tmp.Substring(0, tmp.Length - 1);
|
||||
}, x=> x.Topic.Trim());
|
||||
|
||||
var serializer = new JsonSerializer
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||
};
|
||||
|
||||
foreach (var item in stratumsByUrl)
|
||||
{
|
||||
var thread = new Thread(arg =>
|
||||
{
|
||||
var urlAndTopic = (IGrouping<string, string>) arg;
|
||||
var url = urlAndTopic.Key;
|
||||
var topics = new HashSet<string>(urlAndTopic.Distinct());
|
||||
var receivedOnce = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var subSocket = new SubscriberSocket())
|
||||
{
|
||||
subSocket.Connect(url);
|
||||
|
||||
// subscribe to all topics
|
||||
foreach (var topic in topics)
|
||||
subSocket.Subscribe(topic);
|
||||
|
||||
logger.Info($"Monitoring external stratum {url}/[{string.Join(", ", topics)}]");
|
||||
|
||||
while (true)
|
||||
{
|
||||
// receive
|
||||
var msg = (NetMQMessage)null;
|
||||
|
||||
if (!subSocket.TryReceiveMultipartMessage(relayReceiveTimeout, ref msg, 3))
|
||||
{
|
||||
if (receivedOnce)
|
||||
{
|
||||
logger.Warn(() => $"Timeout receiving message from {url}. Reconnecting ...");
|
||||
break;
|
||||
}
|
||||
|
||||
// retry
|
||||
continue;
|
||||
}
|
||||
|
||||
// extract frames
|
||||
var topic = msg.Pop().ConvertToString(Encoding.UTF8);
|
||||
var flags = msg.Pop().ConvertToInt32();
|
||||
var data = msg.Pop().ToByteArray();
|
||||
receivedOnce = true;
|
||||
|
||||
// validate
|
||||
if (!topics.Contains(topic))
|
||||
{
|
||||
logger.Warn(() => $"Received non-matching topic {topic} on ZeroMQ subscriber socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data?.Length == 0)
|
||||
{
|
||||
logger.Warn(() => $"Received empty data from {url}/{topic}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// deserialize
|
||||
var wireFormat = (ShareRelay.WireFormat)(flags & ShareRelay.WireFormatMask);
|
||||
Share share = null;
|
||||
|
||||
switch (wireFormat)
|
||||
{
|
||||
case ShareRelay.WireFormat.Json:
|
||||
using (var stream = new MemoryStream(data))
|
||||
{
|
||||
using (var reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
using (var jreader = new JsonTextReader(reader))
|
||||
{
|
||||
share = serializer.Deserialize<Share>(jreader);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ShareRelay.WireFormat.ProtocolBuffers:
|
||||
using (var stream = new MemoryStream(data))
|
||||
{
|
||||
share = Serializer.Deserialize<Share>(stream);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.Error(() => $"Unsupported wire format {wireFormat} of share received from {url}/{topic} ");
|
||||
break;
|
||||
}
|
||||
|
||||
if (share == null)
|
||||
{
|
||||
logger.Error(() => $"Unable to deserialize share received from {url}/{topic}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// store
|
||||
share.PoolId = topic;
|
||||
share.Created = clock.Now;
|
||||
queue.Add(share);
|
||||
|
||||
// misc
|
||||
if (pools.TryGetValue(topic, out var poolContext))
|
||||
{
|
||||
var pool = poolContext.Pool;
|
||||
poolContext.Logger.Info(() => $"External {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}share accepted: D={Math.Round(share.Difficulty, 3)}");
|
||||
|
||||
// update pool stats
|
||||
if (pool.NetworkStats != null)
|
||||
{
|
||||
pool.NetworkStats.BlockHeight = share.BlockHeight;
|
||||
pool.NetworkStats.NetworkDifficulty = share.NetworkDifficulty;
|
||||
|
||||
if (poolContext.BlockHeight != share.BlockHeight)
|
||||
{
|
||||
pool.NetworkStats.LastNetworkBlockTime = clock.Now;
|
||||
poolContext.BlockHeight = share.BlockHeight;
|
||||
poolContext.LastBlock = clock.Now;
|
||||
}
|
||||
|
||||
else
|
||||
pool.NetworkStats.LastNetworkBlockTime = poolContext.LastBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
thread.Start(item);
|
||||
}
|
||||
}
|
||||
|
||||
#region API-Surface
|
||||
|
||||
public void AttachPool(IMiningPool pool)
|
||||
{
|
||||
pools[pool.Config.Id] = new PoolContext(pool, LogUtil.GetPoolScopedLogger(typeof(ShareRecorder), pool.Config));
|
||||
|
||||
pool.Shares.Subscribe(x => { queue.Add(x.Share); });
|
||||
}
|
||||
|
||||
|
@ -302,6 +483,7 @@ namespace MiningCore.Payments
|
|||
|
||||
ConfigureRecovery();
|
||||
InitializeQueue();
|
||||
StartExternalStratumPublisherListeners();
|
||||
|
||||
logger.Info(() => "Online");
|
||||
}
|
|
@ -1,19 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using MiningCore.Blockchain;
|
||||
using MiningCore.Configuration;
|
||||
using MiningCore.Mining;
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace MiningCore.Payments
|
||||
namespace MiningCore.Mining
|
||||
{
|
||||
public class ShareRelay
|
||||
{
|
||||
|
@ -23,7 +21,7 @@ namespace MiningCore.Payments
|
|||
}
|
||||
|
||||
private ClusterConfig clusterConfig;
|
||||
private readonly BlockingCollection<IShare> queue = new BlockingCollection<IShare>();
|
||||
private readonly BlockingCollection<Share> queue = new BlockingCollection<Share>();
|
||||
private IDisposable queueSub;
|
||||
private readonly int QueueSizeWarningThreshold = 1024;
|
||||
private bool hasWarnedAboutBacklogSize;
|
||||
|
@ -32,6 +30,15 @@ namespace MiningCore.Payments
|
|||
|
||||
private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
[Flags]
|
||||
public enum WireFormat
|
||||
{
|
||||
Json = 1,
|
||||
ProtocolBuffers = 2
|
||||
}
|
||||
|
||||
public const int WireFormatMask = 0xF;
|
||||
|
||||
#region API-Surface
|
||||
|
||||
public void AttachPool(IMiningPool pool)
|
||||
|
@ -87,10 +94,16 @@ namespace MiningCore.Payments
|
|||
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(share, serializerSettings);
|
||||
|
||||
var flags = (int) WireFormat.ProtocolBuffers;
|
||||
var msg = new NetMQMessage(2);
|
||||
msg.Push(json);
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
Serializer.Serialize(stream, share);
|
||||
msg.Push(stream.ToArray());
|
||||
}
|
||||
|
||||
msg.Push(flags);
|
||||
msg.Push(share.PoolId);
|
||||
pubSocket.SendMultipartMessage(msg);
|
||||
}
|
|
@ -46,21 +46,22 @@
|
|||
<PackageReference Include="Autofac" Version="4.6.2" />
|
||||
<PackageReference Include="AutoMapper" Version="6.2.2" />
|
||||
<PackageReference Include="Dapper" Version="1.50.4" />
|
||||
<PackageReference Include="FluentValidation" Version="7.3.4" />
|
||||
<PackageReference Include="FluentValidation" Version="7.5.1" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="11.1.0" />
|
||||
<PackageReference Include="MailKit" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0" />
|
||||
<PackageReference Include="MailKit" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
|
||||
<PackageReference Include="NBitcoin" Version="4.0.0.51" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.1" />
|
||||
<PackageReference Include="NBitcoin" Version="4.0.0.65" />
|
||||
<PackageReference Include="NetMQ" Version="4.0.0.1" />
|
||||
<PackageReference Include="NetUV.Core" Version="0.1.140" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
|
||||
<PackageReference Include="NLog" Version="5.0.0-beta09" />
|
||||
<PackageReference Include="Npgsql" Version="3.2.6" />
|
||||
<PackageReference Include="Polly" Version="5.6.1" />
|
||||
<PackageReference Include="Npgsql" Version="3.2.7" />
|
||||
<PackageReference Include="Polly" Version="5.8.0" />
|
||||
<PackageReference Include="protobuf-net" Version="2.3.7" />
|
||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||
<PackageReference Include="System.Reactive" Version="3.1.1" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace MiningCore.Native
|
|||
private static extern UInt64 decode_integrated_address(byte* input, int inputSize);
|
||||
|
||||
[DllImport("libcryptonote", EntryPoint = "cn_slow_hash_export", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int cn_slow_hash(byte* input, byte* output, uint inputLength);
|
||||
private static extern int cn_slow_hash(byte* input, byte* output, uint inputLength, int variant);
|
||||
|
||||
[DllImport("libcryptonote", EntryPoint = "cn_slow_hash_lite_export", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int cn_slow_hash_lite(byte* input, byte* output, uint inputLength);
|
||||
|
@ -124,7 +124,7 @@ namespace MiningCore.Native
|
|||
}
|
||||
}
|
||||
|
||||
public static PooledArraySegment<byte> CryptonightHashSlow(byte[] data)
|
||||
public static PooledArraySegment<byte> CryptonightHashSlow(byte[] data, int variant)
|
||||
{
|
||||
Contract.RequiresNonNull(data, nameof(data));
|
||||
|
||||
|
@ -134,7 +134,7 @@ namespace MiningCore.Native
|
|||
{
|
||||
fixed(byte* output = result.Array)
|
||||
{
|
||||
cn_slow_hash(input, output, (uint) data.Length);
|
||||
cn_slow_hash(input, output, (uint) data.Length, variant);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace MiningCore.Persistence.Postgres.Repositories
|
|||
private readonly IMapper mapper;
|
||||
private readonly IMasterClock clock;
|
||||
private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
|
||||
private static readonly TimeSpan MinerStatsMaxAge = TimeSpan.FromMinutes(15);
|
||||
private static readonly TimeSpan MinerStatsMaxAge = TimeSpan.FromMinutes(20);
|
||||
|
||||
public void InsertPoolStats(IDbConnection con, IDbTransaction tx, PoolStats stats)
|
||||
{
|
||||
|
@ -146,7 +146,7 @@ namespace MiningCore.Persistence.Postgres.Repositories
|
|||
var lastUpdate = con.QuerySingleOrDefault<DateTime?>(query, new { poolId, miner }, tx);
|
||||
|
||||
// ignore stale minerstats
|
||||
if (lastUpdate.HasValue && (clock.Now - lastUpdate) > MinerStatsMaxAge)
|
||||
if (lastUpdate.HasValue && (clock.Now - DateTime.SpecifyKind(lastUpdate.Value, DateTimeKind.Utc) > MinerStatsMaxAge))
|
||||
lastUpdate = null;
|
||||
|
||||
if (lastUpdate.HasValue)
|
||||
|
|
|
@ -647,7 +647,7 @@ namespace MiningCore
|
|||
|
||||
private static void TouchNativeLibs()
|
||||
{
|
||||
Console.WriteLine(LibCryptonote.CryptonightHashSlow(Encoding.UTF8.GetBytes("test")).ToHexString());
|
||||
Console.WriteLine(LibCryptonote.CryptonightHashSlow(Encoding.UTF8.GetBytes("test"), 0).ToHexString());
|
||||
Console.WriteLine(LibCryptonote.CryptonightHashFast(Encoding.UTF8.GetBytes("test")).ToHexString());
|
||||
Console.WriteLine(new Blake().Digest(Encoding.UTF8.GetBytes("test"), 0).ToHexString());
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"profiles": {
|
||||
"MiningCore": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "-c config.json"
|
||||
}
|
||||
}
|
||||
{
|
||||
"profiles": {
|
||||
"MiningCore": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "-c ..\\..\\..\\config.json"
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -7,7 +7,8 @@ LDLIBS = -lboost_system -lboost_date_time
|
|||
TARGET = libcryptonote.so
|
||||
|
||||
OBJECTS = contrib/epee/src/hex.o \
|
||||
common/base58.o crypto/aesb.o crypto/blake256.o crypto/chacha8.o \
|
||||
common/base58.o crypto/aesb.o crypto/blake256.o crypto/chacha.o \
|
||||
contrib/epee/src/memwipe.o \
|
||||
crypto/crypto-ops-data.o crypto/crypto-ops.o crypto/crypto.o crypto/groestl.o crypto/hash-extra-blake.o \
|
||||
crypto/hash-extra-groestl.o crypto/hash-extra-jh.o crypto/hash-extra-skein.o crypto/hash.o crypto/jh.o \
|
||||
crypto/keccak.o crypto/oaes_lib.o crypto/random.o crypto/skein.o crypto/slow-hash.o crypto/tree-hash.o \
|
||||
|
|
|
@ -7,7 +7,8 @@ LDLIBS = -lboost_system-mt -lboost_date_time-mt
|
|||
TARGET = libcryptonote.dll
|
||||
|
||||
OBJECTS = contrib/epee/src/hex.o \
|
||||
common/base58.o crypto/aesb.o crypto/blake256.o crypto/chacha8.o \
|
||||
common/base58.o crypto/aesb.o crypto/blake256.o crypto/chacha.o \
|
||||
contrib/epee/src/memwipe.o \
|
||||
crypto/crypto-ops-data.o crypto/crypto-ops.o crypto/crypto.o crypto/groestl.o crypto/hash-extra-blake.o \
|
||||
crypto/hash-extra-groestl.o crypto/hash-extra-jh.o crypto/hash-extra-skein.o crypto/hash.o crypto/jh.o \
|
||||
crypto/keccak.o crypto/oaes_lib.o crypto/random.o crypto/skein.o crypto/slow-hash.o crypto/tree-hash.o \
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -36,7 +36,7 @@
|
|||
|
||||
#include "crypto/hash.h"
|
||||
#include "int-util.h"
|
||||
// OW: unused #include "util.h"
|
||||
#include "util.h"
|
||||
#include "varint.h"
|
||||
|
||||
namespace tools
|
||||
|
@ -111,13 +111,13 @@ namespace tools
|
|||
uint64_t res = 0;
|
||||
switch (9 - size)
|
||||
{
|
||||
case 1: res |= *data++;
|
||||
case 2: res <<= 8; res |= *data++;
|
||||
case 3: res <<= 8; res |= *data++;
|
||||
case 4: res <<= 8; res |= *data++;
|
||||
case 5: res <<= 8; res |= *data++;
|
||||
case 6: res <<= 8; res |= *data++;
|
||||
case 7: res <<= 8; res |= *data++;
|
||||
case 1: res |= *data++; /* FALLTHRU */
|
||||
case 2: res <<= 8; res |= *data++; /* FALLTHRU */
|
||||
case 3: res <<= 8; res |= *data++; /* FALLTHRU */
|
||||
case 4: res <<= 8; res |= *data++; /* FALLTHRU */
|
||||
case 5: res <<= 8; res |= *data++; /* FALLTHRU */
|
||||
case 6: res <<= 8; res |= *data++; /* FALLTHRU */
|
||||
case 7: res <<= 8; res |= *data++; /* FALLTHRU */
|
||||
case 8: res <<= 8; res |= *data; break;
|
||||
default: assert(false);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -35,7 +35,7 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
|
@ -43,6 +43,10 @@
|
|||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun) && defined(__SVR4)
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -205,13 +209,14 @@ static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
|
|||
}
|
||||
}
|
||||
|
||||
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
|
||||
#if !defined(_MSC_VER)
|
||||
static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled");
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#ifdef _MSC_VER
|
||||
# define LITTLE_ENDIAN 1234
|
||||
# define BIG_ENDIAN 4321
|
||||
# define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
|
||||
static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled");
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <system_error>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#include "misc_log_ex.h"
|
||||
#endif
|
||||
|
||||
#include "crypto/hash.h"
|
||||
|
||||
/*! \brief Various Tools
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
namespace tools
|
||||
{
|
||||
//! Functional class for closing C file handles.
|
||||
struct close_file
|
||||
{
|
||||
void operator()(std::FILE* handle) const noexcept
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
std::fclose(handle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//! A file restricted to process owner AND process. Deletes file on destruction.
|
||||
class private_file {
|
||||
std::unique_ptr<std::FILE, close_file> m_handle;
|
||||
std::string m_filename;
|
||||
|
||||
private_file(std::FILE* handle, std::string&& filename) noexcept;
|
||||
public:
|
||||
|
||||
//! `handle() == nullptr && filename.empty()`.
|
||||
private_file() noexcept;
|
||||
|
||||
/*! \return File only readable by owner and only used by this process
|
||||
OR `private_file{}` on error. */
|
||||
static private_file create(std::string filename);
|
||||
|
||||
private_file(private_file&&) = default;
|
||||
private_file& operator=(private_file&&) = default;
|
||||
|
||||
//! Deletes `filename()` and closes `handle()`.
|
||||
~private_file() noexcept;
|
||||
|
||||
std::FILE* handle() const noexcept { return m_handle.get(); }
|
||||
const std::string& filename() const noexcept { return m_filename; }
|
||||
};
|
||||
|
||||
/*! \brief Returns the default data directory.
|
||||
*
|
||||
* \details Windows < Vista: C:\\Documents and Settings\\Username\\Application Data\\CRYPTONOTE_NAME
|
||||
*
|
||||
* Windows >= Vista: C:\\Users\\Username\\AppData\\Roaming\\CRYPTONOTE_NAME
|
||||
*
|
||||
* Mac: ~/Library/Application Support/CRYPTONOTE_NAME
|
||||
*
|
||||
* Unix: ~/.CRYPTONOTE_NAME
|
||||
*/
|
||||
std::string get_default_data_dir();
|
||||
|
||||
#ifdef WIN32
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param nfolder
|
||||
* @param iscreate
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string get_special_folder_path(int nfolder, bool iscreate);
|
||||
#endif
|
||||
|
||||
/*! \brief Returns the OS version string
|
||||
*
|
||||
* \details This is a wrapper around the primitives
|
||||
* get_windows_version_display_string() and
|
||||
* get_nix_version_display_string()
|
||||
*/
|
||||
std::string get_os_version_string();
|
||||
|
||||
/*! \brief creates directories for a path
|
||||
*
|
||||
* wrapper around boost::filesyste::create_directories.
|
||||
* (ensure-directory-exists): greenspun's tenth rule in action!
|
||||
*/
|
||||
bool create_directories_if_necessary(const std::string& path);
|
||||
/*! \brief std::rename wrapper for nix and something strange for windows.
|
||||
*/
|
||||
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name);
|
||||
|
||||
bool sanitize_locale();
|
||||
|
||||
bool on_startup();
|
||||
|
||||
/*! \brief Defines a signal handler for win32 and *nix
|
||||
*/
|
||||
class signal_handler
|
||||
{
|
||||
public:
|
||||
/*! \brief installs a signal handler */
|
||||
template<typename T>
|
||||
static bool install(T t)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
bool r = TRUE == ::SetConsoleCtrlHandler(&win_handler, TRUE);
|
||||
if (r)
|
||||
{
|
||||
m_handler = t;
|
||||
}
|
||||
return r;
|
||||
#else
|
||||
static struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sa.sa_handler = posix_handler;
|
||||
sa.sa_flags = 0;
|
||||
/* Only blocks SIGINT, SIGTERM and SIGPIPE */
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
signal(SIGTERM, posix_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
m_handler = t;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(WIN32)
|
||||
/*! \brief Handler for win */
|
||||
static BOOL WINAPI win_handler(DWORD type)
|
||||
{
|
||||
if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type)
|
||||
{
|
||||
handle_signal(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
MGINFO_RED("Got control signal " << type << ". Exiting without saving...");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
/*! \brief handler for NIX */
|
||||
static void posix_handler(int type)
|
||||
{
|
||||
handle_signal(type);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief calles m_handler */
|
||||
static void handle_signal(int type)
|
||||
{
|
||||
static boost::mutex m_mutex;
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
m_handler(type);
|
||||
}
|
||||
|
||||
/*! \brief where the installed handler is stored */
|
||||
static std::function<void(int)> m_handler;
|
||||
};
|
||||
|
||||
void set_strict_default_file_permissions(bool strict);
|
||||
|
||||
void set_max_concurrency(unsigned n);
|
||||
unsigned get_max_concurrency();
|
||||
|
||||
bool is_local_address(const std::string &address);
|
||||
int vercmp(const char *v0, const char *v1); // returns < 0, 0, > 0, similar to strcmp, but more human friendly than lexical - does not attempt to validate
|
||||
|
||||
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash);
|
||||
bool sha256sum(const std::string &filename, crypto::hash &hash);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -45,7 +45,7 @@
|
|||
* is as follows: Strip the msb of each byte, then from left to right,
|
||||
* read in what remains, placing it in reverse, into the buffer. Thus,
|
||||
* the following bit stream: 0xff02 would return 0x027f. 0xff turns
|
||||
* into 0x7f, is placed on the beggining of the buffer, then 0x02 is
|
||||
* into 0x7f, is placed on the beginning of the buffer, then 0x02 is
|
||||
* unchanged, since its msb is not set, and placed at the end of the
|
||||
* buffer.
|
||||
*/
|
||||
|
@ -108,7 +108,7 @@ namespace tools {
|
|||
return EVARINT_REPRESENT;
|
||||
}
|
||||
|
||||
write |= static_cast<T>(byte & 0x7f) << shift; /* Does the actualy placing into write, stripping the first bit */
|
||||
write |= static_cast<T>(byte & 0x7f) << shift; /* Does the actually placing into write, stripping the first bit */
|
||||
|
||||
/* If there is no next */
|
||||
if ((byte & 0x80) == 0) {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
#include "string_tools.h"
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
|
@ -37,6 +38,8 @@
|
|||
#include <stdio.h>
|
||||
#endif
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
#include "readline_buffer.h"
|
||||
|
@ -456,29 +459,35 @@ eof:
|
|||
class command_handler {
|
||||
public:
|
||||
typedef boost::function<bool (const std::vector<std::string> &)> callback;
|
||||
typedef std::map<std::string, std::pair<callback, std::string> > lookup;
|
||||
typedef std::map<std::string, std::pair<callback, std::pair<std::string, std::string>>> lookup;
|
||||
|
||||
std::string get_usage()
|
||||
{
|
||||
std::stringstream ss;
|
||||
size_t max_command_len = 0;
|
||||
for(auto& x:m_command_handlers)
|
||||
if(x.first.size() > max_command_len)
|
||||
max_command_len = x.first.size();
|
||||
|
||||
for(auto& x:m_command_handlers)
|
||||
{
|
||||
ss.width(max_command_len + 3);
|
||||
ss << std::left << x.first << x.second.second << ENDL;
|
||||
ss << x.second.second.first << ENDL;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void set_handler(const std::string& cmd, const callback& hndlr, const std::string& usage = "")
|
||||
std::pair<std::string, std::string> get_documentation(const std::vector<std::string>& cmd)
|
||||
{
|
||||
if(cmd.empty())
|
||||
return std::make_pair("", "");
|
||||
auto it = m_command_handlers.find(cmd.front());
|
||||
if(it == m_command_handlers.end())
|
||||
return std::make_pair("", "");
|
||||
return it->second.second;
|
||||
}
|
||||
|
||||
void set_handler(const std::string& cmd, const callback& hndlr, const std::string& usage = "", const std::string& description = "")
|
||||
{
|
||||
lookup::mapped_type & vt = m_command_handlers[cmd];
|
||||
vt.first = hndlr;
|
||||
vt.second = usage;
|
||||
vt.second.first = description.empty() ? cmd : usage;
|
||||
vt.second.second = description.empty() ? usage : description;
|
||||
#ifdef HAVE_READLINE
|
||||
rdln::readline_buffer::add_completion(cmd);
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,8 @@ namespace epee
|
|||
public:
|
||||
copyable_atomic()
|
||||
{};
|
||||
copyable_atomic(uint32_t value)
|
||||
{ store(value); }
|
||||
copyable_atomic(const copyable_atomic& a):std::atomic<uint32_t>(a.load())
|
||||
{}
|
||||
copyable_atomic& operator= (const copyable_atomic& a)
|
||||
|
|
|
@ -29,7 +29,33 @@
|
|||
#define _FILE_IO_UTILS_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// On Windows there is a problem with non-ASCII characters in path and file names
|
||||
// as far as support by the standard components used is concerned:
|
||||
|
||||
// The various file stream classes, e.g. std::ifstream and std::ofstream, are
|
||||
// part of the GNU C++ Library / libstdc++. On the most basic level they use the
|
||||
// fopen() call as defined / made accessible to programs compiled within MSYS2
|
||||
// by the stdio.h header file maintained by the MinGW project.
|
||||
|
||||
// The critical point: The implementation of fopen() is part of MSVCRT, the
|
||||
// Microsoft Visual C/C++ Runtime Library, and this method does NOT offer any
|
||||
// Unicode support.
|
||||
|
||||
// Monero code that would want to continue to use the normal file stream classes
|
||||
// but WITH Unicode support could therefore not solve this problem on its own,
|
||||
// but 2 different projects from 2 different maintaining groups would need changes
|
||||
// in this particular direction - something probably difficult to achieve and
|
||||
// with a long time to wait until all new versions / releases arrive.
|
||||
|
||||
// Implemented solution approach: Circumvent the problem by stopping to use std
|
||||
// file stream classes on Windows and directly use Unicode-capable WIN32 API
|
||||
// calls. Most of the code doing so is concentrated in this header file here.
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
@ -45,7 +71,22 @@ namespace file_io_utils
|
|||
inline
|
||||
bool save_string_to_file(const std::string& path_to_file, const std::string& str)
|
||||
{
|
||||
|
||||
#ifdef WIN32
|
||||
WCHAR wide_path[1000];
|
||||
int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000);
|
||||
if (chars == 0)
|
||||
return false;
|
||||
HANDLE file_handle = CreateFileW(wide_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
DWORD bytes_written;
|
||||
DWORD bytes_to_write = (DWORD)str.size();
|
||||
BOOL result = WriteFile(file_handle, str.data(), bytes_to_write, &bytes_written, NULL);
|
||||
CloseHandle(file_handle);
|
||||
if (bytes_written != bytes_to_write)
|
||||
result = FALSE;
|
||||
return result;
|
||||
#else
|
||||
try
|
||||
{
|
||||
std::ofstream fstream;
|
||||
|
@ -60,10 +101,11 @@ namespace file_io_utils
|
|||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline
|
||||
bool get_file_time(const std::string& path_to_file, OUT time_t& ft)
|
||||
bool get_file_time(const std::string& path_to_file, time_t& ft)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
ft = boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ec);
|
||||
|
@ -88,6 +130,27 @@ namespace file_io_utils
|
|||
inline
|
||||
bool load_file_to_string(const std::string& path_to_file, std::string& target_str)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WCHAR wide_path[1000];
|
||||
int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000);
|
||||
if (chars == 0)
|
||||
return false;
|
||||
HANDLE file_handle = CreateFileW(wide_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
DWORD file_size = GetFileSize(file_handle, NULL);
|
||||
if ((file_size == INVALID_FILE_SIZE) || (file_size > 1000000000)) {
|
||||
CloseHandle(file_handle);
|
||||
return false;
|
||||
}
|
||||
target_str.resize(file_size);
|
||||
DWORD bytes_read;
|
||||
BOOL result = ReadFile(file_handle, &target_str[0], file_size, &bytes_read, NULL);
|
||||
CloseHandle(file_handle);
|
||||
if (bytes_read != file_size)
|
||||
result = FALSE;
|
||||
return result;
|
||||
#else
|
||||
try
|
||||
{
|
||||
std::ifstream fstream;
|
||||
|
@ -112,11 +175,13 @@ namespace file_io_utils
|
|||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline
|
||||
bool append_string_to_file(const std::string& path_to_file, const std::string& str)
|
||||
{
|
||||
// No special Windows implementation because so far not used in Monero code
|
||||
try
|
||||
{
|
||||
std::ofstream fstream;
|
||||
|
@ -132,6 +197,43 @@ namespace file_io_utils
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
bool get_file_size(const std::string& path_to_file, uint64_t &size)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WCHAR wide_path[1000];
|
||||
int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000);
|
||||
if (chars == 0)
|
||||
return false;
|
||||
HANDLE file_handle = CreateFileW(wide_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
LARGE_INTEGER file_size;
|
||||
BOOL result = GetFileSizeEx(file_handle, &file_size);
|
||||
CloseHandle(file_handle);
|
||||
if (result) {
|
||||
size = file_size.QuadPart;
|
||||
}
|
||||
return size;
|
||||
#else
|
||||
try
|
||||
{
|
||||
std::ifstream fstream;
|
||||
fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate);
|
||||
size = fstream.tellg();
|
||||
fstream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2017, The Monero Project
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <boost/uuid/random_generator.hpp>
|
||||
|
||||
#include "misc_os_dependent.h"
|
||||
#include "syncobj.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <array>
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *memwipe(void *src, size_t n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace tools {
|
||||
|
||||
/// Scrubs data in the contained type upon destruction.
|
||||
///
|
||||
/// Primarily useful for making sure that private keys don't stick around in
|
||||
/// memory after the objects that held them have gone out of scope.
|
||||
template <class T>
|
||||
struct scrubbed : public T {
|
||||
using type = T;
|
||||
|
||||
~scrubbed() {
|
||||
scrub();
|
||||
}
|
||||
|
||||
/// Destroy the contents of the contained type.
|
||||
void scrub() {
|
||||
static_assert(std::is_pod<T>::value,
|
||||
"T cannot be auto-scrubbed. T must be POD.");
|
||||
static_assert(std::is_trivially_destructible<T>::value,
|
||||
"T cannot be auto-scrubbed. T must be trivially destructable.");
|
||||
memwipe(this, sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T& unwrap(scrubbed<T>& src) { return src; }
|
||||
|
||||
template<typename T>
|
||||
const T& unwrap(scrubbed<T> const& src) { return src; }
|
||||
|
||||
template <class T, size_t N>
|
||||
using scrubbed_arr = scrubbed<std::array<T, N>>;
|
||||
} // namespace tools
|
||||
|
||||
#endif // __cplusplus
|
|
@ -23,6 +23,10 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifdef _WIN32
|
||||
#include <Winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
@ -42,6 +46,9 @@
|
|||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#pragma once
|
||||
namespace epee
|
||||
{
|
||||
|
@ -68,13 +75,13 @@ namespace misc_utils
|
|||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
|
||||
return (mts.tv_sec * 1000000000) + (mts.tv_nsec);
|
||||
return ((uint64_t)mts.tv_sec * 1000000000) + (mts.tv_nsec);
|
||||
#else
|
||||
struct timespec ts;
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return (ts.tv_sec * 1000000000) + (ts.tv_nsec);
|
||||
return ((uint64_t)ts.tv_sec * 1000000000) + (ts.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -305,7 +305,7 @@ namespace net_utils
|
|||
m_connections.back().powner = this;
|
||||
m_connections.back().m_self_it = --m_connections.end();
|
||||
m_connections.back().m_context.m_remote_address = remote_address;
|
||||
m_connections.back().m_htread = threads_helper::create_thread(ConnectionHandlerProc, &m_connections.back());
|
||||
m_connections.back().m_htread = threads_helper::create_thread(ConnectionHandlerProc, &m_connections.back()); // ugh, seems very risky
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -54,8 +54,8 @@
|
|||
#include <boost/thread/thread.hpp>
|
||||
#include "net_utils_base.h"
|
||||
#include "syncobj.h"
|
||||
#include "../../../../src/p2p/connection_basic.hpp"
|
||||
#include "../../../../src/p2p/network_throttle-detail.hpp"
|
||||
#include "connection_basic.hpp"
|
||||
#include "network_throttle-detail.hpp"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
@ -207,12 +207,18 @@ namespace net_utils
|
|||
|
||||
bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0");
|
||||
template<class t_callback>
|
||||
bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_callback cb, const std::string& bind_ip = "0.0.0.0");
|
||||
bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0");
|
||||
|
||||
typename t_protocol_handler::config_type& get_config_object(){return m_config;}
|
||||
|
||||
int get_binded_port(){return m_port;}
|
||||
|
||||
long get_connections_count() const
|
||||
{
|
||||
auto connections_count = (m_sock_count > 0) ? (m_sock_count - 1) : 0; // Socket count minus listening socket
|
||||
return connections_count;
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service(){return io_service_;}
|
||||
|
||||
struct idle_callback_conext_base
|
||||
|
@ -281,8 +287,6 @@ namespace net_utils
|
|||
|
||||
bool is_thread_worker();
|
||||
|
||||
bool cleanup_connections();
|
||||
|
||||
/// The io_service used to perform asynchronous operations.
|
||||
std::unique_ptr<boost::asio::io_service> m_io_service_local_instance;
|
||||
boost::asio::io_service& io_service_;
|
||||
|
@ -309,7 +313,7 @@ namespace net_utils
|
|||
connection_ptr new_connection_;
|
||||
|
||||
boost::mutex connections_mutex;
|
||||
std::deque<std::pair<boost::system_time, connection_ptr>> connections_;
|
||||
std::set<connection_ptr> connections_;
|
||||
|
||||
}; // class <>boosted_tcp_server
|
||||
|
||||
|
|
|
@ -54,8 +54,6 @@
|
|||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#define CONNECTION_CLEANUP_TIME 30 // seconds
|
||||
|
||||
PRAGMA_WARNING_PUSH
|
||||
namespace epee
|
||||
{
|
||||
|
@ -82,7 +80,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
m_throttle_speed_in("speed_in", "throttle_speed_in"),
|
||||
m_throttle_speed_out("speed_out", "throttle_speed_out")
|
||||
{
|
||||
MINFO("test, connection constructor set m_connection_type="<<m_connection_type);
|
||||
MDEBUG("test, connection constructor set m_connection_type="<<m_connection_type);
|
||||
}
|
||||
PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
//---------------------------------------------------------------------------------
|
||||
|
@ -139,14 +137,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
|
||||
|
||||
context = boost::value_initialized<t_connection_context>();
|
||||
long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong());
|
||||
const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())};
|
||||
|
||||
// create a random uuid
|
||||
boost::uuids::uuid random_uuid;
|
||||
// that stuff turns out to be included, even though it's from src... Taking advantage
|
||||
random_uuid = crypto::rand<boost::uuids::uuid>();
|
||||
|
||||
context.set_details(random_uuid, new epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income);
|
||||
context.set_details(random_uuid, epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income);
|
||||
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
|
||||
" to " << local_ep.address().to_string() << ':' << local_ep.port() <<
|
||||
", total sockets objects " << m_ref_sock_count);
|
||||
|
@ -266,7 +264,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
address = endpoint.address().to_string();
|
||||
port = boost::lexical_cast<std::string>(endpoint.port());
|
||||
}
|
||||
MINFO(" connection type " << to_string( m_connection_type ) << " "
|
||||
MDEBUG(" connection type " << to_string( m_connection_type ) << " "
|
||||
<< socket_.local_endpoint().address().to_string() << ":" << socket_.local_endpoint().port()
|
||||
<< " <--> " << address << ":" << port);
|
||||
}
|
||||
|
@ -288,7 +286,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
|
||||
{
|
||||
CRITICAL_REGION_LOCAL( epee::net_utils::network_throttle_manager::network_throttle_manager::m_lock_get_global_throttle_in );
|
||||
epee::net_utils::network_throttle_manager::network_throttle_manager::get_global_throttle_in().handle_trafic_exact(bytes_transferred * 1024);
|
||||
epee::net_utils::network_throttle_manager::network_throttle_manager::get_global_throttle_in().handle_trafic_exact(bytes_transferred);
|
||||
}
|
||||
|
||||
double delay=0; // will be calculated - how much we should sleep to obey speed limit etc
|
||||
|
@ -299,7 +297,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
{
|
||||
{ //_scope_dbg1("CRITICAL_REGION_LOCAL");
|
||||
CRITICAL_REGION_LOCAL( epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_in );
|
||||
delay = epee::net_utils::network_throttle_manager::get_global_throttle_in().get_sleep_time_after_tick( bytes_transferred ); // decission from global throttle
|
||||
delay = epee::net_utils::network_throttle_manager::get_global_throttle_in().get_sleep_time_after_tick( bytes_transferred );
|
||||
}
|
||||
|
||||
delay *= 0.5;
|
||||
|
@ -484,9 +482,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
//some data should be wrote to stream
|
||||
//request complete
|
||||
|
||||
if (speed_limit_is_enabled()) {
|
||||
sleep_before_packet(cb, 1, 1);
|
||||
}
|
||||
// No sleeping here; sleeping is done once and for all in "handle_write"
|
||||
|
||||
m_send_que_lock.lock(); // *** critical ***
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_send_que_lock.unlock();});
|
||||
|
@ -609,6 +605,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
}
|
||||
logger_handle_net_write(cb);
|
||||
|
||||
// The single sleeping that is needed for correctly handling "out" speed throttling
|
||||
if (speed_limit_is_enabled()) {
|
||||
sleep_before_packet(cb, 1, 1);
|
||||
}
|
||||
|
@ -738,7 +735,17 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
boost::asio::placeholders::error));
|
||||
|
||||
return true;
|
||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::init_server", false);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
MFATAL("Error starting server: " << e.what());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
MFATAL("Error starting server");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
PUSH_WARNINGS
|
||||
|
@ -808,7 +815,6 @@ POP_WARNINGS
|
|||
m_threads_count = threads_count;
|
||||
m_main_thread_id = boost::this_thread::get_id();
|
||||
MLOG_SET_THREAD_NAME("[SRV_MAIN]");
|
||||
add_idle_handler(boost::bind(&boosted_tcp_server::cleanup_connections, this), 5000);
|
||||
while(!m_stop_signal_sent)
|
||||
{
|
||||
|
||||
|
@ -898,7 +904,7 @@ POP_WARNINGS
|
|||
connections_mutex.lock();
|
||||
for (auto &c: connections_)
|
||||
{
|
||||
c.second->cancel();
|
||||
c->cancel();
|
||||
}
|
||||
connections_.clear();
|
||||
connections_mutex.unlock();
|
||||
|
@ -907,19 +913,6 @@ POP_WARNINGS
|
|||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::cleanup_connections()
|
||||
{
|
||||
connections_mutex.lock();
|
||||
boost::system_time cutoff = boost::get_system_time() - boost::posix_time::seconds(CONNECTION_CLEANUP_TIME);
|
||||
while (!connections_.empty() && connections_.front().first < cutoff)
|
||||
{
|
||||
connections_.pop_front();
|
||||
}
|
||||
connections_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::is_stop_signal_sent()
|
||||
{
|
||||
return m_stop_signal_sent;
|
||||
|
@ -942,6 +935,9 @@ POP_WARNINGS
|
|||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
|
||||
boost::asio::socket_base::keep_alive opt(true);
|
||||
conn->socket().set_option(opt);
|
||||
|
||||
conn->start(true, 1 < m_threads_count);
|
||||
conn->save_dbg_log();
|
||||
}else
|
||||
|
@ -958,9 +954,10 @@ POP_WARNINGS
|
|||
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
||||
connections_mutex.lock();
|
||||
connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l));
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
connections_mutex.unlock();
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1038,6 +1035,10 @@ POP_WARNINGS
|
|||
|
||||
_dbg3("Connected success to " << adr << ':' << port);
|
||||
|
||||
// start adds the connection to the config object's list, so we don't need to have it locally anymore
|
||||
connections_mutex.lock();
|
||||
connections_.erase(new_connection_l);
|
||||
connections_mutex.unlock();
|
||||
bool r = new_connection_l->start(false, 1 < m_threads_count);
|
||||
if (r)
|
||||
{
|
||||
|
@ -1057,14 +1058,15 @@ POP_WARNINGS
|
|||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler> template<class t_callback>
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_callback cb, const std::string& bind_ip)
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
||||
connections_mutex.lock();
|
||||
connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l));
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
connections_mutex.unlock();
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1113,6 +1115,11 @@ POP_WARNINGS
|
|||
{
|
||||
_dbg3("[sock " << new_connection_l->socket().native_handle() << "] Connected success to " << adr << ':' << port <<
|
||||
" from " << lep.address().to_string() << ':' << lep.port());
|
||||
|
||||
// start adds the connection to the config object's list, so we don't need to have it locally anymore
|
||||
connections_mutex.lock();
|
||||
connections_.erase(new_connection_l);
|
||||
connections_mutex.unlock();
|
||||
bool r = new_connection_l->start(false, 1 < m_threads_count);
|
||||
if (r)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/// @file
|
||||
/// @author rfree (current maintainer in monero.cc project)
|
||||
/// @brief base for connection, contains e.g. the ratelimit hooks
|
||||
|
||||
// ! This file might contain variable names same as in template class connection<>
|
||||
// ! from files contrib/epee/include/net/abstract_tcp_server2.*
|
||||
// ! I am not a lawyer; afaik APIs, var names etc are not copyrightable ;)
|
||||
// ! (how ever if in some wonderful juristdictions that is not the case, then why not make another sub-class withat that members and licence it as epee part)
|
||||
// ! Working on above premise, IF this is valid in your juristdictions, then consider this code as released as:
|
||||
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/* rfree: place for hanlers for the non-template base, can be used by connection<> template class in abstract_tcp_server2 file */
|
||||
|
||||
#ifndef INCLUDED_p2p_connection_basic_hpp
|
||||
#define INCLUDED_p2p_connection_basic_hpp
|
||||
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <atomic>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "net/net_utils_base.h"
|
||||
#include "syncobj.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
/// Represents a single connection from a client.
|
||||
|
||||
class connection_basic_pimpl; // PIMPL for this class
|
||||
|
||||
enum t_connection_type { // type of the connection (of this server), e.g. so that we will know how to limit it
|
||||
e_connection_type_NET = 0, // default (not used?)
|
||||
e_connection_type_RPC = 1, // the rpc commands (probably not rate limited, not chunked, etc)
|
||||
e_connection_type_P2P = 2 // to other p2p node (probably limited)
|
||||
};
|
||||
|
||||
std::string to_string(t_connection_type type);
|
||||
|
||||
class connection_basic { // not-templated base class for rapid developmet of some code parts
|
||||
public:
|
||||
std::unique_ptr< connection_basic_pimpl > mI; // my Implementation
|
||||
|
||||
// moved here from orginal connecton<> - common member variables that do not depend on template in connection<>
|
||||
volatile uint32_t m_want_close_connection;
|
||||
std::atomic<bool> m_was_shutdown;
|
||||
critical_section m_send_que_lock;
|
||||
std::list<std::string> m_send_que;
|
||||
volatile bool m_is_multithreaded;
|
||||
double m_start_time;
|
||||
/// Strand to ensure the connection's handlers are not called concurrently.
|
||||
boost::asio::io_service::strand strand_;
|
||||
/// Socket for the connection.
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
std::atomic<long> &m_ref_sock_count; // reference to external counter of existing sockets that we will ++/--
|
||||
public:
|
||||
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator
|
||||
connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number);
|
||||
|
||||
virtual ~connection_basic() noexcept(false);
|
||||
|
||||
// various handlers to be called from connection class:
|
||||
void do_send_handler_write(const void * ptr , size_t cb);
|
||||
void do_send_handler_write_from_queue(const boost::system::error_code& e, size_t cb , int q_len); // from handle_write, sending next part
|
||||
|
||||
void logger_handle_net_write(size_t size); // network data written
|
||||
void logger_handle_net_read(size_t size); // network data read
|
||||
|
||||
void set_start_time();
|
||||
|
||||
// config for rate limit
|
||||
|
||||
static void set_rate_up_limit(uint64_t limit);
|
||||
static void set_rate_down_limit(uint64_t limit);
|
||||
static uint64_t get_rate_up_limit();
|
||||
static uint64_t get_rate_down_limit();
|
||||
|
||||
// config misc
|
||||
static void set_tos_flag(int tos); // ToS / QoS flag
|
||||
static int get_tos_flag();
|
||||
|
||||
// handlers and sleep
|
||||
void sleep_before_packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?)
|
||||
static void save_limit_to_file(int limit); ///< for dr-monero
|
||||
static double get_sleep_time(size_t cb);
|
||||
|
||||
static void set_save_graph(bool save_graph);
|
||||
};
|
||||
|
||||
} // nameserver
|
||||
} // nameserver
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -33,7 +33,7 @@
|
|||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "wipeable_string.h"
|
||||
#include "http_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
|
@ -48,12 +48,12 @@ namespace net_utils
|
|||
struct login
|
||||
{
|
||||
login() : username(), password() {}
|
||||
login(std::string username_, std::string password_)
|
||||
login(std::string username_, wipeable_string password_)
|
||||
: username(std::move(username_)), password(std::move(password_))
|
||||
{}
|
||||
|
||||
std::string username;
|
||||
std::string password;
|
||||
wipeable_string password;
|
||||
};
|
||||
|
||||
//! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added.
|
||||
|
@ -71,8 +71,8 @@ namespace net_utils
|
|||
std::uint32_t counter;
|
||||
};
|
||||
|
||||
http_server_auth() : user() {}
|
||||
http_server_auth(login credentials);
|
||||
http_server_auth() : user(), rng() {}
|
||||
http_server_auth(login credentials, std::function<void(size_t, uint8_t*)> r);
|
||||
|
||||
//! \return Auth response, or `boost::none` iff `request` had valid auth.
|
||||
boost::optional<http_response_info> get_response(const http_request_info& request)
|
||||
|
@ -81,10 +81,13 @@ namespace net_utils
|
|||
return do_get_response(request);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::optional<http_response_info> do_get_response(const http_request_info& request);
|
||||
|
||||
boost::optional<session> user;
|
||||
|
||||
std::function<void(size_t, uint8_t*)> rng;
|
||||
};
|
||||
|
||||
//! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added.
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace net_utils
|
|||
{
|
||||
|
||||
enum http_method{
|
||||
http_method_options,
|
||||
http_method_get,
|
||||
http_method_post,
|
||||
http_method_put,
|
||||
|
@ -115,6 +116,7 @@ namespace net_utils
|
|||
std::string m_host; //"Host:"
|
||||
std::string m_cookie; //"Cookie:"
|
||||
std::string m_user_agent; //"User-Agent:"
|
||||
std::string m_origin; //"Origin:"
|
||||
fields_list m_etc_fields;
|
||||
|
||||
void clear()
|
||||
|
@ -128,6 +130,7 @@ namespace net_utils
|
|||
m_host.clear();
|
||||
m_cookie.clear();
|
||||
m_user_agent.clear();
|
||||
m_origin.clear();
|
||||
m_etc_fields.clear();
|
||||
}
|
||||
};
|
||||
|
@ -155,7 +158,8 @@ namespace net_utils
|
|||
http_request_info():m_http_method(http_method_unknown),
|
||||
m_http_ver_hi(0),
|
||||
m_http_ver_lo(0),
|
||||
m_have_to_block(false)
|
||||
m_have_to_block(false),
|
||||
m_full_request_buf_size(0)
|
||||
{}
|
||||
|
||||
http_method m_http_method;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
|
||||
#pragma once
|
||||
#include <ctype.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
@ -50,6 +51,7 @@
|
|||
#include "http_auth.h"
|
||||
#include "to_nonconst_iterator.h"
|
||||
#include "net_parse_helpers.h"
|
||||
#include "syncobj.h"
|
||||
|
||||
//#include "shlwapi.h"
|
||||
|
||||
|
@ -66,8 +68,6 @@ namespace epee
|
|||
namespace net_utils
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*struct url
|
||||
{
|
||||
public:
|
||||
|
@ -237,7 +237,8 @@ using namespace std;
|
|||
namespace http
|
||||
{
|
||||
|
||||
class http_simple_client: public i_target_handler
|
||||
template<typename net_client_type>
|
||||
class http_simple_client_template: public i_target_handler
|
||||
{
|
||||
private:
|
||||
enum reciev_machine_state
|
||||
|
@ -260,7 +261,7 @@ using namespace std;
|
|||
};
|
||||
|
||||
|
||||
blocked_mode_client m_net_client;
|
||||
net_client_type m_net_client;
|
||||
std::string m_host_buff;
|
||||
std::string m_port;
|
||||
http_client_auth m_auth;
|
||||
|
@ -274,9 +275,10 @@ using namespace std;
|
|||
chunked_state m_chunked_state;
|
||||
std::string m_chunked_cache;
|
||||
critical_section m_lock;
|
||||
bool m_ssl;
|
||||
|
||||
public:
|
||||
explicit http_simple_client()
|
||||
explicit http_simple_client_template()
|
||||
: i_target_handler()
|
||||
, m_net_client()
|
||||
, m_host_buff()
|
||||
|
@ -291,33 +293,35 @@ using namespace std;
|
|||
, m_chunked_state()
|
||||
, m_chunked_cache()
|
||||
, m_lock()
|
||||
, m_ssl(false)
|
||||
{}
|
||||
|
||||
const std::string &get_host() const { return m_host_buff; };
|
||||
const std::string &get_port() const { return m_port; };
|
||||
|
||||
bool set_server(const std::string& address, boost::optional<login> user)
|
||||
bool set_server(const std::string& address, boost::optional<login> user, bool ssl = false)
|
||||
{
|
||||
http::url_content parsed{};
|
||||
const bool r = parse_url(address, parsed);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user));
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl);
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_server(std::string host, std::string port, boost::optional<login> user)
|
||||
void set_server(std::string host, std::string port, boost::optional<login> user, bool ssl = false)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
disconnect();
|
||||
m_host_buff = std::move(host);
|
||||
m_port = std::move(port);
|
||||
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
|
||||
m_ssl = ssl;
|
||||
}
|
||||
|
||||
bool connect(std::chrono::milliseconds timeout)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return m_net_client.connect(m_host_buff, m_port, timeout);
|
||||
return m_net_client.connect(m_host_buff, m_port, timeout, m_ssl);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool disconnect()
|
||||
|
@ -392,7 +396,6 @@ using namespace std;
|
|||
res = m_net_client.send(body, timeout);
|
||||
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
|
||||
|
||||
|
||||
m_response_info.clear();
|
||||
m_state = reciev_machine_state_header;
|
||||
if (!handle_reciev(timeout))
|
||||
|
@ -427,6 +430,15 @@ using namespace std;
|
|||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool test(const std::string &s, std::chrono::milliseconds timeout) // TEST FUNC ONLY
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
m_net_client.set_test_data(s);
|
||||
m_state = reciev_machine_state_header;
|
||||
return handle_reciev(timeout);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
private:
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool handle_reciev(std::chrono::milliseconds timeout)
|
||||
|
@ -741,85 +753,107 @@ using namespace std;
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
inline
|
||||
bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process)
|
||||
{
|
||||
MTRACE("http_stream_filter::parse_cached_header(*)");
|
||||
|
||||
STATIC_REGEXP_EXPR_1(rexp_mach_field,
|
||||
"\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)"
|
||||
// 12 3 4 5 6 7 8 9 10
|
||||
"|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
|
||||
//11 1213 14
|
||||
boost::regex::icase | boost::regex::normal);
|
||||
|
||||
boost::smatch result;
|
||||
std::string::const_iterator it_current_bound = m_cache_to_process.begin();
|
||||
std::string::const_iterator it_end_bound = m_cache_to_process.end();
|
||||
|
||||
|
||||
|
||||
//lookup all fields and fill well-known fields
|
||||
while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched)
|
||||
{
|
||||
const size_t field_val = 13;
|
||||
//const size_t field_etc_name = 11;
|
||||
|
||||
int i = 2; //start position = 2
|
||||
if(result[i++].matched)//"Connection"
|
||||
body_info.m_connection = result[field_val];
|
||||
else if(result[i++].matched)//"Referrer"
|
||||
body_info.m_referer = result[field_val];
|
||||
else if(result[i++].matched)//"Content-Length"
|
||||
body_info.m_content_length = result[field_val];
|
||||
else if(result[i++].matched)//"Content-Type"
|
||||
body_info.m_content_type = result[field_val];
|
||||
else if(result[i++].matched)//"Transfer-Encoding"
|
||||
body_info.m_transfer_encoding = result[field_val];
|
||||
else if(result[i++].matched)//"Content-Encoding"
|
||||
body_info.m_content_encoding = result[field_val];
|
||||
else if(result[i++].matched)//"Host"
|
||||
{ body_info.m_host = result[field_val];
|
||||
string_tools::trim(body_info.m_host);
|
||||
}
|
||||
else if(result[i++].matched)//"Cookie"
|
||||
body_info.m_cookie = result[field_val];
|
||||
else if(result[i++].matched)//"User-Agent"
|
||||
body_info.m_user_agent = result[field_val];
|
||||
else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
|
||||
body_info.m_etc_fields.emplace_back(result[11], result[field_val]);
|
||||
else
|
||||
{CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<<m_cache_to_process);}
|
||||
|
||||
it_current_bound = result[(int)result.size()-1]. first;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
inline
|
||||
bool analize_first_response_line()
|
||||
inline bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process)
|
||||
{
|
||||
MTRACE("http_stream_filter::parse_cached_header(*)");
|
||||
|
||||
//First line response, look like this: "HTTP/1.1 200 OK"
|
||||
STATIC_REGEXP_EXPR_1(rexp_match_first_response_line, "^HTTP/(\\d+).(\\d+) ((\\d)\\d{2})( [^\n]*)?\r?\n", boost::regex::icase | boost::regex::normal);
|
||||
// 1 2 34 5
|
||||
//size_t match_len = 0;
|
||||
boost::smatch result;
|
||||
if(boost::regex_search( m_header_cache, result, rexp_match_first_response_line, boost::match_default) && result[0].matched)
|
||||
const char *ptr = m_cache_to_process.c_str();
|
||||
while (ptr[0] != '\r' || ptr[1] != '\n')
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(result[1].matched&&result[2].matched, false, "http_stream_filter::handle_invoke_reply_line() assert failed...");
|
||||
m_response_info.m_http_ver_hi = boost::lexical_cast<int>(result[1]);
|
||||
m_response_info.m_http_ver_lo = boost::lexical_cast<int>(result[2]);
|
||||
m_response_info.m_response_code = boost::lexical_cast<int>(result[3]);
|
||||
|
||||
m_header_cache.erase(to_nonsonst_iterator(m_header_cache, result[0].first), to_nonsonst_iterator(m_header_cache, result[0].second));
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
LOG_ERROR("http_stream_filter::handle_invoke_reply_line(): Failed to match first response line:" << m_header_cache);
|
||||
return false;
|
||||
// optional \n
|
||||
if (*ptr == '\n')
|
||||
++ptr;
|
||||
// an identifier composed of letters or -
|
||||
const char *key_pos = ptr;
|
||||
while (isalnum(*ptr) || *ptr == '_' || *ptr == '-')
|
||||
++ptr;
|
||||
const char *key_end = ptr;
|
||||
// optional space (not in RFC, but in previous code)
|
||||
if (*ptr == ' ')
|
||||
++ptr;
|
||||
CHECK_AND_ASSERT_MES(*ptr == ':', true, "http_stream_filter::parse_cached_header() invalid header in: " << m_cache_to_process);
|
||||
++ptr;
|
||||
// optional whitespace, but not newlines - line folding is obsolete, let's ignore it
|
||||
while (isblank(*ptr))
|
||||
++ptr;
|
||||
const char *value_pos = ptr;
|
||||
while (*ptr != '\r' && *ptr != '\n')
|
||||
++ptr;
|
||||
const char *value_end = ptr;
|
||||
// optional trailing whitespace
|
||||
while (value_end > value_pos && isblank(*(value_end-1)))
|
||||
--value_end;
|
||||
if (*ptr == '\r')
|
||||
++ptr;
|
||||
CHECK_AND_ASSERT_MES(*ptr == '\n', true, "http_stream_filter::parse_cached_header() invalid header in: " << m_cache_to_process);
|
||||
++ptr;
|
||||
|
||||
const std::string key = std::string(key_pos, key_end - key_pos);
|
||||
const std::string value = std::string(value_pos, value_end - value_pos);
|
||||
if (!key.empty())
|
||||
{
|
||||
if (!string_tools::compare_no_case(key, "Connection"))
|
||||
body_info.m_connection = value;
|
||||
else if(!string_tools::compare_no_case(key, "Referrer"))
|
||||
body_info.m_referer = value;
|
||||
else if(!string_tools::compare_no_case(key, "Content-Length"))
|
||||
body_info.m_content_length = value;
|
||||
else if(!string_tools::compare_no_case(key, "Content-Type"))
|
||||
body_info.m_content_type = value;
|
||||
else if(!string_tools::compare_no_case(key, "Transfer-Encoding"))
|
||||
body_info.m_transfer_encoding = value;
|
||||
else if(!string_tools::compare_no_case(key, "Content-Encoding"))
|
||||
body_info.m_content_encoding = value;
|
||||
else if(!string_tools::compare_no_case(key, "Host"))
|
||||
body_info.m_host = value;
|
||||
else if(!string_tools::compare_no_case(key, "Cookie"))
|
||||
body_info.m_cookie = value;
|
||||
else if(!string_tools::compare_no_case(key, "User-Agent"))
|
||||
body_info.m_user_agent = value;
|
||||
else if(!string_tools::compare_no_case(key, "Origin"))
|
||||
body_info.m_origin = value;
|
||||
else
|
||||
body_info.m_etc_fields.emplace_back(key, value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool analize_first_response_line()
|
||||
{
|
||||
//First line response, look like this: "HTTP/1.1 200 OK"
|
||||
const char *ptr = m_header_cache.c_str();
|
||||
CHECK_AND_ASSERT_MES(!memcmp(ptr, "HTTP/", 5), false, "Invalid first response line: " + m_header_cache);
|
||||
ptr += 5;
|
||||
CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
|
||||
unsigned long ul;
|
||||
char *end;
|
||||
ul = strtoul(ptr, &end, 10);
|
||||
CHECK_AND_ASSERT_MES(ul <= INT_MAX && *end =='.', false, "Invalid first response line: " + m_header_cache);
|
||||
m_response_info.m_http_ver_hi = ul;
|
||||
ptr = end + 1;
|
||||
CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
|
||||
ul = strtoul(ptr, &end, 10);
|
||||
CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(*end), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
|
||||
m_response_info.m_http_ver_lo = ul;
|
||||
ptr = end + 1;
|
||||
while (isblank(*ptr))
|
||||
++ptr;
|
||||
CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
|
||||
ul = strtoul(ptr, &end, 10);
|
||||
CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(*end), false, "Invalid first response line: " + m_header_cache);
|
||||
m_response_info.m_response_code = ul;
|
||||
ptr = end;
|
||||
// ignore the optional text, till the end
|
||||
while (*ptr != '\r' && *ptr != '\n')
|
||||
++ptr;
|
||||
if (*ptr == '\r')
|
||||
++ptr;
|
||||
CHECK_AND_ASSERT_MES(*ptr == '\n', false, "Invalid first response line: " << m_header_cache);
|
||||
++ptr;
|
||||
|
||||
m_header_cache.erase(0, ptr - m_header_cache.c_str());
|
||||
return true;
|
||||
}
|
||||
inline
|
||||
bool set_reply_content_encoder()
|
||||
|
@ -954,6 +988,7 @@ using namespace std;
|
|||
return true;
|
||||
}
|
||||
};
|
||||
typedef http_simple_client_template<blocked_mode_client> http_simple_client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ namespace epee
|
|||
virtual ~i_sub_handler(){}
|
||||
|
||||
virtual bool update_in( std::string& piece_of_transfer)=0;
|
||||
virtual void stop(std::string& OUT collect_remains)=0;
|
||||
virtual bool update_and_stop(std::string& OUT collect_remains, bool& is_changed)
|
||||
virtual void stop(std::string& collect_remains)=0;
|
||||
virtual bool update_and_stop(std::string& collect_remains, bool& is_changed)
|
||||
{
|
||||
is_changed = true;
|
||||
bool res = this->update_in(collect_remains);
|
||||
|
@ -66,7 +66,7 @@ namespace epee
|
|||
{
|
||||
return m_powner_filter->handle_target_data(piece_of_transfer);
|
||||
}
|
||||
virtual void stop(std::string& OUT collect_remains)
|
||||
virtual void stop(std::string& collect_remains)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ namespace net_utils
|
|||
struct http_server_config
|
||||
{
|
||||
std::string m_folder;
|
||||
std::vector<std::string> m_access_control_origins;
|
||||
boost::optional<login> m_user;
|
||||
critical_section m_lock;
|
||||
};
|
||||
|
@ -159,6 +160,7 @@ namespace net_utils
|
|||
struct custum_handler_config: public http_server_config
|
||||
{
|
||||
i_http_server_handler<t_connection_context>* m_phandler;
|
||||
std::function<void(size_t, uint8_t*)> rng;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -175,7 +177,7 @@ namespace net_utils
|
|||
: simple_http_connection_handler<t_connection_context>(psnd_hndlr, config),
|
||||
m_config(config),
|
||||
m_conn_context(conn_context),
|
||||
m_auth(m_config.m_user ? http_server_auth{*m_config.m_user} : http_server_auth{})
|
||||
m_auth(m_config.m_user ? http_server_auth{*m_config.m_user, config.rng} : http_server_auth{})
|
||||
{}
|
||||
inline bool handle_request(const http_request_info& query_info, http_response_info& response)
|
||||
{
|
||||
|
@ -193,6 +195,7 @@ namespace net_utils
|
|||
response.m_response_code = 200;
|
||||
response.m_response_comment = "OK";
|
||||
response.m_body.clear();
|
||||
|
||||
return m_config.m_phandler->handle_http_request(query_info, response, m_conn_context);
|
||||
}
|
||||
|
||||
|
|
|
@ -316,7 +316,10 @@ namespace net_utils
|
|||
CHECK_AND_ASSERT_MES(result[0].matched, false, "simple_http_connection_handler::analize_http_method() assert failed...");
|
||||
http_ver_major = boost::lexical_cast<int>(result[11]);
|
||||
http_ver_minor = boost::lexical_cast<int>(result[12]);
|
||||
if(result[4].matched)
|
||||
|
||||
if(result[3].matched)
|
||||
method = http::http_method_options;
|
||||
else if(result[4].matched)
|
||||
method = http::http_method_get;
|
||||
else if(result[5].matched)
|
||||
method = http::http_method_head;
|
||||
|
@ -342,7 +345,12 @@ namespace net_utils
|
|||
{
|
||||
analize_http_method(result, m_query_info.m_http_method, m_query_info.m_http_ver_hi, m_query_info.m_http_ver_hi);
|
||||
m_query_info.m_URI = result[10];
|
||||
parse_uri(m_query_info.m_URI, m_query_info.m_uri_content);
|
||||
if (!parse_uri(m_query_info.m_URI, m_query_info.m_uri_content))
|
||||
{
|
||||
m_state = http_state_error;
|
||||
MERROR("Failed to parse URI: m_query_info.m_URI");
|
||||
return false;
|
||||
}
|
||||
m_query_info.m_http_method_str = result[2];
|
||||
m_query_info.m_full_request_str = result[0];
|
||||
|
||||
|
@ -472,8 +480,8 @@ namespace net_utils
|
|||
bool simple_http_connection_handler<t_connection_context>::parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos)
|
||||
{
|
||||
STATIC_REGEXP_EXPR_1(rexp_mach_field,
|
||||
"\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)"
|
||||
// 12 3 4 5 6 7 8 9 10
|
||||
"\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)|(Origin)"
|
||||
// 12 3 4 5 6 7 8 9 10 11
|
||||
"|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
|
||||
//11 1213 14
|
||||
boost::regex::icase | boost::regex::normal);
|
||||
|
@ -487,8 +495,8 @@ namespace net_utils
|
|||
//lookup all fields and fill well-known fields
|
||||
while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched)
|
||||
{
|
||||
const size_t field_val = 13;
|
||||
const size_t field_etc_name = 11;
|
||||
const size_t field_val = 14;
|
||||
const size_t field_etc_name = 12;
|
||||
|
||||
int i = 2; //start position = 2
|
||||
if(result[i++].matched)//"Connection"
|
||||
|
@ -509,6 +517,8 @@ namespace net_utils
|
|||
body_info.m_cookie = result[field_val];
|
||||
else if(result[i++].matched)//"User-Agent"
|
||||
body_info.m_user_agent = result[field_val];
|
||||
else if(result[i++].matched)//"Origin"
|
||||
body_info.m_origin = result[field_val];
|
||||
else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
|
||||
body_info.m_etc_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val]));
|
||||
else
|
||||
|
@ -537,17 +547,27 @@ namespace net_utils
|
|||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::handle_request_and_send_response(const http::http_request_info& query_info)
|
||||
{
|
||||
http_response_info response;
|
||||
bool res = handle_request(query_info, response);
|
||||
http_response_info response{};
|
||||
//CHECK_AND_ASSERT_MES(res, res, "handle_request(query_info, response) returned false" );
|
||||
bool res = true;
|
||||
|
||||
if (query_info.m_http_method != http::http_method_options)
|
||||
{
|
||||
res = handle_request(query_info, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.m_response_code = 200;
|
||||
response.m_response_comment = "OK";
|
||||
}
|
||||
|
||||
std::string response_data = get_response_header(response);
|
||||
|
||||
//LOG_PRINT_L0("HTTP_SEND: << \r\n" << response_data + response.m_body);
|
||||
|
||||
LOG_PRINT_L3("HTTP_RESPONSE_HEAD: << \r\n" << response_data);
|
||||
|
||||
m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size());
|
||||
if(response.m_body.size() && (query_info.m_http_method != http::http_method_head))
|
||||
if ((response.m_body.size() && (query_info.m_http_method != http::http_method_head)) || (query_info.m_http_method == http::http_method_options))
|
||||
m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size());
|
||||
return res;
|
||||
}
|
||||
|
@ -579,7 +599,6 @@ namespace net_utils
|
|||
response.m_response_comment = "OK";
|
||||
response.m_mime_tipe = get_file_mime_tipe(uri_to_path);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
@ -591,8 +610,12 @@ namespace net_utils
|
|||
"Server: Epee-based\r\n"
|
||||
"Content-Length: ";
|
||||
buf += boost::lexical_cast<std::string>(response.m_body.size()) + "\r\n";
|
||||
buf += "Content-Type: ";
|
||||
buf += response.m_mime_tipe + "\r\n";
|
||||
|
||||
if(!response.m_mime_tipe.empty())
|
||||
{
|
||||
buf += "Content-Type: ";
|
||||
buf += response.m_mime_tipe + "\r\n";
|
||||
}
|
||||
|
||||
buf += "Last-Modified: ";
|
||||
time_t tm;
|
||||
|
@ -612,6 +635,22 @@ namespace net_utils
|
|||
m_want_close = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Cross-origin resource sharing
|
||||
if(m_query_info.m_header_info.m_origin.size())
|
||||
{
|
||||
if (std::binary_search(m_config.m_access_control_origins.begin(), m_config.m_access_control_origins.end(), m_query_info.m_header_info.m_origin))
|
||||
{
|
||||
buf += "Access-Control-Allow-Origin: ";
|
||||
buf += m_query_info.m_header_info.m_origin;
|
||||
buf += "\r\n";
|
||||
buf += "Access-Control-Expose-Headers: www-authenticate\r\n";
|
||||
if (m_query_info.m_http_method == http::http_method_options)
|
||||
buf += "Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With\r\n";
|
||||
buf += "Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
//add additional fields, if it is
|
||||
for(fields_list::const_iterator it = response.m_additional_fields.begin(); it!=response.m_additional_fields.end(); it++)
|
||||
buf += it->first + ":" + it->second + "\r\n";
|
||||
|
|
|
@ -55,16 +55,22 @@ namespace epee
|
|||
: m_net_server(external_io_service)
|
||||
{}
|
||||
|
||||
bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
|
||||
bool init(std::function<void(size_t, uint8_t*)> rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
|
||||
std::vector<std::string> access_control_origins = std::vector<std::string>(),
|
||||
boost::optional<net_utils::http::login> user = boost::none)
|
||||
{
|
||||
|
||||
//set self as callback handler
|
||||
m_net_server.get_config_object().m_phandler = static_cast<t_child_class*>(this);
|
||||
m_net_server.get_config_object().rng = std::move(rng);
|
||||
|
||||
//here set folder for hosting reqests
|
||||
m_net_server.get_config_object().m_folder = "";
|
||||
|
||||
//set access control allow origins if configured
|
||||
std::sort(access_control_origins.begin(), access_control_origins.end());
|
||||
m_net_server.get_config_object().m_access_control_origins = std::move(access_control_origins);
|
||||
|
||||
m_net_server.get_config_object().m_user = std::move(user);
|
||||
|
||||
MGINFO("Binding on " << bind_ip << ":" << bind_port);
|
||||
|
@ -112,6 +118,11 @@ namespace epee
|
|||
return m_net_server.get_binded_port();
|
||||
}
|
||||
|
||||
long get_connections_count() const
|
||||
{
|
||||
return m_net_server.get_connections_count();
|
||||
}
|
||||
|
||||
protected:
|
||||
net_utils::boosted_tcp_server<net_utils::http::http_custom_handler<t_connection_context> > m_net_server;
|
||||
};
|
||||
|
|
|
@ -87,6 +87,7 @@ namespace levin
|
|||
virtual void on_connection_new(t_connection_context& context){};
|
||||
virtual void on_connection_close(t_connection_context& context){};
|
||||
|
||||
virtual ~levin_commands_handler(){}
|
||||
};
|
||||
|
||||
#define LEVIN_OK 0
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace levin
|
|||
class levin_client_async
|
||||
{
|
||||
levin_commands_handler* m_pcommands_handler;
|
||||
void (*commands_handler_destroy)(levin_commands_handler*);
|
||||
volatile uint32_t m_is_stop;
|
||||
volatile uint32_t m_threads_count;
|
||||
::critical_section m_send_lock;
|
||||
|
@ -85,9 +86,9 @@ namespace levin
|
|||
::critical_section m_connection_lock;
|
||||
net_utils::blocked_mode_client m_transport;
|
||||
public:
|
||||
levin_client_async():m_pcommands_handler(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0)
|
||||
levin_client_async():m_pcommands_handler(NULL), commands_handler_destroy(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0)
|
||||
{}
|
||||
levin_client_async(const levin_client_async& /*v*/):m_pcommands_handler(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0)
|
||||
levin_client_async(const levin_client_async& /*v*/):m_pcommands_handler(NULL), commands_handler_destroy(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0)
|
||||
{}
|
||||
~levin_client_async()
|
||||
{
|
||||
|
@ -97,11 +98,16 @@ namespace levin
|
|||
|
||||
while(boost::interprocess::ipcdetail::atomic_read32(&m_threads_count))
|
||||
::Sleep(100);
|
||||
|
||||
set_handler(NULL);
|
||||
}
|
||||
|
||||
void set_handler(levin_commands_handler* phandler)
|
||||
void set_handler(levin_commands_handler* phandler, void (*destroy)(levin_commands_handler*) = NULL)
|
||||
{
|
||||
if (commands_handler_destroy && m_pcommands_handler)
|
||||
(*commands_handler_destroy)(m_pcommands_handler);
|
||||
m_pcommands_handler = phandler;
|
||||
m_pcommands_handler_destroy = destroy;
|
||||
}
|
||||
|
||||
bool connect(uint32_t ip, uint32_t port, uint32_t timeout)
|
||||
|
|
|
@ -43,6 +43,8 @@ namespace levin
|
|||
struct protocl_handler_config
|
||||
{
|
||||
levin_commands_handler<t_connection_context>* m_pcommands_handler;
|
||||
void (*m_pcommands_handler_destroy)(levin_commands_handler<t_connection_context>*);
|
||||
~protocl_handler_config() { if (m_pcommands_handler && m_pcommands_handler_destroy) (*m_pcommands_handler_destroy)(m_pcommands_handler); }
|
||||
};
|
||||
|
||||
template<class t_connection_context = net_utils::connection_context_base>
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
#include "levin_base.h"
|
||||
#include "misc_language.h"
|
||||
#include "syncobj.h"
|
||||
#include "misc_os_dependent.h"
|
||||
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
|
@ -72,29 +74,36 @@ class async_protocol_handler_config
|
|||
|
||||
friend class async_protocol_handler<t_connection_context>;
|
||||
|
||||
levin_commands_handler<t_connection_context>* m_pcommands_handler;
|
||||
void (*m_pcommands_handler_destroy)(levin_commands_handler<t_connection_context>*);
|
||||
|
||||
void delete_connections (size_t count, bool incoming);
|
||||
|
||||
public:
|
||||
typedef t_connection_context connection_context;
|
||||
levin_commands_handler<t_connection_context>* m_pcommands_handler;
|
||||
uint64_t m_max_packet_size;
|
||||
uint64_t m_invoke_timeout;
|
||||
|
||||
int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
|
||||
template<class callback_t>
|
||||
int invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, callback_t cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
|
||||
int invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
|
||||
|
||||
int notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id);
|
||||
bool close(boost::uuids::uuid connection_id);
|
||||
bool update_connection_context(const t_connection_context& contxt);
|
||||
bool request_callback(boost::uuids::uuid connection_id);
|
||||
template<class callback_t>
|
||||
bool foreach_connection(callback_t cb);
|
||||
bool foreach_connection(const callback_t &cb);
|
||||
template<class callback_t>
|
||||
bool for_connection(const boost::uuids::uuid &connection_id, callback_t cb);
|
||||
bool for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb);
|
||||
size_t get_connections_count();
|
||||
void set_handler(levin_commands_handler<t_connection_context>* handler, void (*destroy)(levin_commands_handler<t_connection_context>*) = NULL);
|
||||
|
||||
async_protocol_handler_config():m_pcommands_handler(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE)
|
||||
async_protocol_handler_config():m_pcommands_handler(NULL), m_pcommands_handler_destroy(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE)
|
||||
{}
|
||||
~async_protocol_handler_config() { set_handler(NULL, NULL); }
|
||||
void del_out_connections(size_t count);
|
||||
void del_in_connections(size_t count);
|
||||
};
|
||||
|
||||
|
||||
|
@ -239,7 +248,7 @@ public:
|
|||
std::list<boost::shared_ptr<invoke_response_handler_base> > m_invoke_response_handlers;
|
||||
|
||||
template<class callback_t>
|
||||
bool add_invoke_response_handler(callback_t cb, uint64_t timeout, async_protocol_handler& con, int command)
|
||||
bool add_invoke_response_handler(const callback_t &cb, uint64_t timeout, async_protocol_handler& con, int command)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock);
|
||||
boost::shared_ptr<invoke_response_handler_base> handler(boost::make_shared<anvoke_handler<callback_t>>(cb, timeout, con, command));
|
||||
|
@ -373,12 +382,16 @@ public:
|
|||
if(m_cache_in_buffer.size() < m_current_head.m_cb)
|
||||
{
|
||||
is_continue = false;
|
||||
if(cb >= MIN_BYTES_WANTED && !m_invoke_response_handlers.empty())
|
||||
if(cb >= MIN_BYTES_WANTED)
|
||||
{
|
||||
//async call scenario
|
||||
boost::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front();
|
||||
response_handler->reset_timer();
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET partial msg received. len=" << cb);
|
||||
CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock);
|
||||
if (!m_invoke_response_handlers.empty())
|
||||
{
|
||||
//async call scenario
|
||||
boost::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front();
|
||||
response_handler->reset_timer();
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET partial msg received. len=" << cb);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -519,7 +532,7 @@ public:
|
|||
}
|
||||
|
||||
template<class callback_t>
|
||||
bool async_invoke(int command, const std::string& in_buff, callback_t cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
|
||||
bool async_invoke(int command, const std::string& in_buff, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
|
||||
{
|
||||
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
|
||||
boost::bind(&async_protocol_handler::finish_outer_call, this));
|
||||
|
@ -721,32 +734,50 @@ void async_protocol_handler_config<t_connection_context>::del_connection(async_p
|
|||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
void async_protocol_handler_config<t_connection_context>::delete_connections(size_t count, bool incoming)
|
||||
{
|
||||
std::vector <boost::uuids::uuid> connections;
|
||||
CRITICAL_REGION_BEGIN(m_connects_lock);
|
||||
for (auto& c: m_connects)
|
||||
{
|
||||
if (c.second->m_connection_context.m_is_income == incoming)
|
||||
connections.push_back(c.first);
|
||||
}
|
||||
|
||||
// close random connections from the provided set
|
||||
// TODO or better just keep removing random elements (performance)
|
||||
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
shuffle(connections.begin(), connections.end(), std::default_random_engine(seed));
|
||||
while (count > 0 && connections.size() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto i = connections.end() - 1;
|
||||
async_protocol_handler<t_connection_context> *conn = m_connects.at(*i);
|
||||
del_connection(conn);
|
||||
close(*i);
|
||||
connections.erase(i);
|
||||
}
|
||||
catch (const std::out_of_range &e)
|
||||
{
|
||||
MWARNING("Connection not found in m_connects, continuing");
|
||||
}
|
||||
--count;
|
||||
}
|
||||
|
||||
CRITICAL_REGION_END();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
void async_protocol_handler_config<t_connection_context>::del_out_connections(size_t count)
|
||||
{
|
||||
std::vector <boost::uuids::uuid> out_connections;
|
||||
CRITICAL_REGION_BEGIN(m_connects_lock);
|
||||
for (auto& c: m_connects)
|
||||
{
|
||||
if (!c.second->m_connection_context.m_is_income)
|
||||
out_connections.push_back(c.first);
|
||||
}
|
||||
|
||||
if (out_connections.size() == 0)
|
||||
return;
|
||||
|
||||
// close random out connections
|
||||
// TODO or better just keep removing random elements (performance)
|
||||
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
shuffle(out_connections.begin(), out_connections.end(), std::default_random_engine(seed));
|
||||
while (count > 0 && out_connections.size() > 0)
|
||||
{
|
||||
close(*out_connections.begin());
|
||||
del_connection(m_connects.at(*out_connections.begin()));
|
||||
out_connections.erase(out_connections.begin());
|
||||
--count;
|
||||
}
|
||||
|
||||
CRITICAL_REGION_END();
|
||||
delete_connections(count, false);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
void async_protocol_handler_config<t_connection_context>::del_in_connections(size_t count)
|
||||
{
|
||||
delete_connections(count, true);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
|
@ -786,7 +817,7 @@ int async_protocol_handler_config<t_connection_context>::invoke(int command, con
|
|||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context> template<class callback_t>
|
||||
int async_protocol_handler_config<t_connection_context>::invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, callback_t cb, size_t timeout)
|
||||
int async_protocol_handler_config<t_connection_context>::invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout)
|
||||
{
|
||||
async_protocol_handler<t_connection_context>* aph;
|
||||
int r = find_and_lock_connection(connection_id, aph);
|
||||
|
@ -794,7 +825,7 @@ int async_protocol_handler_config<t_connection_context>::invoke_async(int comman
|
|||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context> template<class callback_t>
|
||||
bool async_protocol_handler_config<t_connection_context>::foreach_connection(callback_t cb)
|
||||
bool async_protocol_handler_config<t_connection_context>::foreach_connection(const callback_t &cb)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_connects_lock);
|
||||
for(auto& c: m_connects)
|
||||
|
@ -807,7 +838,7 @@ bool async_protocol_handler_config<t_connection_context>::foreach_connection(cal
|
|||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context> template<class callback_t>
|
||||
bool async_protocol_handler_config<t_connection_context>::for_connection(const boost::uuids::uuid &connection_id, callback_t cb)
|
||||
bool async_protocol_handler_config<t_connection_context>::for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_connects_lock);
|
||||
async_protocol_handler<t_connection_context>* aph = find_connection(connection_id);
|
||||
|
@ -826,6 +857,15 @@ size_t async_protocol_handler_config<t_connection_context>::get_connections_coun
|
|||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
void async_protocol_handler_config<t_connection_context>::set_handler(levin_commands_handler<t_connection_context>* handler, void (*destroy)(levin_commands_handler<t_connection_context>*))
|
||||
{
|
||||
if (m_pcommands_handler && m_pcommands_handler_destroy)
|
||||
(*m_pcommands_handler_destroy)(m_pcommands_handler);
|
||||
m_pcommands_handler = handler;
|
||||
m_pcommands_handler_destroy = destroy;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
int async_protocol_handler_config<t_connection_context>::notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id)
|
||||
{
|
||||
async_protocol_handler<t_connection_context>* aph;
|
||||
|
|
|
@ -31,21 +31,16 @@
|
|||
|
||||
//#include <Winsock2.h>
|
||||
//#include <Ws2tcpip.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/preprocessor/selection/min.hpp>
|
||||
#include <boost/lambda/bind.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include "net/net_utils_base.h"
|
||||
#include "misc_language.h"
|
||||
//#include "profile_tools.h"
|
||||
#include "../string_tools.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
@ -85,11 +80,13 @@ namespace net_utils
|
|||
|
||||
public:
|
||||
inline
|
||||
blocked_mode_client():m_socket(m_io_service),
|
||||
m_initialized(false),
|
||||
blocked_mode_client():m_initialized(false),
|
||||
m_connected(false),
|
||||
m_deadline(m_io_service),
|
||||
m_shutdowned(0)
|
||||
m_shutdowned(0),
|
||||
m_ssl(false),
|
||||
m_ctx(boost::asio::ssl::context::sslv23),
|
||||
m_ssl_socket(m_io_service,m_ctx)
|
||||
{
|
||||
|
||||
|
||||
|
@ -113,18 +110,25 @@ namespace net_utils
|
|||
}
|
||||
|
||||
inline
|
||||
bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
|
||||
{
|
||||
return connect(addr, std::to_string(port), timeout, bind_ip);
|
||||
return connect(addr, std::to_string(port), timeout, ssl, bind_ip);
|
||||
}
|
||||
|
||||
inline
|
||||
bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
|
||||
{
|
||||
m_connected = false;
|
||||
m_ssl = ssl;
|
||||
try
|
||||
{
|
||||
m_socket.close();
|
||||
m_ssl_socket.next_layer().close();
|
||||
|
||||
// Set SSL options
|
||||
// disable sslv2
|
||||
m_ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
|
||||
m_ctx.set_default_verify_paths();
|
||||
|
||||
// Get a list of endpoints corresponding to the server name.
|
||||
|
||||
|
||||
|
@ -147,11 +151,11 @@ namespace net_utils
|
|||
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
|
||||
|
||||
|
||||
m_socket.open(remote_endpoint.protocol());
|
||||
m_ssl_socket.next_layer().open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0);
|
||||
m_socket.bind(local_endpoint);
|
||||
m_ssl_socket.next_layer().bind(local_endpoint);
|
||||
}
|
||||
|
||||
|
||||
|
@ -160,17 +164,24 @@ namespace net_utils
|
|||
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
|
||||
//m_socket.connect(remote_endpoint);
|
||||
m_socket.async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
|
||||
m_ssl_socket.next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.run_one();
|
||||
}
|
||||
|
||||
if (!ec && m_socket.is_open())
|
||||
if (!ec && m_ssl_socket.next_layer().is_open())
|
||||
{
|
||||
m_connected = true;
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
// SSL Options
|
||||
if(m_ssl) {
|
||||
// Disable verification of host certificate
|
||||
m_ssl_socket.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
// Handshake
|
||||
m_ssl_socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
m_ssl_socket.handshake(boost::asio::ssl::stream_base::client);
|
||||
}
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
|
@ -193,7 +204,6 @@ namespace net_utils
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
bool disconnect()
|
||||
{
|
||||
|
@ -202,8 +212,9 @@ namespace net_utils
|
|||
if(m_connected)
|
||||
{
|
||||
m_connected = false;
|
||||
m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
|
||||
if(m_ssl)
|
||||
shutdown_ssl();
|
||||
m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +251,7 @@ namespace net_utils
|
|||
// object is used as a callback and will update the ec variable when the
|
||||
// operation completes. The blocking_udp_client.cpp example shows how you
|
||||
// can use boost::bind rather than boost::lambda.
|
||||
boost::asio::async_write(m_socket, boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
async_write(buff.c_str(), buff.size(), ec);
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
while (ec == boost::asio::error::would_block)
|
||||
|
@ -302,9 +313,7 @@ namespace net_utils
|
|||
*/
|
||||
boost::system::error_code ec;
|
||||
|
||||
size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
|
||||
|
||||
|
||||
size_t writen = write(data, sz, ec);
|
||||
|
||||
if (!writen || ec)
|
||||
{
|
||||
|
@ -334,10 +343,7 @@ namespace net_utils
|
|||
|
||||
bool is_connected()
|
||||
{
|
||||
return m_connected && m_socket.is_open();
|
||||
//TRY_ENTRY()
|
||||
//return m_socket.is_open();
|
||||
//CATCH_ENTRY_L0("is_connected", false)
|
||||
return m_connected && m_ssl_socket.next_layer().is_open();
|
||||
}
|
||||
|
||||
inline
|
||||
|
@ -369,8 +375,8 @@ namespace net_utils
|
|||
handler_obj hndlr(ec, bytes_transfered);
|
||||
|
||||
char local_buff[10000] = {0};
|
||||
//m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr);
|
||||
boost::asio::async_read(m_socket, boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr);
|
||||
|
||||
async_read(local_buff, sizeof(local_buff), boost::asio::transfer_at_least(1), hndlr);
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
|
||||
|
@ -451,10 +457,8 @@ namespace net_utils
|
|||
|
||||
|
||||
handler_obj hndlr(ec, bytes_transfered);
|
||||
|
||||
//char local_buff[10000] = {0};
|
||||
boost::asio::async_read(m_socket, boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr);
|
||||
|
||||
async_read((char*)buff.data(), buff.size(), boost::asio::transfer_at_least(buff.size()), hndlr);
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
|
||||
{
|
||||
|
@ -500,10 +504,18 @@ namespace net_utils
|
|||
bool shutdown()
|
||||
{
|
||||
m_deadline.cancel();
|
||||
boost::system::error_code ignored_ec;
|
||||
m_socket.cancel(ignored_ec);
|
||||
m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
m_socket.close(ignored_ec);
|
||||
boost::system::error_code ec;
|
||||
if(m_ssl)
|
||||
shutdown_ssl();
|
||||
m_ssl_socket.next_layer().cancel(ec);
|
||||
if(ec)
|
||||
MDEBUG("Problems at cancel: " << ec.message());
|
||||
m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
|
||||
if(ec)
|
||||
MDEBUG("Problems at shutdown: " << ec.message());
|
||||
m_ssl_socket.next_layer().close(ec);
|
||||
if(ec)
|
||||
MDEBUG("Problems at close: " << ec.message());
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1);
|
||||
m_connected = false;
|
||||
return true;
|
||||
|
@ -520,7 +532,7 @@ namespace net_utils
|
|||
|
||||
boost::asio::ip::tcp::socket& get_socket()
|
||||
{
|
||||
return m_socket;
|
||||
return m_ssl_socket.next_layer();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -537,7 +549,7 @@ namespace net_utils
|
|||
// connect(), read_line() or write_line() functions to return.
|
||||
LOG_PRINT_L3("Timed out socket");
|
||||
m_connected = false;
|
||||
m_socket.close();
|
||||
m_ssl_socket.next_layer().close();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
|
@ -547,12 +559,61 @@ namespace net_utils
|
|||
// Put the actor back to sleep.
|
||||
m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this));
|
||||
}
|
||||
|
||||
|
||||
void shutdown_ssl() {
|
||||
// ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
m_deadline.expires_from_now(std::chrono::milliseconds(2000));
|
||||
m_ssl_socket.async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.run_one();
|
||||
}
|
||||
// Ignore "short read" error
|
||||
if (ec.category() == boost::asio::error::get_ssl_category() &&
|
||||
ec.value() !=
|
||||
#if BOOST_VERSION >= 106200
|
||||
boost::asio::ssl::error::stream_truncated
|
||||
#else // older Boost supports only OpenSSL 1.0, so 1.0-only macros are appropriate
|
||||
ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)
|
||||
#endif
|
||||
)
|
||||
MDEBUG("Problems at ssl shutdown: " << ec.message());
|
||||
}
|
||||
|
||||
protected:
|
||||
bool write(const void* data, size_t sz, boost::system::error_code& ec)
|
||||
{
|
||||
bool success;
|
||||
if(m_ssl)
|
||||
success = boost::asio::write(m_ssl_socket, boost::asio::buffer(data, sz), ec);
|
||||
else
|
||||
success = boost::asio::write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), ec);
|
||||
return success;
|
||||
}
|
||||
|
||||
void async_write(const void* data, size_t sz, boost::system::error_code& ec)
|
||||
{
|
||||
if(m_ssl)
|
||||
boost::asio::async_write(m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
else
|
||||
boost::asio::async_write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
}
|
||||
|
||||
void async_read(char* buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj& hndlr)
|
||||
{
|
||||
if(!m_ssl)
|
||||
boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
|
||||
else
|
||||
boost::asio::async_read(m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::ip::tcp::socket m_socket;
|
||||
boost::asio::ssl::context m_ctx;
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_ssl_socket;
|
||||
bool m_ssl;
|
||||
bool m_initialized;
|
||||
bool m_connected;
|
||||
boost::asio::steady_timer m_deadline;
|
||||
|
@ -618,8 +679,8 @@ namespace net_utils
|
|||
|
||||
boost::system::error_code ec;
|
||||
|
||||
size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
|
||||
|
||||
size_t writen = write(data, sz, ec);
|
||||
|
||||
if (!writen || ec)
|
||||
{
|
||||
LOG_PRINT_L3("Problems at write: " << ec.message());
|
||||
|
@ -660,7 +721,7 @@ namespace net_utils
|
|||
// asynchronous operations are cancelled. This allows the blocked
|
||||
// connect(), read_line() or write_line() functions to return.
|
||||
LOG_PRINT_L3("Timed out socket");
|
||||
m_socket.close();
|
||||
m_ssl_socket.next_layer().close();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace net_utils
|
|||
STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal);
|
||||
|
||||
boost::smatch result;
|
||||
if(!boost::regex_search(uri, result, rexp_match_uri, boost::match_default) && result[0].matched)
|
||||
if(!(boost::regex_search(uri, result, rexp_match_uri, boost::match_default) && result[0].matched))
|
||||
{
|
||||
LOG_PRINT_L1("[PARSE URI] regex not matched for uri: " << uri);
|
||||
content.m_path = uri;
|
||||
|
@ -139,7 +139,7 @@ namespace net_utils
|
|||
// 12 34 5 6 7
|
||||
content.port = 0;
|
||||
boost::smatch result;
|
||||
if(!boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched)
|
||||
if(!(boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched))
|
||||
{
|
||||
LOG_PRINT_L1("[PARSE URI] regex not matched for uri: " << rexp_match_uri);
|
||||
//content.m_path = uri;
|
||||
|
|
|
@ -29,12 +29,11 @@
|
|||
#ifndef _NET_UTILS_BASE_H_
|
||||
#define _NET_UTILS_BASE_H_
|
||||
|
||||
#include <typeinfo>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "net/local_ip.h"
|
||||
#include "string_tools.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
|
@ -44,108 +43,176 @@
|
|||
#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
|
||||
#endif
|
||||
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
struct network_address_base
|
||||
class ipv4_network_address
|
||||
{
|
||||
public:
|
||||
bool operator==(const network_address_base &other) const { return m_full_id == other.m_full_id; }
|
||||
bool operator!=(const network_address_base &other) const { return !operator==(other); }
|
||||
bool operator<(const network_address_base &other) const { return m_full_id < other.m_full_id; }
|
||||
bool is_same_host(const network_address_base &other) const { return m_host_id == other.m_host_id; }
|
||||
virtual std::string str() const = 0;
|
||||
virtual std::string host_str() const = 0;
|
||||
virtual bool is_loopback() const = 0;
|
||||
virtual bool is_local() const = 0;
|
||||
virtual uint8_t get_type_id() const = 0;
|
||||
protected:
|
||||
// A very simple non cryptographic hash function by Fowler, Noll, Vo
|
||||
uint64_t fnv1a(const uint8_t *data, size_t len) const {
|
||||
uint64_t h = 0xcbf29ce484222325;
|
||||
while (len--)
|
||||
h = (h ^ *data++) * 0x100000001b3;
|
||||
return h;
|
||||
}
|
||||
uint64_t m_host_id;
|
||||
uint64_t m_full_id;
|
||||
};
|
||||
struct ipv4_network_address: public network_address_base
|
||||
{
|
||||
void init_ids()
|
||||
{
|
||||
m_host_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip));
|
||||
m_full_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip) + sizeof(m_port));
|
||||
}
|
||||
public:
|
||||
ipv4_network_address(uint32_t ip, uint16_t port): network_address_base(), m_ip(ip), m_port(port) { init_ids(); }
|
||||
uint32_t ip() const { return m_ip; }
|
||||
uint16_t port() const { return m_port; }
|
||||
virtual std::string str() const { return epee::string_tools::get_ip_string_from_int32(m_ip) + ":" + std::to_string(m_port); }
|
||||
virtual std::string host_str() const { return epee::string_tools::get_ip_string_from_int32(m_ip); }
|
||||
virtual bool is_loopback() const { return epee::net_utils::is_ip_loopback(m_ip); }
|
||||
virtual bool is_local() const { return epee::net_utils::is_ip_local(m_ip); }
|
||||
virtual uint8_t get_type_id() const { return ID; }
|
||||
public: // serialization
|
||||
static const uint8_t ID = 1;
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
uint32_t m_ip;
|
||||
uint16_t m_port;
|
||||
#pragma pack(pop)
|
||||
|
||||
public:
|
||||
constexpr ipv4_network_address(uint32_t ip, uint16_t port) noexcept
|
||||
: m_ip(ip), m_port(port) {}
|
||||
|
||||
bool equal(const ipv4_network_address& other) const noexcept;
|
||||
bool less(const ipv4_network_address& other) const noexcept;
|
||||
constexpr bool is_same_host(const ipv4_network_address& other) const noexcept
|
||||
{ return ip() == other.ip(); }
|
||||
|
||||
constexpr uint32_t ip() const noexcept { return m_ip; }
|
||||
constexpr uint16_t port() const noexcept { return m_port; }
|
||||
std::string str() const;
|
||||
std::string host_str() const;
|
||||
bool is_loopback() const;
|
||||
bool is_local() const;
|
||||
static constexpr uint8_t get_type_id() noexcept { return ID; }
|
||||
|
||||
static const uint8_t ID = 1;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_ip)
|
||||
KV_SERIALIZE(m_port)
|
||||
if (!is_store)
|
||||
const_cast<ipv4_network_address&>(this_ref).init_ids();
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
class network_address: public boost::shared_ptr<network_address_base>
|
||||
|
||||
inline bool operator==(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
||||
{ return lhs.equal(rhs); }
|
||||
inline bool operator!=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
||||
{ return !lhs.equal(rhs); }
|
||||
inline bool operator<(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
||||
{ return lhs.less(rhs); }
|
||||
inline bool operator<=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
||||
{ return !rhs.less(lhs); }
|
||||
inline bool operator>(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
||||
{ return rhs.less(lhs); }
|
||||
inline bool operator>=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
||||
{ return !lhs.less(rhs); }
|
||||
|
||||
class network_address
|
||||
{
|
||||
struct interface
|
||||
{
|
||||
virtual ~interface() {};
|
||||
|
||||
virtual bool equal(const interface&) const = 0;
|
||||
virtual bool less(const interface&) const = 0;
|
||||
virtual bool is_same_host(const interface&) const = 0;
|
||||
|
||||
virtual std::string str() const = 0;
|
||||
virtual std::string host_str() const = 0;
|
||||
virtual bool is_loopback() const = 0;
|
||||
virtual bool is_local() const = 0;
|
||||
virtual uint8_t get_type_id() const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct implementation final : interface
|
||||
{
|
||||
T value;
|
||||
|
||||
implementation(const T& src) : value(src) {}
|
||||
~implementation() = default;
|
||||
|
||||
// Type-checks for cast are done in cpp
|
||||
static const T& cast(const interface& src) noexcept
|
||||
{ return static_cast<const implementation<T>&>(src).value; }
|
||||
|
||||
virtual bool equal(const interface& other) const override
|
||||
{ return value.equal(cast(other)); }
|
||||
|
||||
virtual bool less(const interface& other) const override
|
||||
{ return value.less(cast(other)); }
|
||||
|
||||
virtual bool is_same_host(const interface& other) const override
|
||||
{ return value.is_same_host(cast(other)); }
|
||||
|
||||
virtual std::string str() const override { return value.str(); }
|
||||
virtual std::string host_str() const override { return value.host_str(); }
|
||||
virtual bool is_loopback() const override { return value.is_loopback(); }
|
||||
virtual bool is_local() const override { return value.is_local(); }
|
||||
virtual uint8_t get_type_id() const override { return value.get_type_id(); }
|
||||
};
|
||||
|
||||
std::shared_ptr<interface> self;
|
||||
|
||||
template<typename Type>
|
||||
Type& as_mutable() const
|
||||
{
|
||||
// types `implmentation<Type>` and `implementation<const Type>` are unique
|
||||
using Type_ = typename std::remove_const<Type>::type;
|
||||
network_address::interface* const self_ = self.get(); // avoid clang warning in typeid
|
||||
if (!self_ || typeid(implementation<Type_>) != typeid(*self_))
|
||||
throw std::bad_cast{};
|
||||
return static_cast<implementation<Type_>*>(self_)->value;
|
||||
}
|
||||
public:
|
||||
network_address() {}
|
||||
network_address(ipv4_network_address *address): boost::shared_ptr<network_address_base>(address) {}
|
||||
bool operator==(const network_address &other) const { return (*this)->operator==(*other); }
|
||||
bool operator!=(const network_address &other) const { return (*this)->operator!=(*other); }
|
||||
bool operator<(const network_address &other) const { return (*this)->operator<(*other); }
|
||||
bool is_same_host(const network_address &other) const { return (*this)->is_same_host(*other); }
|
||||
std::string str() const { return (*this) ? (*this)->str() : "<none>"; }
|
||||
std::string host_str() const { return (*this) ? (*this)->host_str() : "<none>"; }
|
||||
bool is_loopback() const { return (*this)->is_loopback(); }
|
||||
bool is_local() const { return (*this)->is_local(); }
|
||||
uint8_t get_type_id() const { return (*this)->get_type_id(); }
|
||||
template<typename Type> Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); }
|
||||
template<typename Type> const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); }
|
||||
network_address() : self(nullptr) {}
|
||||
template<typename T>
|
||||
network_address(const T& src)
|
||||
: self(std::make_shared<implementation<T>>(src)) {}
|
||||
bool equal(const network_address &other) const;
|
||||
bool less(const network_address &other) const;
|
||||
bool is_same_host(const network_address &other) const;
|
||||
std::string str() const { return self ? self->str() : "<none>"; }
|
||||
std::string host_str() const { return self ? self->host_str() : "<none>"; }
|
||||
bool is_loopback() const { return self ? self->is_loopback() : false; }
|
||||
bool is_local() const { return self ? self->is_local() : false; }
|
||||
uint8_t get_type_id() const { return self ? self->get_type_id() : 0; }
|
||||
template<typename Type> const Type &as() const { return as_mutable<const Type>(); }
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
uint8_t type = is_store ? this_ref.get_type_id() : 0;
|
||||
epee::serialization::selector<is_store>::serialize(type, stg, hparent_section, "type");
|
||||
if (!epee::serialization::selector<is_store>::serialize(type, stg, hparent_section, "type"))
|
||||
return false;
|
||||
switch (type)
|
||||
{
|
||||
case ipv4_network_address::ID:
|
||||
{
|
||||
if (!is_store)
|
||||
const_cast<network_address&>(this_ref).reset(new ipv4_network_address(0, 0));
|
||||
KV_SERIALIZE(template as<ipv4_network_address>());
|
||||
{
|
||||
const_cast<network_address&>(this_ref) = ipv4_network_address{0, 0};
|
||||
auto &addr = this_ref.template as_mutable<ipv4_network_address>();
|
||||
if (epee::serialization::selector<is_store>::serialize(addr, stg, hparent_section, "addr"))
|
||||
MDEBUG("Found as addr: " << this_ref.str());
|
||||
else if (epee::serialization::selector<is_store>::serialize(addr, stg, hparent_section, "template as<ipv4_network_address>()"))
|
||||
MDEBUG("Found as template as<ipv4_network_address>(): " << this_ref.str());
|
||||
else if (epee::serialization::selector<is_store>::serialize(addr, stg, hparent_section, "template as_mutable<ipv4_network_address>()"))
|
||||
MDEBUG("Found as template as_mutable<ipv4_network_address>(): " << this_ref.str());
|
||||
else
|
||||
{
|
||||
MWARNING("Address not found");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &addr = this_ref.template as_mutable<ipv4_network_address>();
|
||||
if (!epee::serialization::selector<is_store>::serialize(addr, stg, hparent_section, "addr"))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default: MERROR("Unsupported network address type: " << type); return false;
|
||||
}
|
||||
default: MERROR("Unsupported network address type: " << (unsigned)type); return false;
|
||||
}
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0)
|
||||
{
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
if (epee::string_tools::parse_peer_from_string(ip, port, string))
|
||||
{
|
||||
if (default_port && !port)
|
||||
port = default_port;
|
||||
address.reset(new ipv4_network_address(ip, port));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator==(const network_address& lhs, const network_address& rhs)
|
||||
{ return lhs.equal(rhs); }
|
||||
inline bool operator!=(const network_address& lhs, const network_address& rhs)
|
||||
{ return !lhs.equal(rhs); }
|
||||
inline bool operator<(const network_address& lhs, const network_address& rhs)
|
||||
{ return lhs.less(rhs); }
|
||||
inline bool operator<=(const network_address& lhs, const network_address& rhs)
|
||||
{ return !rhs.less(lhs); }
|
||||
inline bool operator>(const network_address& lhs, const network_address& rhs)
|
||||
{ return rhs.less(lhs); }
|
||||
inline bool operator>=(const network_address& lhs, const network_address& rhs)
|
||||
{ return !lhs.less(rhs); }
|
||||
|
||||
bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0);
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
@ -179,7 +246,7 @@ namespace net_utils
|
|||
{}
|
||||
|
||||
connection_context_base(): m_connection_id(),
|
||||
m_remote_address(new ipv4_network_address(0,0)),
|
||||
m_remote_address(ipv4_network_address{0,0}),
|
||||
m_is_income(false),
|
||||
m_started(time(NULL)),
|
||||
m_last_recv(0),
|
||||
|
@ -228,21 +295,8 @@ namespace net_utils
|
|||
//some helpers
|
||||
|
||||
|
||||
inline
|
||||
std::string print_connection_context(const connection_context_base& ctx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << ctx.m_remote_address->str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline
|
||||
std::string print_connection_context_short(const connection_context_base& ctx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << ctx.m_remote_address->str() << (ctx.m_is_income ? " INC":" OUT");
|
||||
return ss.str();
|
||||
}
|
||||
std::string print_connection_context(const connection_context_base& ctx);
|
||||
std::string print_connection_context_short(const connection_context_base& ctx);
|
||||
|
||||
inline MAKE_LOGGABLE(connection_context_base, ct, os)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/// @file
|
||||
/// @author rfree (current maintainer in monero.cc project)
|
||||
/// @brief implementaion for throttling of connection (count and rate-limit speed etc)
|
||||
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/* rfree: throttle details, implementing rate limiting */
|
||||
|
||||
|
||||
#ifndef INCLUDED_throttle_detail_hpp
|
||||
#define INCLUDED_throttle_detail_hpp
|
||||
|
||||
#include "network_throttle.hpp"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
|
||||
|
||||
class network_throttle : public i_network_throttle {
|
||||
private:
|
||||
struct packet_info {
|
||||
size_t m_size; // octets sent. Summary for given small-window (e.g. for all packaged in 1 second)
|
||||
packet_info();
|
||||
};
|
||||
|
||||
|
||||
network_speed_bps m_target_speed;
|
||||
size_t m_network_add_cost; // estimated add cost of headers
|
||||
size_t m_network_minimal_segment; // estimated minimal cost of sending 1 byte to round up to
|
||||
size_t m_network_max_segment; // recommended max size of 1 TCP transmission
|
||||
|
||||
const size_t m_window_size; // the number of samples to average over
|
||||
network_time_seconds m_slot_size; // the size of one slot. TODO: now hardcoded for 1 second e.g. in time_to_slot()
|
||||
// TODO for big window size, for performance better the substract on change of m_last_sample_time instead of recalculating average of eg >100 elements
|
||||
|
||||
std::vector< packet_info > m_history; // the history of bw usage
|
||||
network_time_seconds m_last_sample_time; // time of last history[0] - so we know when to rotate the buffer
|
||||
network_time_seconds m_start_time; // when we were created
|
||||
bool m_any_packet_yet; // did we yet got any packet to count
|
||||
|
||||
std::string m_name; // my name for debug and logs
|
||||
std::string m_nameshort; // my name for debug and logs (used in log file name)
|
||||
|
||||
// each sample is now 1 second
|
||||
public:
|
||||
network_throttle(const std::string &nameshort, const std::string &name, int window_size=-1);
|
||||
virtual ~network_throttle();
|
||||
virtual void set_name(const std::string &name);
|
||||
virtual void set_target_speed( network_speed_kbps target );
|
||||
virtual network_speed_kbps get_target_speed();
|
||||
|
||||
// add information about events:
|
||||
virtual void handle_trafic_exact(size_t packet_size); ///< count the new traffic/packet; the size is exact considering all network costs
|
||||
virtual void handle_trafic_tcp(size_t packet_size); ///< count the new traffic/packet; the size is as TCP, we will consider MTU etc
|
||||
|
||||
virtual void tick(); ///< poke and update timers/history (recalculates, moves the history if needed, checks the real clock etc)
|
||||
|
||||
virtual double get_time_seconds() const ; ///< timer that we use, time in seconds, monotionic
|
||||
|
||||
// time calculations:
|
||||
virtual void calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const; ///< MAIN LOGIC (see base class for info)
|
||||
|
||||
virtual network_time_seconds get_sleep_time_after_tick(size_t packet_size); ///< increase the timer if needed, and get the package size
|
||||
virtual network_time_seconds get_sleep_time(size_t packet_size) const; ///< gets the Delay (recommended Delay time) from calc. (not safe: only if time didnt change?) TODO
|
||||
|
||||
virtual size_t get_recommended_size_of_planned_transport() const; ///< what should be the size (bytes) of next data block to be transported
|
||||
virtual size_t get_recommended_size_of_planned_transport_window(double force_window) const; ///< ditto, but for given windows time frame
|
||||
virtual double get_current_speed() const;
|
||||
|
||||
private:
|
||||
virtual network_time_seconds time_to_slot(network_time_seconds t) const { return std::floor( t ); } // convert exact time eg 13.7 to rounded time for slot number in history 13
|
||||
virtual void _handle_trafic_exact(size_t packet_size, size_t orginal_size);
|
||||
virtual void logger_handle_net(const std::string &filename, double time, size_t size);
|
||||
};
|
||||
|
||||
/***
|
||||
* The complete set of traffic throttle for one typical connection
|
||||
*/
|
||||
struct network_throttle_bw {
|
||||
public:
|
||||
network_throttle m_in; ///< for incomming traffic (this we can not controll directly as it depends of what others send to us - usually)
|
||||
network_throttle m_inreq; ///< for requesting incomming traffic (this is exact usually)
|
||||
network_throttle m_out; ///< for outgoing traffic that we just sent (this is exact usually)
|
||||
|
||||
public:
|
||||
network_throttle_bw(const std::string &name1);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace net_utils
|
||||
} // namespace epee
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/// @file
|
||||
/// @author rfree (current maintainer in monero.cc project)
|
||||
/// @brief interface for throttling of connection (count and rate-limit speed etc)
|
||||
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/* rfree: throttle basic interface */
|
||||
/* rfree: also includes the manager for singeton/global such objects */
|
||||
|
||||
|
||||
#ifndef INCLUDED_network_throttle_hpp
|
||||
#define INCLUDED_network_throttle_hpp
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <atomic>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include "syncobj.h"
|
||||
|
||||
#include "net/net_utils_base.h"
|
||||
#include "misc_log_ex.h"
|
||||
#include <boost/lambda/bind.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include "misc_language.h"
|
||||
#include "pragma_comp_defs.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
|
||||
// just typedefs to in code define the units used. TODO later it will be enforced that casts to other numericals are only explicit to avoid mistakes? use boost::chrono?
|
||||
typedef double network_speed_kbps; // externally, for parameters and return values, all defined in kilobytes per second
|
||||
typedef double network_speed_bps; // throttle-internally, bytes per second
|
||||
typedef double network_time_seconds;
|
||||
typedef double network_MB;
|
||||
|
||||
class i_network_throttle;
|
||||
|
||||
/***
|
||||
@brief All information about given throttle - speed calculations
|
||||
*/
|
||||
struct calculate_times_struct {
|
||||
double average;
|
||||
double window;
|
||||
double delay;
|
||||
double recomendetDataSize;
|
||||
};
|
||||
typedef calculate_times_struct calculate_times_struct;
|
||||
|
||||
|
||||
/***
|
||||
@brief Access to simple throttles, with singlton to access global network limits
|
||||
*/
|
||||
class network_throttle_manager {
|
||||
// provides global (singleton) in/inreq/out throttle access
|
||||
|
||||
// [[note1]] see also http://www.nuonsoft.com/blog/2012/10/21/implementing-a-thread-safe-singleton-with-c11/
|
||||
// [[note2]] _inreq is the requested in traffic - we anticipate we will get in-bound traffic soon as result of what we do (e.g. that we sent network downloads requests)
|
||||
|
||||
//protected:
|
||||
public: // XXX
|
||||
|
||||
static boost::mutex m_lock_get_global_throttle_in;
|
||||
static boost::mutex m_lock_get_global_throttle_inreq;
|
||||
static boost::mutex m_lock_get_global_throttle_out;
|
||||
|
||||
friend class connection_basic; // FRIEND - to directly access global throttle-s. !! REMEMBER TO USE LOCKS!
|
||||
friend class connection_basic_pimpl; // ditto
|
||||
|
||||
public:
|
||||
static i_network_throttle & get_global_throttle_in(); ///< singleton ; for friend class ; caller MUST use proper locks! like m_lock_get_global_throttle_in
|
||||
static i_network_throttle & get_global_throttle_inreq(); ///< ditto ; use lock ... use m_lock_get_global_throttle_inreq obviously
|
||||
static i_network_throttle & get_global_throttle_out(); ///< ditto ; use lock ... use m_lock_get_global_throttle_out obviously
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***
|
||||
@brief interface for the throttle, see the derivated class
|
||||
*/
|
||||
class i_network_throttle {
|
||||
public:
|
||||
virtual void set_name(const std::string &name)=0;
|
||||
virtual void set_target_speed( network_speed_kbps target )=0;
|
||||
virtual network_speed_kbps get_target_speed()=0;
|
||||
|
||||
virtual void handle_trafic_exact(size_t packet_size) =0; // count the new traffic/packet; the size is exact considering all network costs
|
||||
virtual void handle_trafic_tcp(size_t packet_size) =0; // count the new traffic/packet; the size is as TCP, we will consider MTU etc
|
||||
virtual void tick() =0; // poke and update timers/history
|
||||
|
||||
// time calculations:
|
||||
|
||||
virtual void calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const =0; // assuming sending new package (or 0), calculate:
|
||||
// Average, Window, Delay, Recommended data size ; also gets dbg=debug flag, and forced widnow size if >0 or -1 for not forcing window size
|
||||
|
||||
// Average speed, Window size, recommended Delay to sleep now, Recommended size of data to send now
|
||||
|
||||
virtual network_time_seconds get_sleep_time(size_t packet_size) const =0; // gets the D (recommended Delay time) from calc
|
||||
virtual network_time_seconds get_sleep_time_after_tick(size_t packet_size) =0; // ditto, but first tick the timer
|
||||
|
||||
virtual size_t get_recommended_size_of_planned_transport() const =0; // what should be the recommended limit of data size that we can transport over current network_throttle in near future
|
||||
|
||||
virtual double get_time_seconds() const =0; // a timer
|
||||
virtual void logger_handle_net(const std::string &filename, double time, size_t size)=0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
// ... more in the -advanced.h file
|
||||
|
||||
|
||||
} // namespace net_utils
|
||||
} // namespace epee
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
#ifndef _PROFILE_TOOLS_H_
|
||||
#define _PROFILE_TOOLS_H_
|
||||
|
||||
#include "misc_os_dependent.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
#include <streambuf>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace rdln
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#define _REG_EXP_DEFINER_H_
|
||||
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
|
||||
#include "syncobj.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "misc_log_ex.h"
|
||||
#include "enableable.h"
|
||||
#include "keyvalue_serialization_overloads.h"
|
||||
#include "serialization/serialization.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
|
|
@ -26,6 +26,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/contains_fwd.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
|
@ -73,7 +80,7 @@ namespace epee
|
|||
template<class serializible_type, class t_storage>
|
||||
static bool unserialize_t_obj(serializible_type& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true);
|
||||
typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, false);
|
||||
if(!hchild_section) return false;
|
||||
return obj._load(stg, hchild_section);
|
||||
}
|
||||
|
@ -90,7 +97,7 @@ namespace epee
|
|||
static bool unserialize_t_obj(enableable<serializible_type>& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
obj.enabled = false;
|
||||
typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true);
|
||||
typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, false);
|
||||
if(!hchild_section) return false;
|
||||
obj.enabled = true;
|
||||
return obj.v._load(stg, hchild_section);
|
||||
|
@ -117,9 +124,9 @@ namespace epee
|
|||
typename stl_container::value_type exchange_val;
|
||||
typename t_storage::harray hval_array = stg.get_first_value(pname, exchange_val, hparent_section);
|
||||
if(!hval_array) return false;
|
||||
container.push_back(std::move(exchange_val));
|
||||
container.insert(container.end(), std::move(exchange_val));
|
||||
while(stg.get_next_value(hval_array, exchange_val))
|
||||
container.push_back(std::move(exchange_val));
|
||||
container.insert(container.end(), std::move(exchange_val));
|
||||
return true;
|
||||
}//--------------------------------------------------------------------------------------------------------------------
|
||||
template<class stl_container, class t_storage>
|
||||
|
@ -152,7 +159,7 @@ namespace epee
|
|||
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type));
|
||||
size_t count = (loaded_size/sizeof(typename stl_container::value_type));
|
||||
for(size_t i = 0; i < count; i++)
|
||||
container.push_back(*(pelem++));
|
||||
container.insert(container.end(), *(pelem++));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -186,12 +193,12 @@ namespace epee
|
|||
typename t_storage::harray hsec_array = stg.get_first_section(pname, hchild_section, hparent_section);
|
||||
if(!hsec_array || !hchild_section) return false;
|
||||
res = val._load(stg, hchild_section);
|
||||
container.push_back(val);
|
||||
container.insert(container.end(), val);
|
||||
while(stg.get_next_section(hsec_array, hchild_section))
|
||||
{
|
||||
typename stl_container::value_type val_l = typename stl_container::value_type();
|
||||
res |= val_l._load(stg, hchild_section);
|
||||
container.push_back(std::move(val_l));
|
||||
container.insert(container.end(), std::move(val_l));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -227,6 +234,18 @@ namespace epee
|
|||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_serialize(const std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return serialize_stl_container_t_val(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return serialize_stl_container_t_val(d, stg, hparent_section, pname);
|
||||
|
@ -238,6 +257,18 @@ namespace epee
|
|||
return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return serialize_stl_container_t_val(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
};
|
||||
template<>
|
||||
struct kv_serialization_overloads_impl_is_base_serializable_types<false>
|
||||
|
@ -268,6 +299,18 @@ namespace epee
|
|||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_serialize(const std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
|
||||
|
@ -278,6 +321,18 @@ namespace epee
|
|||
{
|
||||
return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
|
||||
}
|
||||
};
|
||||
template<class t_storage>
|
||||
struct base_serializable_types: public boost::mpl::vector<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, typename t_storage::meta_entry>::type
|
||||
|
@ -353,6 +408,18 @@ namespace epee
|
|||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_serialize(const std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
|
||||
|
@ -363,5 +430,17 @@ namespace epee
|
|||
{
|
||||
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2017, The Monero Project
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -108,7 +108,7 @@ namespace epee
|
|||
template<typename T>
|
||||
constexpr bool has_padding() noexcept
|
||||
{
|
||||
return !std::is_pod<T>() || alignof(T) != 1;
|
||||
return !std::is_standard_layout<T>() || alignof(T) != 1;
|
||||
}
|
||||
|
||||
//! \return Cast data from `src` as `span<const std::uint8_t>`.
|
||||
|
|
|
@ -44,8 +44,11 @@ namespace epee
|
|||
if(!serialization::store_t_to_json(out_struct, req_param))
|
||||
return false;
|
||||
|
||||
http::fields_list additional_params;
|
||||
additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
|
||||
|
||||
const http::http_response_info* pri = NULL;
|
||||
if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri)))
|
||||
if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri), std::move(additional_params)))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri);
|
||||
return false;
|
||||
|
@ -112,7 +115,7 @@ namespace epee
|
|||
}
|
||||
if(resp_t.error.code || resp_t.error.message.size())
|
||||
{
|
||||
LOG_ERROR("RPC call of \"" << method_name << "\" returned error: " << resp_t.error.code << ", message: " << resp_t.error.message);
|
||||
LOG_ERROR("RPC call of \"" << req_t.method << "\" returned error: " << resp_t.error.code << ", message: " << resp_t.error.message);
|
||||
return false;
|
||||
}
|
||||
result_struct = resp_t.result;
|
||||
|
|
|
@ -60,8 +60,7 @@ namespace epee
|
|||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
return false;
|
||||
}
|
||||
result_struct.load(stg_ret);
|
||||
return true;
|
||||
return result_struct.load(stg_ret);
|
||||
}
|
||||
|
||||
template<class t_arg, class t_transport>
|
||||
|
@ -105,13 +104,11 @@ namespace epee
|
|||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
return false;
|
||||
}
|
||||
result_struct.load(stg_ret);
|
||||
|
||||
return true;
|
||||
return result_struct.load(stg_ret);
|
||||
}
|
||||
|
||||
template<class t_result, class t_arg, class callback_t, class t_transport>
|
||||
bool async_invoke_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_transport& transport, callback_t cb, size_t inv_timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
|
||||
bool async_invoke_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_transport& transport, const callback_t &cb, size_t inv_timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
|
||||
{
|
||||
typename serialization::portable_storage stg;
|
||||
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
|
||||
|
@ -133,7 +130,12 @@ namespace epee
|
|||
cb(LEVIN_ERROR_FORMAT, result_struct, context);
|
||||
return false;
|
||||
}
|
||||
result_struct.load(stg_ret);
|
||||
if (!result_struct.load(stg_ret))
|
||||
{
|
||||
LOG_ERROR("Failed to load result struct on command " << command);
|
||||
cb(LEVIN_ERROR_FORMAT, result_struct, context);
|
||||
return false;
|
||||
}
|
||||
cb(code, result_struct, context);
|
||||
return true;
|
||||
}, inv_timeout);
|
||||
|
@ -176,7 +178,11 @@ namespace epee
|
|||
boost::value_initialized<t_in_type> in_struct;
|
||||
boost::value_initialized<t_out_type> out_struct;
|
||||
|
||||
static_cast<t_in_type&>(in_struct).load(strg);
|
||||
if (!static_cast<t_in_type&>(in_struct).load(strg))
|
||||
{
|
||||
LOG_ERROR("Failed to load in_struct in command " << command);
|
||||
return -1;
|
||||
}
|
||||
int res = cb(command, static_cast<t_in_type&>(in_struct), static_cast<t_out_type&>(out_struct), context);
|
||||
serialization::portable_storage strg_out;
|
||||
static_cast<t_out_type&>(out_struct).store(strg_out);
|
||||
|
@ -200,7 +206,11 @@ namespace epee
|
|||
return -1;
|
||||
}
|
||||
boost::value_initialized<t_in_type> in_struct;
|
||||
static_cast<t_in_type&>(in_struct).load(strg);
|
||||
if (!static_cast<t_in_type&>(in_struct).load(strg))
|
||||
{
|
||||
LOG_ERROR("Failed to load in_struct in notify " << command);
|
||||
return -1;
|
||||
}
|
||||
return cb(command, in_struct, context);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
//
|
||||
|
||||
#pragma once
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "parserse_base_utils.h"
|
||||
#include "file_io_utils.h"
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "pragma_comp_defs.h"
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
|
||||
|
@ -47,6 +48,9 @@ namespace epee
|
|||
|
||||
PRAGMA_WARNING_PUSH
|
||||
PRAGMA_GCC("GCC diagnostic ignored \"-Wstrict-aliasing\"")
|
||||
#ifdef __clang__
|
||||
PRAGMA_GCC("GCC diagnostic ignored \"-Wtautological-constant-out-of-range-compare\"")
|
||||
#endif
|
||||
template<class t_stream>
|
||||
size_t pack_varint(t_stream& strm, size_t val)
|
||||
{ //the first two bits always reserved for size information
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "warnings.h"
|
||||
|
@ -131,6 +134,36 @@ POP_WARNINGS
|
|||
}
|
||||
};
|
||||
|
||||
// For MyMonero/OpenMonero backend compatibility
|
||||
// MyMonero backend sends amount, fees and timestamp values as strings.
|
||||
// Until MM backend is updated, this is needed for compatibility between OpenMonero and MyMonero.
|
||||
template<>
|
||||
struct convert_to_integral<std::string, uint64_t, false>
|
||||
{
|
||||
static void convert(const std::string& from, uint64_t& to)
|
||||
{
|
||||
MTRACE("Converting std::string to uint64_t. Source: " << from);
|
||||
// String only contains digits
|
||||
if(std::all_of(from.begin(), from.end(), ::isdigit))
|
||||
to = boost::lexical_cast<uint64_t>(from);
|
||||
// MyMonero ISO 8061 timestamp (2017-05-06T16:27:06Z)
|
||||
else if (boost::regex_match (from, boost::regex("\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\dZ")))
|
||||
{
|
||||
// Convert to unix timestamp
|
||||
#ifdef HAVE_STRPTIME
|
||||
struct tm tm;
|
||||
if (strptime(from.c_str(), "%Y-%m-%dT%H:%M:%S", &tm))
|
||||
#else
|
||||
std::tm tm = {};
|
||||
std::istringstream ss(from);
|
||||
if (ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S"))
|
||||
#endif
|
||||
to = std::mktime(&tm);
|
||||
} else
|
||||
ASSERT_AND_THROW_WRONG_CONVERSION();
|
||||
}
|
||||
};
|
||||
|
||||
template<class from_type, class to_type>
|
||||
struct is_convertable: std::integral_constant<bool,
|
||||
std::is_integral<to_type>::value &&
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <locale>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
@ -42,8 +43,9 @@
|
|||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "hex.h"
|
||||
#include "memwipe.h"
|
||||
#include "span.h"
|
||||
#include "warnings.h"
|
||||
|
||||
|
@ -160,7 +162,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
|
|||
val = boost::lexical_cast<XType>(str_id);
|
||||
return true;
|
||||
}
|
||||
catch(std::exception& /*e*/)
|
||||
catch(const std::exception& /*e*/)
|
||||
{
|
||||
//const char* pmsg = e.what();
|
||||
return false;
|
||||
|
@ -329,7 +331,7 @@ POP_WARNINGS
|
|||
template<class t_pod_type>
|
||||
std::string pod_to_hex(const t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
|
||||
static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type");
|
||||
return to_hex::string(as_byte_span(s));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -349,6 +351,14 @@ POP_WARNINGS
|
|||
s = *(t_pod_type*)bin_buff.data();
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class t_pod_type>
|
||||
bool hex_to_pod(const std::string& hex_str, tools::scrubbed<t_pod_type>& s)
|
||||
{
|
||||
return hex_to_pod(hex_str, unwrap(s));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool validate_hex(uint64_t length, const std::string& str);
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string get_extension(const std::string& str)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class wipeable_string
|
||||
{
|
||||
public:
|
||||
wipeable_string() {}
|
||||
wipeable_string(const wipeable_string &other);
|
||||
wipeable_string(wipeable_string &&other);
|
||||
wipeable_string(const std::string &other);
|
||||
wipeable_string(std::string &&other);
|
||||
wipeable_string(const char *s);
|
||||
~wipeable_string();
|
||||
void wipe();
|
||||
void push_back(char c);
|
||||
void pop_back();
|
||||
const char *data() const noexcept { return buffer.data(); }
|
||||
size_t size() const noexcept { return buffer.size(); }
|
||||
bool empty() const noexcept { return buffer.empty(); }
|
||||
void resize(size_t sz);
|
||||
void reserve(size_t sz);
|
||||
void clear();
|
||||
bool operator==(const wipeable_string &other) const noexcept { return buffer == other.buffer; }
|
||||
bool operator!=(const wipeable_string &other) const noexcept { return buffer != other.buffer; }
|
||||
wipeable_string &operator=(wipeable_string &&other);
|
||||
wipeable_string &operator=(const wipeable_string &other);
|
||||
|
||||
private:
|
||||
void grow(size_t sz, size_t reserved = 0);
|
||||
|
||||
private:
|
||||
std::vector<char> buffer;
|
||||
};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2017, The Monero Project
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file Copyright (c) 2009-2015 The Bitcoin Core developers
|
||||
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EXPLICIT_BZERO
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include "memwipe.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define SCARECROW
|
||||
#else
|
||||
#define SCARECROW \
|
||||
__asm__ __volatile__("" : : "r"(ptr) : "memory");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMSET_S
|
||||
|
||||
void *memwipe(void *ptr, size_t n)
|
||||
{
|
||||
if (memset_s(ptr, n, 0, n))
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
fprintf(stderr, "Error: memset_s failed\n");
|
||||
_exit(1);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
SCARECROW // might as well...
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#elif defined HAVE_EXPLICIT_BZERO
|
||||
|
||||
void *memwipe(void *ptr, size_t n)
|
||||
{
|
||||
explicit_bzero(ptr, n);
|
||||
SCARECROW
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* The memory_cleanse implementation is taken from Bitcoin */
|
||||
|
||||
/* Compilers have a bad habit of removing "superfluous" memset calls that
|
||||
* are trying to zero memory. For example, when memset()ing a buffer and
|
||||
* then free()ing it, the compiler might decide that the memset is
|
||||
* unobservable and thus can be removed.
|
||||
*
|
||||
* Previously we used OpenSSL which tried to stop this by a) implementing
|
||||
* memset in assembly on x86 and b) putting the function in its own file
|
||||
* for other platforms.
|
||||
*
|
||||
* This change removes those tricks in favour of using asm directives to
|
||||
* scare the compiler away. As best as our compiler folks can tell, this is
|
||||
* sufficient and will continue to be so.
|
||||
*
|
||||
* Adam Langley <agl@google.com>
|
||||
* Commit: ad1907fe73334d6c696c8539646c21b11178f20f
|
||||
* BoringSSL (LICENSE: ISC)
|
||||
*/
|
||||
static void memory_cleanse(void *ptr, size_t len)
|
||||
{
|
||||
memset(ptr, 0, len);
|
||||
|
||||
/* As best as we can tell, this is sufficient to break any optimisations that
|
||||
might try to eliminate "superfluous" memsets. If there's an easy way to
|
||||
detect memset_s, it would be better to use that. */
|
||||
SCARECROW
|
||||
}
|
||||
|
||||
void *memwipe(void *ptr, size_t n)
|
||||
{
|
||||
memory_cleanse(ptr, n);
|
||||
SCARECROW
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <string.h>
|
||||
#include "memwipe.h"
|
||||
#include "misc_log_ex.h"
|
||||
#include "wipeable_string.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
wipeable_string::wipeable_string(const wipeable_string &other):
|
||||
buffer(other.buffer)
|
||||
{
|
||||
}
|
||||
|
||||
wipeable_string::wipeable_string(wipeable_string &&other)
|
||||
{
|
||||
if (&other == this)
|
||||
return;
|
||||
buffer = std::move(other.buffer);
|
||||
}
|
||||
|
||||
wipeable_string::wipeable_string(const std::string &other)
|
||||
{
|
||||
grow(other.size());
|
||||
memcpy(buffer.data(), other.c_str(), size());
|
||||
}
|
||||
|
||||
wipeable_string::wipeable_string(std::string &&other)
|
||||
{
|
||||
grow(other.size());
|
||||
memcpy(buffer.data(), other.c_str(), size());
|
||||
if (!other.empty())
|
||||
{
|
||||
memwipe(&other[0], other.size()); // we're kinda left with this again aren't we
|
||||
other = std::string();
|
||||
}
|
||||
}
|
||||
|
||||
wipeable_string::wipeable_string(const char *s)
|
||||
{
|
||||
grow(strlen(s));
|
||||
memcpy(buffer.data(), s, size());
|
||||
}
|
||||
|
||||
wipeable_string::~wipeable_string()
|
||||
{
|
||||
wipe();
|
||||
}
|
||||
|
||||
void wipeable_string::wipe()
|
||||
{
|
||||
if (!buffer.empty())
|
||||
memwipe(buffer.data(), buffer.size() * sizeof(char));
|
||||
}
|
||||
|
||||
void wipeable_string::grow(size_t sz, size_t reserved)
|
||||
{
|
||||
if (reserved < sz)
|
||||
reserved = sz;
|
||||
if (reserved <= buffer.capacity())
|
||||
{
|
||||
if (sz < buffer.size())
|
||||
memwipe(buffer.data() + sz, buffer.size() - sz);
|
||||
buffer.resize(sz);
|
||||
return;
|
||||
}
|
||||
size_t old_sz = buffer.size();
|
||||
std::unique_ptr<char[]> tmp{new char[old_sz]};
|
||||
memcpy(tmp.get(), buffer.data(), old_sz * sizeof(char));
|
||||
if (old_sz > 0)
|
||||
memwipe(buffer.data(), old_sz * sizeof(char));
|
||||
buffer.reserve(reserved);
|
||||
buffer.resize(sz);
|
||||
memcpy(buffer.data(), tmp.get(), old_sz * sizeof(char));
|
||||
if (old_sz > 0)
|
||||
memwipe(tmp.get(), old_sz * sizeof(char));
|
||||
}
|
||||
|
||||
void wipeable_string::push_back(char c)
|
||||
{
|
||||
grow(size() + 1);
|
||||
buffer.back() = c;
|
||||
}
|
||||
|
||||
void wipeable_string::pop_back()
|
||||
{
|
||||
resize(size() - 1);
|
||||
}
|
||||
|
||||
void wipeable_string::resize(size_t sz)
|
||||
{
|
||||
grow(sz);
|
||||
}
|
||||
|
||||
void wipeable_string::reserve(size_t sz)
|
||||
{
|
||||
grow(size(), sz);
|
||||
}
|
||||
|
||||
void wipeable_string::clear()
|
||||
{
|
||||
resize(0);
|
||||
}
|
||||
|
||||
wipeable_string &wipeable_string::operator=(wipeable_string &&other)
|
||||
{
|
||||
if (&other != this)
|
||||
buffer = std::move(other.buffer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
wipeable_string &wipeable_string::operator=(const wipeable_string &other)
|
||||
{
|
||||
if (&other != this)
|
||||
buffer = other.buffer;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
# Copyright (c) 2014-2018, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are
|
||||
# permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
# conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
# of conditions and the following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
set(crypto_sources
|
||||
aesb.c
|
||||
blake256.c
|
||||
chacha.c
|
||||
crypto-ops-data.c
|
||||
crypto-ops.c
|
||||
crypto.cpp
|
||||
groestl.c
|
||||
hash-extra-blake.c
|
||||
hash-extra-groestl.c
|
||||
hash-extra-jh.c
|
||||
hash-extra-skein.c
|
||||
hash.c
|
||||
jh.c
|
||||
keccak.c
|
||||
oaes_lib.c
|
||||
random.c
|
||||
skein.c
|
||||
slow-hash.c
|
||||
tree-hash.c)
|
||||
|
||||
set(crypto_headers)
|
||||
|
||||
set(crypto_private_headers
|
||||
blake256.h
|
||||
chacha.h
|
||||
crypto-ops.h
|
||||
crypto.h
|
||||
generic-ops.h
|
||||
groestl.h
|
||||
groestl_tables.h
|
||||
hash-ops.h
|
||||
hash.h
|
||||
initializer.h
|
||||
jh.h
|
||||
keccak.h
|
||||
oaes_config.h
|
||||
oaes_lib.h
|
||||
random.h
|
||||
skein.h
|
||||
skein_port.h)
|
||||
|
||||
monero_private_headers(cncrypto
|
||||
${crypto_private_headers})
|
||||
monero_add_library(cncrypto
|
||||
${crypto_sources}
|
||||
${crypto_headers}
|
||||
${crypto_private_headers})
|
||||
target_link_libraries(cncrypto
|
||||
PUBLIC
|
||||
epee
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
if (ARM)
|
||||
option(NO_OPTIMIZED_MULTIPLY_ON_ARM
|
||||
"Compute multiply using generic C implementation instead of ARM ASM" OFF)
|
||||
if(NO_OPTIMIZED_MULTIPLY_ON_ARM)
|
||||
message(STATUS "Using generic C implementation for multiply")
|
||||
set_property(SOURCE slow-hash.c
|
||||
PROPERTY COMPILE_DEFINITIONS "NO_OPTIMIZED_MULTIPLY_ON_ARM")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Because of the way Qt works on android with JNI, the code does not live in the main android thread
|
||||
# So this code runs with a 1 MB default stack size.
|
||||
# This will force the use of the heap for the allocation of the scratchpad
|
||||
if (ANDROID OR IOS)
|
||||
if( BUILD_GUI_DEPS )
|
||||
add_definitions(-DFORCE_USE_HEAP=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -157,7 +157,7 @@ void blake256_update(state *S, const uint8_t *data, uint64_t datalen) {
|
|||
int left = S->buflen >> 3;
|
||||
int fill = 64 - left;
|
||||
|
||||
if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) {
|
||||
if (left && (((datalen >> 3)) >= (unsigned) fill)) {
|
||||
memcpy((void *) (S->buf + left), (void *) data, fill);
|
||||
S->t[0] += 512;
|
||||
if (S->t[0] == 0) S->t[1]++;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include "chacha.h"
|
||||
#include "common/int-util.h"
|
||||
#include "warnings.h"
|
||||
|
||||
/*
|
||||
* The following macros are used to obtain exact-width results.
|
||||
*/
|
||||
#define U8V(v) ((uint8_t)(v) & UINT8_C(0xFF))
|
||||
#define U32V(v) ((uint32_t)(v) & UINT32_C(0xFFFFFFFF))
|
||||
|
||||
/*
|
||||
* The following macros load words from an array of bytes with
|
||||
* different types of endianness, and vice versa.
|
||||
*/
|
||||
#define U8TO32_LITTLE(p) SWAP32LE(((uint32_t*)(p))[0])
|
||||
#define U32TO8_LITTLE(p, v) (((uint32_t*)(p))[0] = SWAP32LE(v))
|
||||
|
||||
#define ROTATE(v,c) (rol32(v,c))
|
||||
#define XOR(v,w) ((v) ^ (w))
|
||||
#define PLUS(v,w) (U32V((v) + (w)))
|
||||
#define PLUSONE(v) (PLUS((v),1))
|
||||
|
||||
#define QUARTERROUND(a,b,c,d) \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
||||
|
||||
static const char sigma[] = "expand 32-byte k";
|
||||
|
||||
DISABLE_GCC_AND_CLANG_WARNING(strict-aliasing)
|
||||
|
||||
static void chacha(unsigned rounds, const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher) {
|
||||
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
||||
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||
char* ctarget = 0;
|
||||
char tmp[64];
|
||||
int i;
|
||||
|
||||
if (!length) return;
|
||||
|
||||
j0 = U8TO32_LITTLE(sigma + 0);
|
||||
j1 = U8TO32_LITTLE(sigma + 4);
|
||||
j2 = U8TO32_LITTLE(sigma + 8);
|
||||
j3 = U8TO32_LITTLE(sigma + 12);
|
||||
j4 = U8TO32_LITTLE(key + 0);
|
||||
j5 = U8TO32_LITTLE(key + 4);
|
||||
j6 = U8TO32_LITTLE(key + 8);
|
||||
j7 = U8TO32_LITTLE(key + 12);
|
||||
j8 = U8TO32_LITTLE(key + 16);
|
||||
j9 = U8TO32_LITTLE(key + 20);
|
||||
j10 = U8TO32_LITTLE(key + 24);
|
||||
j11 = U8TO32_LITTLE(key + 28);
|
||||
j12 = 0;
|
||||
j13 = 0;
|
||||
j14 = U8TO32_LITTLE(iv + 0);
|
||||
j15 = U8TO32_LITTLE(iv + 4);
|
||||
|
||||
for (;;) {
|
||||
if (length < 64) {
|
||||
memcpy(tmp, data, length);
|
||||
data = tmp;
|
||||
ctarget = cipher;
|
||||
cipher = tmp;
|
||||
}
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
for (i = rounds;i > 0;i -= 2) {
|
||||
QUARTERROUND( x0, x4, x8,x12)
|
||||
QUARTERROUND( x1, x5, x9,x13)
|
||||
QUARTERROUND( x2, x6,x10,x14)
|
||||
QUARTERROUND( x3, x7,x11,x15)
|
||||
QUARTERROUND( x0, x5,x10,x15)
|
||||
QUARTERROUND( x1, x6,x11,x12)
|
||||
QUARTERROUND( x2, x7, x8,x13)
|
||||
QUARTERROUND( x3, x4, x9,x14)
|
||||
}
|
||||
x0 = PLUS( x0, j0);
|
||||
x1 = PLUS( x1, j1);
|
||||
x2 = PLUS( x2, j2);
|
||||
x3 = PLUS( x3, j3);
|
||||
x4 = PLUS( x4, j4);
|
||||
x5 = PLUS( x5, j5);
|
||||
x6 = PLUS( x6, j6);
|
||||
x7 = PLUS( x7, j7);
|
||||
x8 = PLUS( x8, j8);
|
||||
x9 = PLUS( x9, j9);
|
||||
x10 = PLUS(x10,j10);
|
||||
x11 = PLUS(x11,j11);
|
||||
x12 = PLUS(x12,j12);
|
||||
x13 = PLUS(x13,j13);
|
||||
x14 = PLUS(x14,j14);
|
||||
x15 = PLUS(x15,j15);
|
||||
|
||||
x0 = XOR( x0,U8TO32_LITTLE((uint8_t*)data + 0));
|
||||
x1 = XOR( x1,U8TO32_LITTLE((uint8_t*)data + 4));
|
||||
x2 = XOR( x2,U8TO32_LITTLE((uint8_t*)data + 8));
|
||||
x3 = XOR( x3,U8TO32_LITTLE((uint8_t*)data + 12));
|
||||
x4 = XOR( x4,U8TO32_LITTLE((uint8_t*)data + 16));
|
||||
x5 = XOR( x5,U8TO32_LITTLE((uint8_t*)data + 20));
|
||||
x6 = XOR( x6,U8TO32_LITTLE((uint8_t*)data + 24));
|
||||
x7 = XOR( x7,U8TO32_LITTLE((uint8_t*)data + 28));
|
||||
x8 = XOR( x8,U8TO32_LITTLE((uint8_t*)data + 32));
|
||||
x9 = XOR( x9,U8TO32_LITTLE((uint8_t*)data + 36));
|
||||
x10 = XOR(x10,U8TO32_LITTLE((uint8_t*)data + 40));
|
||||
x11 = XOR(x11,U8TO32_LITTLE((uint8_t*)data + 44));
|
||||
x12 = XOR(x12,U8TO32_LITTLE((uint8_t*)data + 48));
|
||||
x13 = XOR(x13,U8TO32_LITTLE((uint8_t*)data + 52));
|
||||
x14 = XOR(x14,U8TO32_LITTLE((uint8_t*)data + 56));
|
||||
x15 = XOR(x15,U8TO32_LITTLE((uint8_t*)data + 60));
|
||||
|
||||
j12 = PLUSONE(j12);
|
||||
if (!j12)
|
||||
{
|
||||
j13 = PLUSONE(j13);
|
||||
/* stopping at 2^70 bytes per iv is user's responsibility */
|
||||
}
|
||||
|
||||
U32TO8_LITTLE(cipher + 0,x0);
|
||||
U32TO8_LITTLE(cipher + 4,x1);
|
||||
U32TO8_LITTLE(cipher + 8,x2);
|
||||
U32TO8_LITTLE(cipher + 12,x3);
|
||||
U32TO8_LITTLE(cipher + 16,x4);
|
||||
U32TO8_LITTLE(cipher + 20,x5);
|
||||
U32TO8_LITTLE(cipher + 24,x6);
|
||||
U32TO8_LITTLE(cipher + 28,x7);
|
||||
U32TO8_LITTLE(cipher + 32,x8);
|
||||
U32TO8_LITTLE(cipher + 36,x9);
|
||||
U32TO8_LITTLE(cipher + 40,x10);
|
||||
U32TO8_LITTLE(cipher + 44,x11);
|
||||
U32TO8_LITTLE(cipher + 48,x12);
|
||||
U32TO8_LITTLE(cipher + 52,x13);
|
||||
U32TO8_LITTLE(cipher + 56,x14);
|
||||
U32TO8_LITTLE(cipher + 60,x15);
|
||||
|
||||
if (length <= 64) {
|
||||
if (length < 64) {
|
||||
memcpy(ctarget, cipher, length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
length -= 64;
|
||||
cipher += 64;
|
||||
data = (uint8_t*)data + 64;
|
||||
}
|
||||
}
|
||||
|
||||
void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher)
|
||||
{
|
||||
chacha(8, data, length, key, iv, cipher);
|
||||
}
|
||||
|
||||
void chacha20(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher)
|
||||
{
|
||||
chacha(20, data, length, key, iv, cipher);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define CHACHA_KEY_SIZE 32
|
||||
#define CHACHA_IV_SIZE 8
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include <memory.h>
|
||||
|
||||
#include "memwipe.h"
|
||||
#include "hash.h"
|
||||
|
||||
namespace crypto {
|
||||
extern "C" {
|
||||
#endif
|
||||
void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher);
|
||||
void chacha20(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
using chacha_key = tools::scrubbed_arr<uint8_t, CHACHA_KEY_SIZE>;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
// MS VC 2012 doesn't interpret `class chacha_iv` as POD in spite of [9.0.10], so it is a struct
|
||||
struct chacha_iv {
|
||||
uint8_t data[CHACHA_IV_SIZE];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(chacha_key) == CHACHA_KEY_SIZE && sizeof(chacha_iv) == CHACHA_IV_SIZE, "Invalid structure size");
|
||||
|
||||
inline void chacha8(const void* data, std::size_t length, const chacha_key& key, const chacha_iv& iv, char* cipher) {
|
||||
chacha8(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
|
||||
}
|
||||
|
||||
inline void chacha20(const void* data, std::size_t length, const chacha_key& key, const chacha_iv& iv, char* cipher) {
|
||||
chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
|
||||
}
|
||||
|
||||
inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) {
|
||||
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
|
||||
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
|
||||
crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 0/*prehashed*/);
|
||||
memcpy(&key, pwd_hash.data(), sizeof(key));
|
||||
}
|
||||
|
||||
inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key) {
|
||||
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
|
||||
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
|
||||
crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 1/*prehashed*/);
|
||||
memcpy(&key, pwd_hash.data(), sizeof(key));
|
||||
}
|
||||
|
||||
inline void generate_chacha_key(std::string password, chacha_key& key) {
|
||||
return generate_chacha_key(password.data(), password.size(), key);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -870,3 +870,4 @@ const fe fe_fffb1 = {-31702527, -2466483, -26106795, -12203692, -12169197, -3210
|
|||
const fe fe_fffb2 = {8166131, -6741800, -17040804, 3154616, 21461005, 1466302, -30876704, -6368709, 10503587, -13363080}; /* sqrt(2 * A * (A + 2)) */
|
||||
const fe fe_fffb3 = {-13620103, 14639558, 4532995, 7679154, 16815101, -15883539, -22863840, -14813421, 13716513, -6477756}; /* sqrt(-sqrt(-1) * A * (A + 2)) */
|
||||
const fe fe_fffb4 = {-21786234, -12173074, 21573800, 4524538, -4645904, 16204591, 8012863, -8444712, 3212926, 6885324}; /* sqrt(sqrt(-1) * A * (A + 2)) */
|
||||
const ge_p3 ge_p3_identity = { {0}, {1, 0}, {1, 0}, {0} };
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -1234,6 +1234,51 @@ void ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const g
|
|||
}
|
||||
}
|
||||
|
||||
void ge_double_scalarmult_base_vartime_p3(ge_p3 *r3, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
ge_p2 r;
|
||||
int i;
|
||||
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
ge_dsm_precomp(Ai, A);
|
||||
|
||||
ge_p2_0(&r);
|
||||
|
||||
for (i = 255; i >= 0; --i) {
|
||||
if (aslide[i] || bslide[i]) break;
|
||||
}
|
||||
|
||||
for (; i >= 0; --i) {
|
||||
ge_p2_dbl(&t, &r);
|
||||
|
||||
if (aslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_add(&t, &u, &Ai[aslide[i]/2]);
|
||||
} else if (aslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
|
||||
}
|
||||
|
||||
if (bslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_madd(&t, &u, &ge_Bi[bslide[i]/2]);
|
||||
} else if (bslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_msub(&t, &u, &ge_Bi[(-bslide[i])/2]);
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
ge_p1p1_to_p3(r3, &t);
|
||||
else
|
||||
ge_p1p1_to_p2(&r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
/* From ge_frombytes.c, modified */
|
||||
|
||||
int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
|
@ -2000,17 +2045,79 @@ void ge_scalarmult(ge_p2 *r, const unsigned char *a, const ge_p3 *A) {
|
|||
}
|
||||
}
|
||||
|
||||
void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) {
|
||||
void ge_scalarmult_p3(ge_p3 *r3, const unsigned char *a, const ge_p3 *A) {
|
||||
signed char e[64];
|
||||
int carry, carry2, i;
|
||||
ge_cached Ai[8]; /* 1 * A, 2 * A, ..., 8 * A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
ge_p2 r;
|
||||
|
||||
carry = 0; /* 0..1 */
|
||||
for (i = 0; i < 31; i++) {
|
||||
carry += a[i]; /* 0..256 */
|
||||
carry2 = (carry + 8) >> 4; /* 0..16 */
|
||||
e[2 * i] = carry - (carry2 << 4); /* -8..7 */
|
||||
carry = (carry2 + 8) >> 4; /* 0..1 */
|
||||
e[2 * i + 1] = carry2 - (carry << 4); /* -8..7 */
|
||||
}
|
||||
carry += a[31]; /* 0..128 */
|
||||
carry2 = (carry + 8) >> 4; /* 0..8 */
|
||||
e[62] = carry - (carry2 << 4); /* -8..7 */
|
||||
e[63] = carry2; /* 0..8 */
|
||||
|
||||
ge_p3_to_cached(&Ai[0], A);
|
||||
for (i = 0; i < 7; i++) {
|
||||
ge_add(&t, A, &Ai[i]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[i + 1], &u);
|
||||
}
|
||||
|
||||
ge_p2_0(&r);
|
||||
for (i = 63; i >= 0; i--) {
|
||||
signed char b = e[i];
|
||||
unsigned char bnegative = negative(b);
|
||||
unsigned char babs = b - (((-bnegative) & b) << 1);
|
||||
ge_cached cur, minuscur;
|
||||
ge_p2_dbl(&t, &r);
|
||||
ge_p1p1_to_p2(&r, &t);
|
||||
ge_p2_dbl(&t, &r);
|
||||
ge_p1p1_to_p2(&r, &t);
|
||||
ge_p2_dbl(&t, &r);
|
||||
ge_p1p1_to_p2(&r, &t);
|
||||
ge_p2_dbl(&t, &r);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_cached_0(&cur);
|
||||
ge_cached_cmov(&cur, &Ai[0], equal(babs, 1));
|
||||
ge_cached_cmov(&cur, &Ai[1], equal(babs, 2));
|
||||
ge_cached_cmov(&cur, &Ai[2], equal(babs, 3));
|
||||
ge_cached_cmov(&cur, &Ai[3], equal(babs, 4));
|
||||
ge_cached_cmov(&cur, &Ai[4], equal(babs, 5));
|
||||
ge_cached_cmov(&cur, &Ai[5], equal(babs, 6));
|
||||
ge_cached_cmov(&cur, &Ai[6], equal(babs, 7));
|
||||
ge_cached_cmov(&cur, &Ai[7], equal(babs, 8));
|
||||
fe_copy(minuscur.YplusX, cur.YminusX);
|
||||
fe_copy(minuscur.YminusX, cur.YplusX);
|
||||
fe_copy(minuscur.Z, cur.Z);
|
||||
fe_neg(minuscur.T2d, cur.T2d);
|
||||
ge_cached_cmov(&cur, &minuscur, bnegative);
|
||||
ge_add(&t, &u, &cur);
|
||||
if (i == 0)
|
||||
ge_p1p1_to_p3(r3, &t);
|
||||
else
|
||||
ge_p1p1_to_p2(&r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
void ge_double_scalarmult_precomp_vartime2(ge_p2 *r, const unsigned char *a, const ge_dsmp Ai, const unsigned char *b, const ge_dsmp Bi) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
int i;
|
||||
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
ge_dsm_precomp(Ai, A);
|
||||
|
||||
ge_p2_0(r);
|
||||
|
||||
|
@ -2041,6 +2148,56 @@ void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, cons
|
|||
}
|
||||
}
|
||||
|
||||
void ge_double_scalarmult_precomp_vartime2_p3(ge_p3 *r3, const unsigned char *a, const ge_dsmp Ai, const unsigned char *b, const ge_dsmp Bi) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
ge_p2 r;
|
||||
int i;
|
||||
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
|
||||
ge_p2_0(&r);
|
||||
|
||||
for (i = 255; i >= 0; --i) {
|
||||
if (aslide[i] || bslide[i]) break;
|
||||
}
|
||||
|
||||
for (; i >= 0; --i) {
|
||||
ge_p2_dbl(&t, &r);
|
||||
|
||||
if (aslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_add(&t, &u, &Ai[aslide[i]/2]);
|
||||
} else if (aslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_sub(&t, &u, &Ai[(-aslide[i])/2]);
|
||||
}
|
||||
|
||||
if (bslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_add(&t, &u, &Bi[bslide[i]/2]);
|
||||
} else if (bslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_sub(&t, &u, &Bi[(-bslide[i])/2]);
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
ge_p1p1_to_p3(r3, &t);
|
||||
else
|
||||
ge_p1p1_to_p2(&r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) {
|
||||
ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
|
||||
|
||||
ge_dsm_precomp(Ai, A);
|
||||
ge_double_scalarmult_precomp_vartime2(r, a, Ai, b, Bi);
|
||||
}
|
||||
|
||||
void ge_mul8(ge_p1p1 *r, const ge_p2 *t) {
|
||||
ge_p2 u;
|
||||
ge_p2_dbl(r, t);
|
||||
|
@ -2898,6 +3055,658 @@ void sc_mulsub(unsigned char *s, const unsigned char *a, const unsigned char *b,
|
|||
s[31] = s11 >> 17;
|
||||
}
|
||||
|
||||
//copied from above and modified
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (ab) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
void sc_mul(unsigned char *s, const unsigned char *a, const unsigned char *b) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = a0*b0;
|
||||
s1 = (a0*b1 + a1*b0);
|
||||
s2 = (a0*b2 + a1*b1 + a2*b0);
|
||||
s3 = (a0*b3 + a1*b2 + a2*b1 + a3*b0);
|
||||
s4 = (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
|
||||
s5 = (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
|
||||
s6 = (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
|
||||
s7 = (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
|
||||
s8 = (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
|
||||
s9 = (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
|
||||
s10 = (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
|
||||
s11 = (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
|
||||
s12 = (a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
|
||||
s13 = (a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
|
||||
s14 = (a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
|
||||
s15 = (a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
|
||||
s16 = (a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
|
||||
s17 = (a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
|
||||
s18 = (a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
|
||||
s19 = (a8*b11 + a9*b10 + a10*b9 + a11*b8);
|
||||
s20 = (a9*b11 + a10*b10 + a11*b9);
|
||||
s21 = (a10*b11 + a11*b10);
|
||||
s22 = a11*b11;
|
||||
s23 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
s[0] = s0 >> 0;
|
||||
s[1] = s0 >> 8;
|
||||
s[2] = (s0 >> 16) | (s1 << 5);
|
||||
s[3] = s1 >> 3;
|
||||
s[4] = s1 >> 11;
|
||||
s[5] = (s1 >> 19) | (s2 << 2);
|
||||
s[6] = s2 >> 6;
|
||||
s[7] = (s2 >> 14) | (s3 << 7);
|
||||
s[8] = s3 >> 1;
|
||||
s[9] = s3 >> 9;
|
||||
s[10] = (s3 >> 17) | (s4 << 4);
|
||||
s[11] = s4 >> 4;
|
||||
s[12] = s4 >> 12;
|
||||
s[13] = (s4 >> 20) | (s5 << 1);
|
||||
s[14] = s5 >> 7;
|
||||
s[15] = (s5 >> 15) | (s6 << 6);
|
||||
s[16] = s6 >> 2;
|
||||
s[17] = s6 >> 10;
|
||||
s[18] = (s6 >> 18) | (s7 << 3);
|
||||
s[19] = s7 >> 5;
|
||||
s[20] = s7 >> 13;
|
||||
s[21] = s8 >> 0;
|
||||
s[22] = s8 >> 8;
|
||||
s[23] = (s8 >> 16) | (s9 << 5);
|
||||
s[24] = s9 >> 3;
|
||||
s[25] = s9 >> 11;
|
||||
s[26] = (s9 >> 19) | (s10 << 2);
|
||||
s[27] = s10 >> 6;
|
||||
s[28] = (s10 >> 14) | (s11 << 7);
|
||||
s[29] = s11 >> 1;
|
||||
s[30] = s11 >> 9;
|
||||
s[31] = s11 >> 17;
|
||||
}
|
||||
|
||||
//copied from above and modified
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
c[0]+256*c[1]+...+256^31*c[31] = c
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (c+ab) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t c0 = 2097151 & load_3(c);
|
||||
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
||||
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
||||
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
||||
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
||||
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
||||
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
||||
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
||||
int64_t c8 = 2097151 & load_3(c + 21);
|
||||
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
||||
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
||||
int64_t c11 = (load_4(c + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = c0 + a0*b0;
|
||||
s1 = c1 + (a0*b1 + a1*b0);
|
||||
s2 = c2 + (a0*b2 + a1*b1 + a2*b0);
|
||||
s3 = c3 + (a0*b3 + a1*b2 + a2*b1 + a3*b0);
|
||||
s4 = c4 + (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
|
||||
s5 = c5 + (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
|
||||
s6 = c6 + (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
|
||||
s7 = c7 + (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
|
||||
s8 = c8 + (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
|
||||
s9 = c9 + (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
|
||||
s10 = c10 + (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
|
||||
s11 = c11 + (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
|
||||
s12 = (a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
|
||||
s13 = (a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
|
||||
s14 = (a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
|
||||
s15 = (a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
|
||||
s16 = (a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
|
||||
s17 = (a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
|
||||
s18 = (a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
|
||||
s19 = (a8*b11 + a9*b10 + a10*b9 + a11*b8);
|
||||
s20 = (a9*b11 + a10*b10 + a11*b9);
|
||||
s21 = (a10*b11 + a11*b10);
|
||||
s22 = a11*b11;
|
||||
s23 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
s[0] = s0 >> 0;
|
||||
s[1] = s0 >> 8;
|
||||
s[2] = (s0 >> 16) | (s1 << 5);
|
||||
s[3] = s1 >> 3;
|
||||
s[4] = s1 >> 11;
|
||||
s[5] = (s1 >> 19) | (s2 << 2);
|
||||
s[6] = s2 >> 6;
|
||||
s[7] = (s2 >> 14) | (s3 << 7);
|
||||
s[8] = s3 >> 1;
|
||||
s[9] = s3 >> 9;
|
||||
s[10] = (s3 >> 17) | (s4 << 4);
|
||||
s[11] = s4 >> 4;
|
||||
s[12] = s4 >> 12;
|
||||
s[13] = (s4 >> 20) | (s5 << 1);
|
||||
s[14] = s5 >> 7;
|
||||
s[15] = (s5 >> 15) | (s6 << 6);
|
||||
s[16] = s6 >> 2;
|
||||
s[17] = s6 >> 10;
|
||||
s[18] = (s6 >> 18) | (s7 << 3);
|
||||
s[19] = s7 >> 5;
|
||||
s[20] = s7 >> 13;
|
||||
s[21] = s8 >> 0;
|
||||
s[22] = s8 >> 8;
|
||||
s[23] = (s8 >> 16) | (s9 << 5);
|
||||
s[24] = s9 >> 3;
|
||||
s[25] = s9 >> 11;
|
||||
s[26] = (s9 >> 19) | (s10 << 2);
|
||||
s[27] = s10 >> 6;
|
||||
s[28] = (s10 >> 14) | (s11 << 7);
|
||||
s[29] = s11 >> 1;
|
||||
s[30] = s11 >> 9;
|
||||
s[31] = s11 >> 17;
|
||||
}
|
||||
|
||||
/* Assumes that a != INT64_MIN */
|
||||
static int64_t signum(int64_t a) {
|
||||
return (a >> 63) - ((-a) >> 63);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -79,6 +79,7 @@ typedef ge_cached ge_dsmp[8];
|
|||
extern const ge_precomp ge_Bi[8];
|
||||
void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s);
|
||||
void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *);
|
||||
void ge_double_scalarmult_base_vartime_p3(ge_p3 *, const unsigned char *, const ge_p3 *, const unsigned char *);
|
||||
|
||||
/* From ge_frombytes.c, modified */
|
||||
|
||||
|
@ -127,7 +128,10 @@ void sc_reduce(unsigned char *);
|
|||
/* New code */
|
||||
|
||||
void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
|
||||
void ge_scalarmult_p3(ge_p3 *, const unsigned char *, const ge_p3 *);
|
||||
void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp);
|
||||
void ge_double_scalarmult_precomp_vartime2(ge_p2 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp);
|
||||
void ge_double_scalarmult_precomp_vartime2_p3(ge_p3 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp);
|
||||
void ge_mul8(ge_p1p1 *, const ge_p2 *);
|
||||
extern const fe fe_ma2;
|
||||
extern const fe fe_ma;
|
||||
|
@ -135,12 +139,15 @@ extern const fe fe_fffb1;
|
|||
extern const fe fe_fffb2;
|
||||
extern const fe fe_fffb3;
|
||||
extern const fe fe_fffb4;
|
||||
extern const ge_p3 ge_p3_identity;
|
||||
void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
|
||||
void sc_0(unsigned char *);
|
||||
void sc_reduce32(unsigned char *);
|
||||
void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_mul(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
|
||||
int sc_check(const unsigned char *);
|
||||
int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -43,6 +43,18 @@
|
|||
#include "crypto.h"
|
||||
#include "hash.h"
|
||||
|
||||
namespace {
|
||||
static void local_abort(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
#ifdef NDEBUG
|
||||
_exit(1);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace crypto {
|
||||
|
||||
using std::abort;
|
||||
|
@ -87,14 +99,14 @@ namespace crypto {
|
|||
random_scalar_not_thread_safe(res);
|
||||
}
|
||||
|
||||
static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
|
||||
void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
|
||||
cn_fast_hash(data, length, reinterpret_cast<hash &>(res));
|
||||
sc_reduce32(&res);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate public and secret keys from a random 256-bit integer
|
||||
* TODO: allow specifiying random value (for wallet recovery)
|
||||
* TODO: allow specifying random value (for wallet recovery)
|
||||
*
|
||||
*/
|
||||
secret_key crypto_ops::generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) {
|
||||
|
@ -189,6 +201,25 @@ namespace crypto {
|
|||
sc_add(&derived_key, &base, &scalar);
|
||||
}
|
||||
|
||||
bool crypto_ops::derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key) {
|
||||
ec_scalar scalar;
|
||||
ge_p3 point1;
|
||||
ge_p3 point2;
|
||||
ge_cached point3;
|
||||
ge_p1p1 point4;
|
||||
ge_p2 point5;
|
||||
if (ge_frombytes_vartime(&point1, &out_key) != 0) {
|
||||
return false;
|
||||
}
|
||||
derivation_to_scalar(derivation, output_index, scalar);
|
||||
ge_scalarmult_base(&point2, &scalar);
|
||||
ge_p3_to_cached(&point3, &point2);
|
||||
ge_sub(&point4, &point1, &point3);
|
||||
ge_p1p1_to_p2(&point5, &point4);
|
||||
ge_tobytes(&derived_key, &point5);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct s_comm {
|
||||
hash h;
|
||||
ec_point key;
|
||||
|
@ -246,22 +277,33 @@ namespace crypto {
|
|||
return sc_isnonzero(&c) == 0;
|
||||
}
|
||||
|
||||
void crypto_ops::generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const secret_key &r, signature &sig) {
|
||||
void crypto_ops::generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
|
||||
// sanity check
|
||||
ge_p3 R_p3;
|
||||
ge_p3 A_p3;
|
||||
ge_p3 B_p3;
|
||||
ge_p3 D_p3;
|
||||
if (ge_frombytes_vartime(&R_p3, &R) != 0) throw std::runtime_error("tx pubkey is invalid");
|
||||
if (ge_frombytes_vartime(&A_p3, &A) != 0) throw std::runtime_error("recipient view pubkey is invalid");
|
||||
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) throw std::runtime_error("recipient spend pubkey is invalid");
|
||||
if (ge_frombytes_vartime(&D_p3, &D) != 0) throw std::runtime_error("key derivation is invalid");
|
||||
#if !defined(NDEBUG)
|
||||
{
|
||||
assert(sc_check(&r) == 0);
|
||||
// check R == r*G
|
||||
ge_p3 dbg_R_p3;
|
||||
ge_scalarmult_base(&dbg_R_p3, &r);
|
||||
// check R == r*G or R == r*B
|
||||
public_key dbg_R;
|
||||
ge_p3_tobytes(&dbg_R, &dbg_R_p3);
|
||||
if (B)
|
||||
{
|
||||
ge_p2 dbg_R_p2;
|
||||
ge_scalarmult(&dbg_R_p2, &r, &B_p3);
|
||||
ge_tobytes(&dbg_R, &dbg_R_p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ge_p3 dbg_R_p3;
|
||||
ge_scalarmult_base(&dbg_R_p3, &r);
|
||||
ge_p3_tobytes(&dbg_R, &dbg_R_p3);
|
||||
}
|
||||
assert(R == dbg_R);
|
||||
// check D == r*A
|
||||
ge_p2 dbg_D_p2;
|
||||
|
@ -276,43 +318,84 @@ namespace crypto {
|
|||
ec_scalar k;
|
||||
random_scalar(k);
|
||||
|
||||
// compute X = k*G
|
||||
ge_p3 X_p3;
|
||||
ge_scalarmult_base(&X_p3, &k);
|
||||
s_comm_2 buf;
|
||||
buf.msg = prefix_hash;
|
||||
buf.D = D;
|
||||
|
||||
if (B)
|
||||
{
|
||||
// compute X = k*B
|
||||
ge_p2 X_p2;
|
||||
ge_scalarmult(&X_p2, &k, &B_p3);
|
||||
ge_tobytes(&buf.X, &X_p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// compute X = k*G
|
||||
ge_p3 X_p3;
|
||||
ge_scalarmult_base(&X_p3, &k);
|
||||
ge_p3_tobytes(&buf.X, &X_p3);
|
||||
}
|
||||
|
||||
// compute Y = k*A
|
||||
ge_p2 Y_p2;
|
||||
ge_scalarmult(&Y_p2, &k, &A_p3);
|
||||
ge_tobytes(&buf.Y, &Y_p2);
|
||||
|
||||
// sig.c = Hs(Msg || D || X || Y)
|
||||
s_comm_2 buf;
|
||||
buf.msg = prefix_hash;
|
||||
buf.D = D;
|
||||
ge_p3_tobytes(&buf.X, &X_p3);
|
||||
ge_tobytes(&buf.Y, &Y_p2);
|
||||
hash_to_scalar(&buf, sizeof(s_comm_2), sig.c);
|
||||
hash_to_scalar(&buf, sizeof(buf), sig.c);
|
||||
|
||||
// sig.r = k - sig.c*r
|
||||
sc_mulsub(&sig.r, &sig.c, &r, &k);
|
||||
}
|
||||
|
||||
bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const signature &sig) {
|
||||
bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
|
||||
// sanity check
|
||||
ge_p3 R_p3;
|
||||
ge_p3 A_p3;
|
||||
ge_p3 B_p3;
|
||||
ge_p3 D_p3;
|
||||
if (ge_frombytes_vartime(&R_p3, &R) != 0) return false;
|
||||
if (ge_frombytes_vartime(&A_p3, &A) != 0) return false;
|
||||
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) return false;
|
||||
if (ge_frombytes_vartime(&D_p3, &D) != 0) return false;
|
||||
if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) return false;
|
||||
|
||||
// compute sig.c*R
|
||||
ge_p2 cR_p2;
|
||||
ge_scalarmult(&cR_p2, &sig.c, &R_p3);
|
||||
ge_p3 cR_p3;
|
||||
{
|
||||
ge_p2 cR_p2;
|
||||
ge_scalarmult(&cR_p2, &sig.c, &R_p3);
|
||||
public_key cR;
|
||||
ge_tobytes(&cR, &cR_p2);
|
||||
if (ge_frombytes_vartime(&cR_p3, &cR) != 0) return false;
|
||||
}
|
||||
|
||||
// compute sig.r*G
|
||||
ge_p3 rG_p3;
|
||||
ge_scalarmult_base(&rG_p3, &sig.r);
|
||||
ge_p1p1 X_p1p1;
|
||||
if (B)
|
||||
{
|
||||
// compute X = sig.c*R + sig.r*B
|
||||
ge_p2 rB_p2;
|
||||
ge_scalarmult(&rB_p2, &sig.r, &B_p3);
|
||||
public_key rB;
|
||||
ge_tobytes(&rB, &rB_p2);
|
||||
ge_p3 rB_p3;
|
||||
if (ge_frombytes_vartime(&rB_p3, &rB) != 0) return false;
|
||||
ge_cached rB_cached;
|
||||
ge_p3_to_cached(&rB_cached, &rB_p3);
|
||||
ge_add(&X_p1p1, &cR_p3, &rB_cached);
|
||||
}
|
||||
else
|
||||
{
|
||||
// compute X = sig.c*R + sig.r*G
|
||||
ge_p3 rG_p3;
|
||||
ge_scalarmult_base(&rG_p3, &sig.r);
|
||||
ge_cached rG_cached;
|
||||
ge_p3_to_cached(&rG_cached, &rG_p3);
|
||||
ge_add(&X_p1p1, &cR_p3, &rG_cached);
|
||||
}
|
||||
ge_p2 X_p2;
|
||||
ge_p1p1_to_p2(&X_p2, &X_p1p1);
|
||||
|
||||
// compute sig.c*D
|
||||
ge_p2 cD_p2;
|
||||
|
@ -322,18 +405,6 @@ namespace crypto {
|
|||
ge_p2 rA_p2;
|
||||
ge_scalarmult(&rA_p2, &sig.r, &A_p3);
|
||||
|
||||
// compute X = sig.c*R + sig.r*G
|
||||
public_key cR;
|
||||
ge_tobytes(&cR, &cR_p2);
|
||||
ge_p3 cR_p3;
|
||||
if (ge_frombytes_vartime(&cR_p3, &cR) != 0) return false;
|
||||
ge_cached rG_cached;
|
||||
ge_p3_to_cached(&rG_cached, &rG_p3);
|
||||
ge_p1p1 X_p1p1;
|
||||
ge_add(&X_p1p1, &cR_p3, &rG_cached);
|
||||
ge_p2 X_p2;
|
||||
ge_p1p1_to_p2(&X_p2, &X_p1p1);
|
||||
|
||||
// compute Y = sig.c*D + sig.r*A
|
||||
public_key cD;
|
||||
public_key rA;
|
||||
|
@ -408,7 +479,7 @@ POP_WARNINGS
|
|||
ec_scalar sum, k, h;
|
||||
boost::shared_ptr<rs_comm> buf(reinterpret_cast<rs_comm *>(malloc(rs_comm_size(pubs_count))), free);
|
||||
if (!buf)
|
||||
abort();
|
||||
local_abort("malloc failure");
|
||||
assert(sec_index < pubs_count);
|
||||
#if !defined(NDEBUG)
|
||||
{
|
||||
|
@ -427,7 +498,7 @@ POP_WARNINGS
|
|||
}
|
||||
#endif
|
||||
if (ge_frombytes_vartime(&image_unp, &image) != 0) {
|
||||
abort();
|
||||
local_abort("invalid key image");
|
||||
}
|
||||
ge_dsm_precomp(image_pre, &image_unp);
|
||||
sc_0(&sum);
|
||||
|
@ -446,7 +517,7 @@ POP_WARNINGS
|
|||
random_scalar(sig[i].c);
|
||||
random_scalar(sig[i].r);
|
||||
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
|
||||
abort();
|
||||
local_abort("invalid pubkey");
|
||||
}
|
||||
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
|
||||
ge_tobytes(&buf->ab[i].a, &tmp2);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -31,12 +31,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "common/pod-class.h"
|
||||
#include "common/util.h"
|
||||
#include "memwipe.h"
|
||||
#include "generic-ops.h"
|
||||
#include "hex.h"
|
||||
#include "span.h"
|
||||
#include "hash.h"
|
||||
|
||||
namespace crypto {
|
||||
|
@ -60,9 +68,7 @@ namespace crypto {
|
|||
friend class crypto_ops;
|
||||
};
|
||||
|
||||
POD_CLASS secret_key: ec_scalar {
|
||||
friend class crypto_ops;
|
||||
};
|
||||
using secret_key = tools::scrubbed<ec_scalar>;
|
||||
|
||||
POD_CLASS public_keyV {
|
||||
std::vector<public_key> keys;
|
||||
|
@ -94,6 +100,8 @@ namespace crypto {
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
void hash_to_scalar(const void *data, size_t length, ec_scalar &res);
|
||||
|
||||
static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
|
||||
sizeof(public_key) == 32 && sizeof(secret_key) == 32 &&
|
||||
sizeof(key_derivation) == 32 && sizeof(key_image) == 32 &&
|
||||
|
@ -119,14 +127,16 @@ namespace crypto {
|
|||
friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
|
||||
static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
|
||||
friend void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
|
||||
static bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
|
||||
friend bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
|
||||
static void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
|
||||
friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
|
||||
static bool check_signature(const hash &, const public_key &, const signature &);
|
||||
friend bool check_signature(const hash &, const public_key &, const signature &);
|
||||
static void generate_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const secret_key &, signature &);
|
||||
friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const secret_key &, signature &);
|
||||
static bool check_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const signature &);
|
||||
friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const signature &);
|
||||
static void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
|
||||
friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
|
||||
static void generate_key_image(const public_key &, const secret_key &, key_image &);
|
||||
friend void generate_key_image(const public_key &, const secret_key &, key_image &);
|
||||
static void generate_ring_signature(const hash &, const key_image &,
|
||||
|
@ -194,6 +204,9 @@ namespace crypto {
|
|||
const secret_key &base, secret_key &derived_key) {
|
||||
crypto_ops::derive_secret_key(derivation, output_index, base, derived_key);
|
||||
}
|
||||
inline bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &result) {
|
||||
return crypto_ops::derive_subaddress_public_key(out_key, derivation, output_index, result);
|
||||
}
|
||||
|
||||
/* Generation and checking of a standard signature.
|
||||
*/
|
||||
|
@ -206,12 +219,13 @@ namespace crypto {
|
|||
|
||||
/* Generation and checking of a tx proof; given a tx pubkey R, the recipient's view pubkey A, and the key
|
||||
* derivation D, the signature proves the knowledge of the tx secret key r such that R=r*G and D=r*A
|
||||
* When the recipient's address is a subaddress, the tx pubkey R is defined as R=r*B where B is the recipient's spend pubkey
|
||||
*/
|
||||
inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const secret_key &r, signature &sig) {
|
||||
crypto_ops::generate_tx_proof(prefix_hash, R, A, D, r, sig);
|
||||
inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
|
||||
crypto_ops::generate_tx_proof(prefix_hash, R, A, B, D, r, sig);
|
||||
}
|
||||
inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const signature &sig) {
|
||||
return crypto_ops::check_tx_proof(prefix_hash, R, A, D, sig);
|
||||
inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
|
||||
return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig);
|
||||
}
|
||||
|
||||
/* To send money to a key:
|
||||
|
@ -248,8 +262,28 @@ namespace crypto {
|
|||
const signature *sig) {
|
||||
return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig);
|
||||
}
|
||||
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
}
|
||||
|
||||
const static crypto::public_key null_pkey = boost::value_initialized<crypto::public_key>();
|
||||
const static crypto::secret_key null_skey = boost::value_initialized<crypto::secret_key>();
|
||||
}
|
||||
|
||||
CRYPTO_MAKE_HASHABLE(public_key)
|
||||
CRYPTO_MAKE_HASHABLE(secret_key)
|
||||
CRYPTO_MAKE_HASHABLE(key_image)
|
||||
CRYPTO_MAKE_COMPARABLE(signature)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2017, The Monero Project
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue