diff --git a/.gitignore b/.gitignore index 370ac6467..5bcc43ed6 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ recovered-shares.json src/MiningCore/config\.json +/src/MiningCore/config2.json diff --git a/src/MiningCore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs b/src/MiningCore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs index 2282c2ead..faafe0fa8 100644 --- a/src/MiningCore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs +++ b/src/MiningCore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs @@ -47,12 +47,12 @@ public void BitcoinJob_Should_Accept_Valid_Share() // 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 @@ public void BitcoinJob_Should_Not_Accept_Invalid_Share() Assert.Throws(() => 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(() => job.ProcessShare(worker, "01000000", "59ef86f2", "8D84AE6A")); // invalid time Assert.Throws(() => job.ProcessShare(worker, "01000000", "69ef86f2", "8d84ae6a")); // invalid nonce - Assert.Throws(() => job.ProcessShare(worker, "01000000", "59ef86f2", "ad84be6a")); + Assert.Throws(() => job.ProcessShare(worker, "01000000", "59ef86f2", "4a84be6a")); // valid share data but invalid submission time clock.CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1408869907).UtcDateTime; diff --git a/src/MiningCore.Tests/Blockchain/Monero/MoneroJobTests.cs b/src/MiningCore.Tests/Blockchain/Monero/MoneroJobTests.cs index 39f2ac5e8..b2e757de6 100644 --- a/src/MiningCore.Tests/Blockchain/Monero/MoneroJobTests.cs +++ b/src/MiningCore.Tests/Blockchain/Monero/MoneroJobTests.cs @@ -26,12 +26,12 @@ public void MoneroJob_Should_Accept_Valid_Share() "{\"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); } diff --git a/src/MiningCore.Tests/Crypto/CrytonoteTests.cs b/src/MiningCore.Tests/Crypto/CrytonoteTests.cs new file mode 100644 index 000000000..b8e32bacf --- /dev/null +++ b/src/MiningCore.Tests/Crypto/CrytonoteTests.cs @@ -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(() => 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(() => 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(() => 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(() => LibCryptonote.DecodeAddress(null)); + Assert.Throws(() => LibCryptonote.DecodeAddress("")); + } + + [Fact] + public void Crytonote_DecodeIntegratedAddress() + { + var address = "4BrL51JCc9NGQ71kWhnYoDRffsDZy7m1HUU7MRU4nUMXAHNFBEJhkTZV9HdaL4gfuNBxLPc3BeMkLGaPbF5vWtANQsGwTGg55Kq4p3ENE7"; + var result = LibCryptonote.DecodeIntegratedAddress(address); + + Assert.Equal(19ul, result); + } + } +} diff --git a/src/MiningCore.Tests/Crypto/HashingTests.cs b/src/MiningCore.Tests/Crypto/HashingTests.cs index a0be06bd4..ae8292e44 100644 --- a/src/MiningCore.Tests/Crypto/HashingTests.cs +++ b/src/MiningCore.Tests/Crypto/HashingTests.cs @@ -18,7 +18,7 @@ public class HashingTests : TestBase 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 @@ public void Blake_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Blake2s_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Groestl_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Kezzak_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Scrypt_Hash_Should_Throw_On_Null_Input() } [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 @@ public void NeoScrypt_Hash_Should_Throw_On_Null_Input() } [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 @@ public void ScryptN_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Lyra2Rev2_Hash_Should_Throw_On_Short_Input() } [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 @@ public void Sha256D_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Sha256S_Hash_Should_Throw_On_Null_Input() } [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 @@ public void X11_Hash_Should_Throw_On_Null_Input() } [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 @@ public void X17_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Skein_Hash_Should_Throw_On_Null_Input() } [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 @@ public void Qubit_Hash_Should_Throw_On_Null_Input() } [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 @@ public void GroestlMyriad_Hash_Should_Throw_On_Null_Input() } [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 @@ public void EquihashVerifier_Should_Throw_On_Wrong_Argument_Length() } [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 @@ public void Sha3_256_Hash_Should_Throw_On_Null_Input() } [Fact] - public void Sha3_512_Hash_Should_Match() + public void Sha3_512_Hash() { var hasher = new Sha3_512(); var result = hasher.Digest(testValue).ToHexString(); diff --git a/src/MiningCore.Tests/Native/LibCryptonoteTests.cs b/src/MiningCore.Tests/Native/LibCryptonoteTests.cs deleted file mode 100644 index a699012e7..000000000 --- a/src/MiningCore.Tests/Native/LibCryptonoteTests.cs +++ /dev/null @@ -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(() => 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(() => 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(() => LibCryptonote.DecodeAddress(null)); - Assert.Throws(() => 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(() => LibCryptonote.ConvertBlob(null, 0)); - } - } -} diff --git a/src/MiningCore/AutoMapperProfile.cs b/src/MiningCore/AutoMapperProfile.cs index e76232781..5dd268ac1 100644 --- a/src/MiningCore/AutoMapperProfile.cs +++ b/src/MiningCore/AutoMapperProfile.cs @@ -34,9 +34,9 @@ public AutoMapperProfile() ////////////////////// // outgoing mappings - CreateMap(); + CreateMap(); - CreateMap() + CreateMap() .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 @@ public AutoMapperProfile() CreateMap(); // PostgreSQL - CreateMap(); + CreateMap(); CreateMap(); CreateMap(); CreateMap(); @@ -82,7 +82,7 @@ public AutoMapperProfile() // incoming mappings // PostgreSQL - CreateMap(); + CreateMap(); CreateMap(); CreateMap(); CreateMap(); diff --git a/src/MiningCore/Blockchain/Abstractions.cs b/src/MiningCore/Blockchain/Abstractions.cs index 9b2c1ff45..a583f83b0 100644 --- a/src/MiningCore/Blockchain/Abstractions.cs +++ b/src/MiningCore/Blockchain/Abstractions.cs @@ -37,84 +37,4 @@ public interface IExtraNonceProvider { string Next(); } - - public interface IShare - { - /// - /// The pool originating this share from - /// - string PoolId { get; set; } - - /// - /// Who mined it (wallet address) - /// - string Miner { get; } - - /// - /// Who mined it - /// - string Worker { get; } - - /// - /// Extra information for payout processing - /// - string PayoutInfo { get; set; } - - /// - /// Mining Software - /// - string UserAgent { get; } - - /// - /// From where was it submitted - /// - string IpAddress { get; } - - /// - /// Submission source (pool, external stratum etc) - /// - string Source { get; set; } - - /// - /// Stratum difficulty assigned to the miner at the time the share was submitted/accepted (used for payout - /// calculations) - /// - double Difficulty { get; set; } - - /// - /// Block this share refers to - /// - long BlockHeight { get; set; } - - /// - /// Block reward after deducting pool fee and donations - /// - decimal BlockReward { get; set; } - - /// - /// Block hash - /// - string BlockHash { get; set; } - - /// - /// If this share presumably resulted in a block - /// - bool IsBlockCandidate { get; set; } - - /// - /// Arbitrary data to be interpreted by the payment processor specialized - /// in this coin to verify this block candidate was accepted by the network - /// - string TransactionConfirmationData { get; set; } - - /// - /// Network difficulty at the time the share was submitted (used for some payout schemes like PPLNS) - /// - double NetworkDifficulty { get; set; } - - /// - /// When the share was found - /// - DateTime Created { get; set; } - } } diff --git a/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs b/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs index de532815b..2fd135fef 100644 --- a/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs @@ -99,15 +99,12 @@ protected virtual void BuildMerkleBranches() 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 @@ protected virtual void BuildCoinbase() 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 @@ protected virtual Script GenerateScriptSigInitial() // push timestamp ops.Add(Op.GetPushOp(now)); + // push placeholder + ops.Add(Op.GetPushOp((uint) 0)); + return new Script(ops); } @@ -289,7 +286,7 @@ protected virtual byte[] SerializeHeader(byte[] coinbaseHash, uint nTime, uint n 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(); var extraNonce1 = context.ExtraNonce1; @@ -330,24 +327,26 @@ protected virtual BitcoinShare ProcessShareInternal(StratumClient worker, string 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 @@ public virtual object GetJobParams(bool isNew) 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)); diff --git a/src/MiningCore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/MiningCore/Blockchain/Bitcoin/BitcoinJobManager.cs index 71313b26b..398b72e16 100644 --- a/src/MiningCore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/MiningCore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -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 @@ private async Task UpdateNetworkStatsAsync() 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 @@ private async Task UpdateNetworkStatsAsync() 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 @@ public string[] GetTransactions(StratumClient worker, object requestParams) return job.BlockTemplate.Transactions.Select(x => x.Data).ToArray(); } - public virtual async Task SubmitShareAsync(StratumClient worker, object submission, + public virtual async Task SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -484,14 +487,23 @@ public virtual async Task SubmitShareAsync(StratumClient worker, o 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 @@ public virtual async Task SubmitShareAsync(StratumClient worker, o } } - // 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 @@ protected override async Task PostStartInitAsync() 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(); diff --git a/src/MiningCore/Blockchain/Bitcoin/BitcoinPoolBase.cs b/src/MiningCore/Blockchain/Bitcoin/BitcoinPoolBase.cs index fa368b2c8..a7be6c34d 100644 --- a/src/MiningCore/Blockchain/Bitcoin/BitcoinPoolBase.cs +++ b/src/MiningCore/Blockchain/Bitcoin/BitcoinPoolBase.cs @@ -40,7 +40,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace MiningCore.Blockchain.Bitcoin { - public class BitcoinPoolBase : PoolBase + public class BitcoinPoolBase : PoolBase where TBlockTemplate : BlockTemplate where TJob : BitcoinJob, new() { diff --git a/src/MiningCore/Blockchain/Bitcoin/BitcoinProperties.cs b/src/MiningCore/Blockchain/Bitcoin/BitcoinProperties.cs index 40e4a661d..c888b92ef 100644 --- a/src/MiningCore/Blockchain/Bitcoin/BitcoinProperties.cs +++ b/src/MiningCore/Blockchain/Bitcoin/BitcoinProperties.cs @@ -44,6 +44,7 @@ public class BitcoinProperties 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 @@ public class BitcoinProperties 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 coinProperties = new Dictionary { @@ -97,7 +101,7 @@ public class BitcoinProperties { CoinType.BCH, sha256Coin }, { CoinType.NMC, sha256Coin }, { CoinType.PPC, sha256Coin }, - { CoinType.GLT, sha256Coin }, + { CoinType.GLT, sha256Coin }, // Scrypt { CoinType.LTC, scryptCoin }, @@ -145,9 +149,10 @@ private static BitcoinCoinProperties GetDigiByteProperties(string algorithm) { Contract.Requires(!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 @@ private static BitcoinCoinProperties GetVergeProperties(string algorithm) return vergeBlake2sCoin; default: // scrypt - return scryptCoin; + return vergeScryptCoin; } } diff --git a/src/MiningCore/Blockchain/Bitcoin/BitcoinShare.cs b/src/MiningCore/Blockchain/Bitcoin/BitcoinShare.cs deleted file mode 100644 index d3bd3d317..000000000 --- a/src/MiningCore/Blockchain/Bitcoin/BitcoinShare.cs +++ /dev/null @@ -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; } - } -} diff --git a/src/MiningCore/Blockchain/CoinMetaData.cs b/src/MiningCore/Blockchain/CoinMetaData.cs index f97494bbd..76b24bd92 100644 --- a/src/MiningCore/Blockchain/CoinMetaData.cs +++ b/src/MiningCore/Blockchain/CoinMetaData.cs @@ -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> BlockInfoLinks = new Dictionary> - { - { CoinType.ETH, new Dictionary - { - { string.Empty, $"https://etherscan.io/block/{BlockHeightPH}" }, - { EthereumConstants.BlockTypeUncle, $"https://etherscan.io/uncle/{BlockHeightPH}" }, - }}, - - { CoinType.ETC, new Dictionary - { - { string.Empty, $"https://gastracker.io/block/{BlockHeightPH}" }, - { EthereumConstants.BlockTypeUncle, $"https://gastracker.io/uncle/{BlockHeightPH}" } - }}, - - { CoinType.XMR, new Dictionary { { string.Empty, $"https://chainradar.com/xmr/block/{BlockHeightPH}" }}}, - { CoinType.ETN, new Dictionary { { string.Empty, $"https://blockexplorer.electroneum.com/block/{BlockHeightPH}" } }}, - { CoinType.LTC, new Dictionary { { string.Empty, $"https://chainz.cryptoid.info/ltc/block.dws?{BlockHeightPH}.htm" } }}, - { CoinType.BCH, new Dictionary { { string.Empty, $"https://www.blocktrail.com/BCC/block/{BlockHeightPH}" }}}, - { CoinType.DASH, new Dictionary { { string.Empty, $"https://chainz.cryptoid.info/dash/block.dws?{BlockHeightPH}.htm" }}}, - { CoinType.BTC, new Dictionary { { string.Empty, $"https://blockchain.info/block/{BlockHeightPH}" }}}, - { CoinType.DOGE, new Dictionary { { string.Empty, $"https://dogechain.info/block/{BlockHeightPH}" }}}, - { CoinType.ZEC, new Dictionary { { string.Empty, $"https://explorer.zcha.in/blocks/{BlockHashPH}" } }}, - { CoinType.BTCP, new Dictionary { { string.Empty, $"http://explorer.btcprivate.org/block/{BlockHashPH}" } }}, - { CoinType.ZCL, new Dictionary { { string.Empty, $"http://explorer.zclmine.pro/block/{BlockHeightPH}" }}}, - { CoinType.ZEN, new Dictionary { { string.Empty, $"http://explorer.zensystem.io/block/{BlockHashPH}" } }}, - { CoinType.DGB, new Dictionary { { string.Empty, $"https://digiexplorer.info/block/{BlockHeightPH}" }}}, - { CoinType.NMC, new Dictionary { { string.Empty, $"https://explorer.namecoin.info/b/{BlockHeightPH}" }}}, - { CoinType.GRS, new Dictionary { { string.Empty, $"https://groestlsight.groestlcoin.org/block/{BlockHeightPH}" }}}, - { CoinType.MONA, new Dictionary { { string.Empty, $"https://bchain.info/MONA/block/{BlockHeightPH}" }}}, - { CoinType.GLT, new Dictionary { { string.Empty, $"https://bchain.info/GLT/block/{BlockHeightPH}" }}}, - { CoinType.VTC, new Dictionary { { string.Empty, $"https://bchain.info/VTC/block/{BlockHeightPH}" }}}, - { CoinType.BTG, new Dictionary { { string.Empty, $"https://btg-bitcore2.trezor.io/block/{BlockHashPH}" } }}, - { CoinType.ELLA, new Dictionary { { string.Empty, $"https://explorer.ellaism.org/block/{BlockHeightPH}" }}}, - { CoinType.EXP, new Dictionary { { string.Empty, $"http://www.gander.tech/blocks/{BlockHeightPH}" }}}, - { CoinType.AEON, new Dictionary { { string.Empty, $"https://chainradar.com/aeon/block/{BlockHeightPH}" }}}, - { CoinType.STAK, new Dictionary { { string.Empty, $"https://straks.info/block/{BlockHeightPH}" }}}, - { CoinType.MOON, new Dictionary { { string.Empty, $"https://chainz.cryptoid.info/moon/block.dws?{BlockHeightPH}.htm" }}}, - { CoinType.XVG, new Dictionary { { string.Empty, $"https://verge-blockchain.info/block/{BlockHashPH}" } }}, - }; - - public static readonly Dictionary TxInfoLinks = new Dictionary - { - { 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 AddressInfoLinks = new Dictionary - { - { 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> CoinAlgorithm = new Dictionary> - { - { 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> BlockInfoLinks = new Dictionary> + { + { CoinType.ETH, new Dictionary + { + { string.Empty, $"https://etherscan.io/block/{BlockHeightPH}" }, + { EthereumConstants.BlockTypeUncle, $"https://etherscan.io/uncle/{BlockHeightPH}" }, + }}, + + { CoinType.ETC, new Dictionary + { + { string.Empty, $"https://gastracker.io/block/{BlockHeightPH}" }, + { EthereumConstants.BlockTypeUncle, $"https://gastracker.io/uncle/{BlockHeightPH}" } + }}, + + { CoinType.XMR, new Dictionary { { string.Empty, $"https://chainradar.com/xmr/block/{BlockHeightPH}" }}}, + { CoinType.ETN, new Dictionary { { string.Empty, $"https://blockexplorer.electroneum.com/block/{BlockHeightPH}" } }}, + { CoinType.LTC, new Dictionary { { string.Empty, $"https://chainz.cryptoid.info/ltc/block.dws?{BlockHeightPH}.htm" } }}, + { CoinType.PPC, new Dictionary { { string.Empty, $"https://chainz.cryptoid.info/ppc/block.dws?{BlockHeightPH}.htm" } }}, + { CoinType.BCH, new Dictionary { { string.Empty, $"https://www.blocktrail.com/BCC/block/{BlockHeightPH}" }}}, + { CoinType.DASH, new Dictionary { { string.Empty, $"https://chainz.cryptoid.info/dash/block.dws?{BlockHeightPH}.htm" }}}, + { CoinType.BTC, new Dictionary { { string.Empty, $"https://blockchain.info/block/{BlockHeightPH}" }}}, + { CoinType.DOGE, new Dictionary { { string.Empty, $"https://dogechain.info/block/{BlockHeightPH}" }}}, + { CoinType.ZEC, new Dictionary { { string.Empty, $"https://explorer.zcha.in/blocks/{BlockHashPH}" } }}, + { CoinType.BTCP, new Dictionary { { string.Empty, $"http://explorer.btcprivate.org/block/{BlockHashPH}" } }}, + { CoinType.ZCL, new Dictionary { { string.Empty, $"http://explorer.zclmine.pro/block/{BlockHeightPH}" }}}, + { CoinType.ZEN, new Dictionary { { string.Empty, $"http://explorer.zensystem.io/block/{BlockHashPH}" } }}, + { CoinType.DGB, new Dictionary { { string.Empty, $"https://digiexplorer.info/block/{BlockHeightPH}" }}}, + { CoinType.NMC, new Dictionary { { string.Empty, $"https://explorer.namecoin.info/b/{BlockHeightPH}" }}}, + { CoinType.GRS, new Dictionary { { string.Empty, $"https://groestlsight.groestlcoin.org/block/{BlockHeightPH}" }}}, + { CoinType.MONA, new Dictionary { { string.Empty, $"https://bchain.info/MONA/block/{BlockHeightPH}" }}}, + { CoinType.GLT, new Dictionary { { string.Empty, $"https://bchain.info/GLT/block/{BlockHeightPH}" }}}, + { CoinType.VTC, new Dictionary { { string.Empty, $"https://bchain.info/VTC/block/{BlockHeightPH}" }}}, + { CoinType.BTG, new Dictionary { { string.Empty, $"https://btg-bitcore2.trezor.io/block/{BlockHashPH}" } }}, + { CoinType.ELLA, new Dictionary { { string.Empty, $"https://explorer.ellaism.org/block/{BlockHeightPH}" }}}, + { CoinType.EXP, new Dictionary { { string.Empty, $"http://www.gander.tech/blocks/{BlockHeightPH}" }}}, + { CoinType.AEON, new Dictionary { { string.Empty, $"https://chainradar.com/aeon/block/{BlockHeightPH}" }}}, + { CoinType.STAK, new Dictionary { { string.Empty, $"https://straks.info/block/{BlockHeightPH}" }}}, + { CoinType.MOON, new Dictionary { { string.Empty, $"https://chainz.cryptoid.info/moon/block.dws?{BlockHeightPH}.htm" }}}, + { CoinType.XVG, new Dictionary { { string.Empty, $"https://verge-blockchain.info/block/{BlockHashPH}" } }}, + }; + + public static readonly Dictionary TxInfoLinks = new Dictionary + { + { 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 AddressInfoLinks = new Dictionary + { + { 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> CoinAlgorithm = new Dictionary> + { + { 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 }, + }; + } +} diff --git a/src/MiningCore/Blockchain/Ethereum/EthereumJob.cs b/src/MiningCore/Blockchain/Ethereum/EthereumJob.cs index e6df3ac6b..5d263a308 100644 --- a/src/MiningCore/Blockchain/Ethereum/EthereumJob.cs +++ b/src/MiningCore/Blockchain/Ethereum/EthereumJob.cs @@ -49,7 +49,7 @@ private void RegisterNonce(StratumClient worker, string nonce) } } - public async Task 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 @@ public async Task ProcessShareAsync(StratumClient worker, string } // 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); + + share.TransactionConfirmationData = $"{mixDigest.ToHexString(true)}:{fullNonceHex}"; + + return (share, fullNonceHex, headerHash, mixHash); + } - return share; + return (share, null, null, null); } } } diff --git a/src/MiningCore/Blockchain/Ethereum/EthereumJobManager.cs b/src/MiningCore/Blockchain/Ethereum/EthereumJobManager.cs index e74ec4f40..a30e86c8f 100644 --- a/src/MiningCore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/MiningCore/Blockchain/Ethereum/EthereumJobManager.cs @@ -291,14 +291,14 @@ private async Task UpdateNetworkStatsAsync() BlockchainStats.ConnectedPeers = peerCount; } - private async Task SubmitBlockAsync(EthereumShare share) + private async Task SubmitBlockAsync(Share share, string fullNonceHex, string headerHash, string mixHash) { // submit work var response = await daemon.ExecuteCmdAnyAsync(EC.SubmitWork, new[] { - share.FullNonceHex, - share.HeaderHash, - share.MixHash + fullNonceHex, + headerHash, + mixHash }); if (response.Error != null || (bool?) response.Response == false) @@ -393,7 +393,7 @@ public void PrepareWorker(StratumClient client) context.ExtraNonce1 = extraNonceProvider.Next(); } - public async Task SubmitShareAsync(StratumClient worker, + public async Task SubmitShareAsync(StratumClient worker, string[] request, double stratumDifficulty, double stratumDifficultyBase) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -415,14 +415,20 @@ public async Task SubmitShareAsync(StratumClient worker, } // validate & process - var share = await job.ProcessShareAsync(worker, nonce, ethash); + var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, nonce, ethash); + + // enrich share with common data + share.PoolId = poolConfig.Id; + share.NetworkDifficulty = BlockchainStats.NetworkDifficulty; + 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); + share.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, mixHash); if (share.IsBlockCandidate) { @@ -430,12 +436,6 @@ public async Task SubmitShareAsync(StratumClient worker, } } - // enrich share with common data - share.PoolId = poolConfig.Id; - share.NetworkDifficulty = BlockchainStats.NetworkDifficulty; - share.Source = clusterConfig.ClusterName; - share.Created = clock.Now; - return share; } @@ -542,7 +542,8 @@ protected override async Task PostStartInitAsync() EthereumUtils.DetectNetworkAndChain(netVersion, parityChain, out networkType, out chainType); - ConfigureRewards(); + if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + ConfigureRewards(); // update stats BlockchainStats.RewardType = "POW"; diff --git a/src/MiningCore/Blockchain/Ethereum/EthereumPool.cs b/src/MiningCore/Blockchain/Ethereum/EthereumPool.cs index 57a11c1e4..d2bcd422f 100644 --- a/src/MiningCore/Blockchain/Ethereum/EthereumPool.cs +++ b/src/MiningCore/Blockchain/Ethereum/EthereumPool.cs @@ -42,7 +42,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace MiningCore.Blockchain.Ethereum { [CoinMetadata(CoinType.ETH, CoinType.ETC, CoinType.EXP, CoinType.ELLA)] - public class EthereumPool : PoolBase + public class EthereumPool : PoolBase { public EthereumPool(IComponentContext ctx, JsonSerializerSettings serializerSettings, diff --git a/src/MiningCore/Blockchain/Ethereum/EthereumShare.cs b/src/MiningCore/Blockchain/Ethereum/EthereumShare.cs deleted file mode 100644 index 187a4f0e4..000000000 --- a/src/MiningCore/Blockchain/Ethereum/EthereumShare.cs +++ /dev/null @@ -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; } - } -} diff --git a/src/MiningCore/Blockchain/Monero/MoneroJob.cs b/src/MiningCore/Blockchain/Monero/MoneroJob.cs index 6ea927106..7afb65d85 100644 --- a/src/MiningCore/Blockchain/Monero/MoneroJob.cs +++ b/src/MiningCore/Blockchain/Monero/MoneroJob.cs @@ -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 @@ public MoneroJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, stri 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 @@ public MoneroJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, stri PrepareBlobTemplate(instanceId); } - private readonly Func> hashSlow; + private readonly Func> hashSlow; private byte[] blobTemplate; private uint extraNonce; @@ -135,7 +136,7 @@ public void PrepareWorkerJob(MoneroWorkerJob workerJob, out string blob, out str 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(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); Contract.Requires(!string.IsNullOrEmpty(workerHash), $"{nameof(workerHash)} must not be empty"); @@ -165,8 +166,11 @@ public MoneroShare ProcessShare(string nonce, uint workerExtraNonce, string work 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 @@ public MoneroShare ProcessShare(string nonce, uint workerExtraNonce, string work 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); } } } diff --git a/src/MiningCore/Blockchain/Monero/MoneroJobManager.cs b/src/MiningCore/Blockchain/Monero/MoneroJobManager.cs index 69e7ec02a..044eb62ad 100644 --- a/src/MiningCore/Blockchain/Monero/MoneroJobManager.cs +++ b/src/MiningCore/Blockchain/Monero/MoneroJobManager.cs @@ -169,15 +169,15 @@ private async Task UpdateNetworkStatsAsync() BlockchainStats.ConnectedPeers = info.OutgoingConnectionsCount + info.IncomingConnectionsCount; } - private async Task SubmitBlockAsync(MoneroShare share) + private async Task SubmitBlockAsync(Share share, string blobHex, string blobHash) { - var response = await daemon.ExecuteCmdAnyAsync(MC.SubmitBlock, new[] { share.BlobHex }); + var response = await daemon.ExecuteCmdAnyAsync(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 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi .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 @@ public void PrepareWorkerJob(MoneroWorkerJob workerJob, out string blob, out str } } - public async Task SubmitShareAsync(StratumClient worker, + public async Task SubmitShareAsync(StratumClient worker, MoneroSubmitShareRequest request, MoneroWorkerJob workerJob, double stratumDifficultyBase) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -272,20 +275,31 @@ public async Task SubmitShareAsync(StratumClient worker, throw new StratumException(StratumError.MinusOne, "block expired"); // validate & process - var share = job?.ProcessShare(request.Nonce, workerJob.ExtraNonce, request.Hash, worker); + var (share, blobHex, blobHash) = job.ProcessShare(request.Nonce, workerJob.ExtraNonce, request.Hash, worker); + + // enrich share with common data + share.PoolId = poolConfig.Id; + share.IpAddress = worker.RemoteEndpoint.Address.ToString(); + share.Miner = context.MinerName; + share.Worker = context.WorkerName; + share.PayoutInfo = context.PaymentId; + share.UserAgent = context.UserAgent; + share.Source = clusterConfig.ClusterName; + 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} [{share.BlobHash.Substring(0, 6)}]"); + logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight} [{blobHash.Substring(0, 6)}]"); - share.IsBlockCandidate = await SubmitBlockAsync(share); + share.IsBlockCandidate = await SubmitBlockAsync(share, blobHex, blobHash); if (share.IsBlockCandidate) { - logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} [{share.BlobHash.Substring(0, 6)}] submitted by {context.MinerName}"); + logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} [{blobHash.Substring(0, 6)}] submitted by {context.MinerName}"); - share.TransactionConfirmationData = share.BlobHash; + share.TransactionConfirmationData = blobHash; } else @@ -295,17 +309,6 @@ public async Task SubmitShareAsync(StratumClient worker, } } - // enrich share with common data - share.PoolId = poolConfig.Id; - share.IpAddress = worker.RemoteEndpoint.Address.ToString(); - share.Miner = context.MinerName; - share.Worker = context.WorkerName; - share.PayoutInfo = context.PaymentId; - share.UserAgent = context.UserAgent; - share.Source = clusterConfig.ClusterName; - share.NetworkDifficulty = job.BlockTemplate.Difficulty; - share.Created = clock.Now; - return share; } @@ -322,9 +325,12 @@ protected override void ConfigureDaemons() 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 AreDaemonsHealthyAsync() @@ -340,15 +346,20 @@ protected override async Task AreDaemonsHealthyAsync() if (!responses.All(x => x.Error == null)) return false; - // test wallet daemons - var responses2 = await walletDaemon.ExecuteCmdAllAsync(MWC.GetAddress); + if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // test wallet daemons + var responses2 = await walletDaemon.ExecuteCmdAllAsync(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 AreDaemonsConnectedAsync() @@ -398,14 +409,18 @@ protected override async Task EnsureDaemonsSynchedAsync() protected override async Task PostStartInitAsync() { var infoResponse = await daemon.ExecuteCmdAnyAsync(MC.GetInfo); - var addressResponse = await walletDaemon.ExecuteCmdAnyAsync(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(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(); @@ -430,7 +445,8 @@ protected override async Task PostStartInitAsync() break; } - ConfigureRewards(); + if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + ConfigureRewards(); // update stats BlockchainStats.RewardType = "POW"; diff --git a/src/MiningCore/Blockchain/Monero/MoneroPool.cs b/src/MiningCore/Blockchain/Monero/MoneroPool.cs index 4be9ade41..b640c5050 100644 --- a/src/MiningCore/Blockchain/Monero/MoneroPool.cs +++ b/src/MiningCore/Blockchain/Monero/MoneroPool.cs @@ -43,7 +43,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace MiningCore.Blockchain.Monero { [CoinMetadata(CoinType.XMR, CoinType.AEON, CoinType.ETN)] - public class MoneroPool : PoolBase + public class MoneroPool : PoolBase { public MoneroPool(IComponentContext ctx, JsonSerializerSettings serializerSettings, diff --git a/src/MiningCore/Blockchain/Monero/MoneroShare.cs b/src/MiningCore/Blockchain/Monero/MoneroShare.cs deleted file mode 100644 index 7c35f14e1..000000000 --- a/src/MiningCore/Blockchain/Monero/MoneroShare.cs +++ /dev/null @@ -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; } - } -} diff --git a/src/MiningCore/Blockchain/Share.cs b/src/MiningCore/Blockchain/Share.cs new file mode 100644 index 000000000..d29d97a4b --- /dev/null +++ b/src/MiningCore/Blockchain/Share.cs @@ -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 + { + /// + /// The pool originating this share from + /// + [ProtoMember(1)] + public string PoolId { get; set; } + + /// + /// Who mined it (wallet address) + /// + [ProtoMember(2)] + public string Miner { get; set; } + + /// + /// Who mined it + /// + [ProtoMember(3)] + public string Worker { get; set; } + + /// + /// Extra information for payout processing + /// + [ProtoMember(4)] + public string PayoutInfo { get; set; } + + /// + /// Mining Software + /// + [ProtoMember(5)] + public string UserAgent { get; set; } + + /// + /// From where was it submitted + /// + [ProtoMember(6)] + public string IpAddress { get; set; } + + /// + /// Submission source (pool, external stratum etc) + /// + [ProtoMember(7)] + public string Source { get; set; } + + /// + /// Stratum difficulty assigned to the miner at the time the share was submitted/accepted (used for payout + /// calculations) + /// + [ProtoMember(8)] + public double Difficulty { get; set; } + + /// + /// Block this share refers to + /// + [ProtoMember(9)] + public long BlockHeight { get; set; } + + /// + /// Block reward after deducting pool fee and donations + /// + [ProtoMember(10)] + public decimal BlockReward { get; set; } + + /// + /// Block hash + /// + [ProtoMember(11)] + public string BlockHash { get; set; } + + /// + /// If this share presumably resulted in a block + /// + [ProtoMember(12)] + public bool IsBlockCandidate { get; set; } + + /// + /// Arbitrary data to be interpreted by the payment processor specialized + /// in this coin to verify this block candidate was accepted by the network + /// + [ProtoMember(13)] + public string TransactionConfirmationData { get; set; } + + /// + /// Network difficulty at the time the share was submitted (used for some payout schemes like PPLNS) + /// + [ProtoMember(14)] + public double NetworkDifficulty { get; set; } + + /// + /// When the share was found + /// + [ProtoMember(15)] + public DateTime Created { get; set; } + } +} diff --git a/src/MiningCore/Blockchain/ShareBase.cs b/src/MiningCore/Blockchain/ShareBase.cs deleted file mode 100644 index fd00a6582..000000000 --- a/src/MiningCore/Blockchain/ShareBase.cs +++ /dev/null @@ -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; } - } -} diff --git a/src/MiningCore/Blockchain/ZCash/ZCashJob.cs b/src/MiningCore/Blockchain/ZCash/ZCashJob.cs index ad4bb386d..2049d9b05 100644 --- a/src/MiningCore/Blockchain/ZCash/ZCashJob.cs +++ b/src/MiningCore/Blockchain/ZCash/ZCashJob.cs @@ -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 @@ public override void Init(ZCashBlockTemplate blockTemplate, string jobId, #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(!string.IsNullOrEmpty(extraNonce2), $"{nameof(extraNonce2)} must not be empty"); @@ -295,7 +293,7 @@ protected byte[] SerializeBlock(byte[] header, byte[] coinbase, byte[] solution) } } - 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(); @@ -341,22 +339,26 @@ protected virtual BitcoinShare ProcessShareInternal(StratumClient worker, string 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) diff --git a/src/MiningCore/Blockchain/ZCash/ZCashJobManager.cs b/src/MiningCore/Blockchain/ZCash/ZCashJobManager.cs index b0c7ca7f4..e091c411e 100644 --- a/src/MiningCore/Blockchain/ZCash/ZCashJobManager.cs +++ b/src/MiningCore/Blockchain/ZCash/ZCashJobManager.cs @@ -106,7 +106,7 @@ protected override IDestination AddressToDestination(string address) return result; } - public override async Task SubmitShareAsync(StratumClient worker, object submission, + public override async Task SubmitShareAsync(StratumClient worker, object submission, double stratumDifficultyBase) { Contract.RequiresNonNull(worker, nameof(worker)); @@ -148,14 +148,14 @@ public override async Task SubmitShareAsync(StratumClient worker, 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; diff --git a/src/MiningCore/Mining/Abstractions.cs b/src/MiningCore/Mining/Abstractions.cs index 686dde3a6..2264af804 100644 --- a/src/MiningCore/Mining/Abstractions.cs +++ b/src/MiningCore/Mining/Abstractions.cs @@ -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 diff --git a/src/MiningCore/Mining/PoolBase.cs b/src/MiningCore/Mining/PoolBase.cs index 2342b47e4..b5125028c 100644 --- a/src/MiningCore/Mining/PoolBase.cs +++ b/src/MiningCore/Mining/PoolBase.cs @@ -52,9 +52,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace MiningCore.Mining { - public abstract class PoolBase : StratumServer, + public abstract class PoolBase : StratumServer, IMiningPool - where TShare: IShare { protected PoolBase(IComponentContext ctx, JsonSerializerSettings serializerSettings, @@ -139,107 +138,6 @@ private void EnsureNoZombieClient(StratumClient client) }); } - 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(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 @@ public virtual void Configure(PoolConfig poolConfig, ClusterConfig clusterConfig Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); - logger = LogUtil.GetPoolScopedLogger(typeof(PoolBase), poolConfig); + logger = LogUtil.GetPoolScopedLogger(typeof(PoolBase), poolConfig); this.poolConfig = poolConfig; this.clusterConfig = clusterConfig; } @@ -442,9 +340,6 @@ public virtual async Task StartAsync() StartListeners(poolConfig.Id, ipEndpoints); } - if(poolConfig.ExternalStratums?.Length > 0) - StartExternalStratumPublisherListeners(); - logger.Info(() => $"[{LogCat}] Online"); OutputPoolInfo(); } diff --git a/src/MiningCore/Payments/ShareRecorder.cs b/src/MiningCore/Mining/ShareRecorder.cs similarity index 59% rename from src/MiningCore/Payments/ShareRecorder.cs rename to src/MiningCore/Mining/ShareRecorder.cs index 26257ce2c..b0a5d433d 100644 --- a/src/MiningCore/Payments/ShareRecorder.cs +++ b/src/MiningCore/Mining/ShareRecorder.cs @@ -28,23 +28,29 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 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 { /// /// Asynchronously persist shares produced by all pools for processing by coin-specific payment processor(s) @@ -54,6 +60,7 @@ public class ShareRecorder 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 @@ public ShareRecorder(IConnectionFactory cf, IMapper mapper, 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 @@ public ShareRecorder(IConnectionFactory cf, IMapper mapper, 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 queue = new BlockingCollection(); + private readonly ConcurrentDictionary pools = new ConcurrentDictionary(); + private readonly BlockingCollection queue = new BlockingCollection(); + + 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 @@ public ShareRecorder(IConnectionFactory cf, IMapper mapper, private const string PolicyContextKeyShares = "share"; private bool notifiedAdminOnPolicyFallback = false; - private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); - - private void PersistSharesFaulTolerant(IList shares) + private void PersistSharesFaulTolerant(IList shares) { var context = new Dictionary { { PolicyContextKeyShares, shares } }; faultPolicy.Execute(() => { PersistShares(shares); }, context); } - private void PersistShares(IList shares) + private void PersistShares(IList shares) { cf.RunTx((con, tx) => { foreach(var share in shares) { - var shareEntity = mapper.Map(share); + var shareEntity = mapper.Map(share); shareRepo.Insert(con, tx, shareEntity); if (share.IsBlockCandidate) @@ -136,7 +160,7 @@ private void OnPolicyFallback(Exception ex, Context context) private void OnExecutePolicyFallback(Context context) { - var shares = (IList) context[PolicyContextKeyShares]; + var shares = (IList) context[PolicyContextKeyShares]; try { @@ -189,7 +213,7 @@ public void RecoverShares(ClusterConfig clusterConfig, string recoveryFilename) { using(var reader = new StreamReader(stream, new UTF8Encoding(false))) { - var shares = new List(); + var shares = new List(); var lastProgressUpdate = DateTime.UtcNow; while(!reader.EndOfStream) @@ -207,7 +231,7 @@ public void RecoverShares(ClusterConfig clusterConfig, string recoveryFilename) // parse try { - var share = JsonConvert.DeserializeObject(line, jsonSerializerSettings); + var share = JsonConvert.DeserializeObject(line, jsonSerializerSettings); shares.Add(share); } @@ -289,10 +313,167 @@ private void NotifyAdminOnPolicyFallback() } } + 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) arg; + var url = urlAndTopic.Key; + var topics = new HashSet(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(jreader); + } + } + } + break; + + case ShareRelay.WireFormat.ProtocolBuffers: + using (var stream = new MemoryStream(data)) + { + share = Serializer.Deserialize(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 @@ public void Start(ClusterConfig clusterConfig) ConfigureRecovery(); InitializeQueue(); + StartExternalStratumPublisherListeners(); logger.Info(() => "Online"); } diff --git a/src/MiningCore/Payments/ShareRelay.cs b/src/MiningCore/Mining/ShareRelay.cs similarity index 80% rename from src/MiningCore/Payments/ShareRelay.cs rename to src/MiningCore/Mining/ShareRelay.cs index 10e82644c..3bd7669cc 100644 --- a/src/MiningCore/Payments/ShareRelay.cs +++ b/src/MiningCore/Mining/ShareRelay.cs @@ -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 @@ public ShareRelay(JsonSerializerSettings serializerSettings) } private ClusterConfig clusterConfig; - private readonly BlockingCollection queue = new BlockingCollection(); + private readonly BlockingCollection queue = new BlockingCollection(); private IDisposable queueSub; private readonly int QueueSizeWarningThreshold = 1024; private bool hasWarnedAboutBacklogSize; @@ -32,6 +30,15 @@ public ShareRelay(JsonSerializerSettings serializerSettings) 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 @@ private void InitializeQueue() 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); } diff --git a/src/MiningCore/MiningCore.csproj b/src/MiningCore/MiningCore.csproj index 74b9172f3..797efb61d 100644 --- a/src/MiningCore/MiningCore.csproj +++ b/src/MiningCore/MiningCore.csproj @@ -46,21 +46,22 @@ - + - - - + + + - - - + + + - + - - + + + diff --git a/src/MiningCore/Native/LibCryptonote.cs b/src/MiningCore/Native/LibCryptonote.cs index 165fcd11e..fbb36d543 100644 --- a/src/MiningCore/Native/LibCryptonote.cs +++ b/src/MiningCore/Native/LibCryptonote.cs @@ -39,7 +39,7 @@ public static unsafe class LibCryptonote 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 @@ public static UInt64 DecodeIntegratedAddress(string address) } } - public static PooledArraySegment CryptonightHashSlow(byte[] data) + public static PooledArraySegment CryptonightHashSlow(byte[] data, int variant) { Contract.RequiresNonNull(data, nameof(data)); @@ -134,7 +134,7 @@ public static PooledArraySegment CryptonightHashSlow(byte[] data) { fixed(byte* output = result.Array) { - cn_slow_hash(input, output, (uint) data.Length); + cn_slow_hash(input, output, (uint) data.Length, variant); } } diff --git a/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs b/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs index 0974ed0df..4b6718031 100644 --- a/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -46,7 +46,7 @@ public StatsRepository(IMapper mapper, IMasterClock clock) 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 @@ public MinerStats GetMinerStats(IDbConnection con, IDbTransaction tx, string poo var lastUpdate = con.QuerySingleOrDefault(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) diff --git a/src/MiningCore/Program.cs b/src/MiningCore/Program.cs index 0d2bc8677..cb991e461 100644 --- a/src/MiningCore/Program.cs +++ b/src/MiningCore/Program.cs @@ -647,7 +647,7 @@ private static void OnAppDomainUnhandledException(object sender, UnhandledExcept 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()); } diff --git a/src/MiningCore/Properties/launchSettings.json b/src/MiningCore/Properties/launchSettings.json index 72807c195..9218cd2b3 100644 --- a/src/MiningCore/Properties/launchSettings.json +++ b/src/MiningCore/Properties/launchSettings.json @@ -1,8 +1,8 @@ -{ - "profiles": { - "MiningCore": { - "commandName": "Project", - "commandLineArgs": "-c config.json" - } - } +{ + "profiles": { + "MiningCore": { + "commandName": "Project", + "commandLineArgs": "-c ..\\..\\..\\config.json" + } + } } \ No newline at end of file diff --git a/src/MiningCore/runtimes/win-x64/native/libcryptonote.dll b/src/MiningCore/runtimes/win-x64/native/libcryptonote.dll index 15a282c49..8d1a1fa94 100644 Binary files a/src/MiningCore/runtimes/win-x64/native/libcryptonote.dll and b/src/MiningCore/runtimes/win-x64/native/libcryptonote.dll differ diff --git a/src/MiningCore/runtimes/win-x86/native/libcryptonote.dll b/src/MiningCore/runtimes/win-x86/native/libcryptonote.dll index 1f4803a9d..bc0245ed5 100644 Binary files a/src/MiningCore/runtimes/win-x86/native/libcryptonote.dll and b/src/MiningCore/runtimes/win-x86/native/libcryptonote.dll differ diff --git a/src/Native/libcryptonote/Makefile b/src/Native/libcryptonote/Makefile index 17df8a373..0cd26e4c2 100644 --- a/src/Native/libcryptonote/Makefile +++ b/src/Native/libcryptonote/Makefile @@ -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 \ diff --git a/src/Native/libcryptonote/Makefile.MSys2 b/src/Native/libcryptonote/Makefile.MSys2 index 5b0eb9e5f..a04d38435 100644 --- a/src/Native/libcryptonote/Makefile.MSys2 +++ b/src/Native/libcryptonote/Makefile.MSys2 @@ -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 \ diff --git a/src/Native/libcryptonote/common/base58.cpp b/src/Native/libcryptonote/common/base58.cpp index 43208c1bf..75556cad9 100644 --- a/src/Native/libcryptonote/common/base58.cpp +++ b/src/Native/libcryptonote/common/base58.cpp @@ -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); } diff --git a/src/Native/libcryptonote/common/base58.h b/src/Native/libcryptonote/common/base58.h index 6dd850c03..02ca96956 100644 --- a/src/Native/libcryptonote/common/base58.h +++ b/src/Native/libcryptonote/common/base58.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/common/int-util.h b/src/Native/libcryptonote/common/int-util.h index ff1340dc2..3bcc085e2 100644 --- a/src/Native/libcryptonote/common/int-util.h +++ b/src/Native/libcryptonote/common/int-util.h @@ -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 #include -#if !defined(_MSC_VER) +#ifndef _MSC_VER #include #endif @@ -43,6 +43,10 @@ #include #endif +#if defined(__sun) && defined(__SVR4) +#include +#endif + #if defined(_MSC_VER) #include @@ -205,13 +209,14 @@ static inline void memcpy_swap64(void *dst, const void *src, size_t n) { } } +#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) -#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 -#endif #endif #if BYTE_ORDER == LITTLE_ENDIAN diff --git a/src/Native/libcryptonote/common/pod-class.h b/src/Native/libcryptonote/common/pod-class.h index 3896d5c29..5f6709eef 100644 --- a/src/Native/libcryptonote/common/pod-class.h +++ b/src/Native/libcryptonote/common/pod-class.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/common/util.h b/src/Native/libcryptonote/common/util.h new file mode 100644 index 000000000..d3ba47a4f --- /dev/null +++ b/src/Native/libcryptonote/common/util.h @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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 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 + 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 lock(m_mutex); + m_handler(type); + } + + /*! \brief where the installed handler is stored */ + static std::function 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); +} diff --git a/src/Native/libcryptonote/common/varint.h b/src/Native/libcryptonote/common/varint.h index cb785e61a..151d13dbf 100644 --- a/src/Native/libcryptonote/common/varint.h +++ b/src/Native/libcryptonote/common/varint.h @@ -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(byte & 0x7f) << shift; /* Does the actualy placing into write, stripping the first bit */ + write |= static_cast(byte & 0x7f) << shift; /* Does the actually placing into write, stripping the first bit */ /* If there is no next */ if ((byte & 0x80) == 0) { diff --git a/src/Native/libcryptonote/contrib/epee/include/console_handler.h b/src/Native/libcryptonote/contrib/epee/include/console_handler.h index b8336b270..4ea3fa54b 100644 --- a/src/Native/libcryptonote/contrib/epee/include/console_handler.h +++ b/src/Native/libcryptonote/contrib/epee/include/console_handler.h @@ -27,6 +27,7 @@ #pragma once #include "misc_log_ex.h" +#include "string_tools.h" #include #include #include @@ -37,6 +38,8 @@ #include #endif #include +#include +#include #ifdef HAVE_READLINE #include "readline_buffer.h" @@ -456,29 +459,35 @@ namespace epee class command_handler { public: typedef boost::function &)> callback; - typedef std::map > lookup; + typedef std::map>> 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 get_documentation(const std::vector& 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 diff --git a/src/Native/libcryptonote/contrib/epee/include/copyable_atomic.h b/src/Native/libcryptonote/contrib/epee/include/copyable_atomic.h index 410b4b4ff..00a5f484b 100644 --- a/src/Native/libcryptonote/contrib/epee/include/copyable_atomic.h +++ b/src/Native/libcryptonote/contrib/epee/include/copyable_atomic.h @@ -35,6 +35,8 @@ namespace epee public: copyable_atomic() {}; + copyable_atomic(uint32_t value) + { store(value); } copyable_atomic(const copyable_atomic& a):std::atomic(a.load()) {} copyable_atomic& operator= (const copyable_atomic& a) diff --git a/src/Native/libcryptonote/contrib/epee/include/file_io_utils.h b/src/Native/libcryptonote/contrib/epee/include/file_io_utils.h index c387743a6..196610674 100644 --- a/src/Native/libcryptonote/contrib/epee/include/file_io_utils.h +++ b/src/Native/libcryptonote/contrib/epee/include/file_io_utils.h @@ -29,7 +29,33 @@ #define _FILE_IO_UTILS_H_ #include -#include +#include +#include +#ifdef WIN32 +#include +#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 + } + } } diff --git a/src/Native/libcryptonote/contrib/epee/include/hex.h b/src/Native/libcryptonote/contrib/epee/include/hex.h index f8d6be048..e960da1d2 100644 --- a/src/Native/libcryptonote/contrib/epee/include/hex.h +++ b/src/Native/libcryptonote/contrib/epee/include/hex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017, The Monero Project +// Copyright (c) 2017-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/contrib/epee/include/math_helper.h b/src/Native/libcryptonote/contrib/epee/include/math_helper.h index 90398acbb..ef839f609 100644 --- a/src/Native/libcryptonote/contrib/epee/include/math_helper.h +++ b/src/Native/libcryptonote/contrib/epee/include/math_helper.h @@ -37,6 +37,7 @@ #include #include "misc_os_dependent.h" +#include "syncobj.h" namespace epee { diff --git a/src/Native/libcryptonote/contrib/epee/include/memwipe.h b/src/Native/libcryptonote/contrib/epee/include/memwipe.h new file mode 100644 index 000000000..0d8f491b7 --- /dev/null +++ b/src/Native/libcryptonote/contrib/epee/include/memwipe.h @@ -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 + +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 + struct scrubbed : public T { + using type = T; + + ~scrubbed() { + scrub(); + } + + /// Destroy the contents of the contained type. + void scrub() { + static_assert(std::is_pod::value, + "T cannot be auto-scrubbed. T must be POD."); + static_assert(std::is_trivially_destructible::value, + "T cannot be auto-scrubbed. T must be trivially destructable."); + memwipe(this, sizeof(T)); + } + }; + + template + T& unwrap(scrubbed& src) { return src; } + + template + const T& unwrap(scrubbed const& src) { return src; } + + template + using scrubbed_arr = scrubbed>; +} // namespace tools + +#endif // __cplusplus diff --git a/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h b/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h index 69ded09e5..ffe575501 100644 --- a/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h +++ b/src/Native/libcryptonote/contrib/epee/include/misc_os_dependent.h @@ -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 +#endif + #ifdef WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -42,6 +46,9 @@ #include #endif +#include +#include + #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 } diff --git a/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server.h b/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server.h index 000305cfa..cbad1717c 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server.h @@ -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; } diff --git a/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.h b/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.h index ca58d5467..ccde928ba 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.h @@ -54,8 +54,8 @@ #include #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 - 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 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> connections_; + std::set connections_; }; // class <>boosted_tcp_server diff --git a/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.inl b/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.inl index 61276e761..195ee2f0c 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/src/Native/libcryptonote/contrib/epee/include/net/abstract_tcp_server2.inl @@ -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="<(); - 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(); - 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(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::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 - bool boosted_tcp_server::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 bool boosted_tcp_server::is_stop_signal_sent() { return m_stop_signal_sent; @@ -942,6 +935,9 @@ POP_WARNINGS boost::bind(&boosted_tcp_server::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(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 template - bool boosted_tcp_server::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::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(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) { diff --git a/src/Native/libcryptonote/contrib/epee/include/net/connection_basic.hpp b/src/Native/libcryptonote/contrib/epee/include/net/connection_basic.hpp new file mode 100644 index 000000000..095e747a5 --- /dev/null +++ b/src/Native/libcryptonote/contrib/epee/include/net/connection_basic.hpp @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 m_was_shutdown; + critical_section m_send_que_lock; + std::list 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 &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 &ref_sock_count, std::atomic &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 + + diff --git a/src/Native/libcryptonote/contrib/epee/include/net/http_auth.h b/src/Native/libcryptonote/contrib/epee/include/net/http_auth.h index bf368e6f4..4324c41fd 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/http_auth.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/http_auth.h @@ -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 #include #include - +#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 r); //! \return Auth response, or `boost::none` iff `request` had valid auth. boost::optional 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 do_get_response(const http_request_info& request); boost::optional user; + + std::function rng; }; //! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added. diff --git a/src/Native/libcryptonote/contrib/epee/include/net/http_base.h b/src/Native/libcryptonote/contrib/epee/include/net/http_base.h index e5aa06cb4..a66fb7c23 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/http_base.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/http_base.h @@ -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; diff --git a/src/Native/libcryptonote/contrib/epee/include/net/http_client.h b/src/Native/libcryptonote/contrib/epee/include/net/http_client.h index 8e099e2bc..1edf65928 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/http_client.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/http_client.h @@ -27,6 +27,7 @@ #pragma once +#include #include #include #include @@ -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 + 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 user) + bool set_server(const std::string& address, boost::optional 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 user) + void set_server(std::string host, std::string port, boost::optional 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) - { + 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 char *ptr = m_cache_to_process.c_str(); + while (ptr[0] != '\r' || ptr[1] != '\n') { - 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); + // 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); } - 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:"<(result[1]); - m_response_info.m_http_ver_lo = boost::lexical_cast(result[2]); - m_response_info.m_response_code = boost::lexical_cast(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; - } - + //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 http_simple_client; } } } diff --git a/src/Native/libcryptonote/contrib/epee/include/net/http_client_base.h b/src/Native/libcryptonote/contrib/epee/include/net/http_client_base.h index f5fb57d03..c3da28718 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/http_client_base.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/http_client_base.h @@ -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) { } diff --git a/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.h b/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.h index babe49ad7..b4485d1cd 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.h @@ -54,6 +54,7 @@ namespace net_utils struct http_server_config { std::string m_folder; + std::vector m_access_control_origins; boost::optional 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* m_phandler; + std::function rng; }; /************************************************************************/ @@ -175,7 +177,7 @@ namespace net_utils : simple_http_connection_handler(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); } diff --git a/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.inl b/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.inl index c92a13bcc..c18f7f706 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.inl +++ b/src/Native/libcryptonote/contrib/epee/include/net/http_protocol_handler.inl @@ -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(result[11]); http_ver_minor = boost::lexical_cast(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::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(result[field_etc_name], result[field_val])); else @@ -537,17 +547,27 @@ namespace net_utils template bool simple_http_connection_handler::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(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"; diff --git a/src/Native/libcryptonote/contrib/epee/include/net/http_server_impl_base.h b/src/Native/libcryptonote/contrib/epee/include/net/http_server_impl_base.h index acecbb2d4..1a97e610a 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/http_server_impl_base.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/http_server_impl_base.h @@ -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 rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0", + std::vector access_control_origins = std::vector(), boost::optional user = boost::none) { //set self as callback handler m_net_server.get_config_object().m_phandler = static_cast(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 > m_net_server; }; diff --git a/src/Native/libcryptonote/contrib/epee/include/net/levin_base.h b/src/Native/libcryptonote/contrib/epee/include/net/levin_base.h index d630bff19..7d060f5ef 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/levin_base.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/levin_base.h @@ -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 diff --git a/src/Native/libcryptonote/contrib/epee/include/net/levin_client_async.h b/src/Native/libcryptonote/contrib/epee/include/net/levin_client_async.h index 337d345c4..6c8f9bcb3 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/levin_client_async.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/levin_client_async.h @@ -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) diff --git a/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler.h b/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler.h index fbc9727e2..b3a75bedc 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler.h @@ -43,6 +43,8 @@ namespace levin struct protocl_handler_config { levin_commands_handler* m_pcommands_handler; + void (*m_pcommands_handler_destroy)(levin_commands_handler*); + ~protocl_handler_config() { if (m_pcommands_handler && m_pcommands_handler_destroy) (*m_pcommands_handler_destroy)(m_pcommands_handler); } }; template diff --git a/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler_async.h b/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler_async.h index 60a667690..0b1fe05fa 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/levin_protocol_handler_async.h @@ -35,6 +35,8 @@ #include "levin_base.h" #include "misc_language.h" +#include "syncobj.h" +#include "misc_os_dependent.h" #include #include @@ -72,29 +74,36 @@ class async_protocol_handler_config friend class async_protocol_handler; + levin_commands_handler* m_pcommands_handler; + void (*m_pcommands_handler_destroy)(levin_commands_handler*); + + void delete_connections (size_t count, bool incoming); + public: typedef t_connection_context connection_context; - levin_commands_handler* 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 - 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 - bool foreach_connection(callback_t cb); + bool foreach_connection(const callback_t &cb); template - 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* handler, void (*destroy)(levin_commands_handler*) = 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 @@ class async_protocol_handler std::list > m_invoke_response_handlers; template - 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 handler(boost::make_shared>(cb, timeout, con, command)); @@ -373,12 +382,16 @@ class async_protocol_handler 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 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 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 @@ class async_protocol_handler } template - 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::del_connection(async_p } //------------------------------------------------------------------------------------------ template +void async_protocol_handler_config::delete_connections(size_t count, bool incoming) +{ + std::vector 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 *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 void async_protocol_handler_config::del_out_connections(size_t count) { - std::vector 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 +void async_protocol_handler_config::del_in_connections(size_t count) +{ + delete_connections(count, true); } //------------------------------------------------------------------------------------------ template @@ -786,7 +817,7 @@ int async_protocol_handler_config::invoke(int command, con } //------------------------------------------------------------------------------------------ template template -int async_protocol_handler_config::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::invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout) { async_protocol_handler* aph; int r = find_and_lock_connection(connection_id, aph); @@ -794,7 +825,7 @@ int async_protocol_handler_config::invoke_async(int comman } //------------------------------------------------------------------------------------------ template template -bool async_protocol_handler_config::foreach_connection(callback_t cb) +bool async_protocol_handler_config::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::foreach_connection(cal } //------------------------------------------------------------------------------------------ template template -bool async_protocol_handler_config::for_connection(const boost::uuids::uuid &connection_id, callback_t cb) +bool async_protocol_handler_config::for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb) { CRITICAL_REGION_LOCAL(m_connects_lock); async_protocol_handler* aph = find_connection(connection_id); @@ -826,6 +857,15 @@ size_t async_protocol_handler_config::get_connections_coun } //------------------------------------------------------------------------------------------ template +void async_protocol_handler_config::set_handler(levin_commands_handler* handler, void (*destroy)(levin_commands_handler*)) +{ + 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 int async_protocol_handler_config::notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id) { async_protocol_handler* aph; diff --git a/src/Native/libcryptonote/contrib/epee/include/net/net_helper.h b/src/Native/libcryptonote/contrib/epee/include/net/net_helper.h index 1d808cc4c..2c2efcd82 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/net_helper.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/net_helper.h @@ -31,21 +31,16 @@ //#include //#include -#include -#include -#include -#include #include +#include #include +#include #include -#include #include #include #include #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 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. diff --git a/src/Native/libcryptonote/contrib/epee/include/net/net_parse_helpers.h b/src/Native/libcryptonote/contrib/epee/include/net/net_parse_helpers.h index 08d2a2000..708cce0ff 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/net_parse_helpers.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/net_parse_helpers.h @@ -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; diff --git a/src/Native/libcryptonote/contrib/epee/include/net/net_utils_base.h b/src/Native/libcryptonote/contrib/epee/include/net/net_utils_base.h index ef3a1d146..7615786be 100644 --- a/src/Native/libcryptonote/contrib/epee/include/net/net_utils_base.h +++ b/src/Native/libcryptonote/contrib/epee/include/net/net_utils_base.h @@ -29,12 +29,11 @@ #ifndef _NET_UTILS_BASE_H_ #define _NET_UTILS_BASE_H_ -#include -#include #include +#include +#include +#include #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(this_ref).init_ids(); END_KV_SERIALIZE_MAP() }; - class network_address: public boost::shared_ptr + + 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 + 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&>(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 self; + + template + Type& as_mutable() const + { + // types `implmentation` and `implementation` are unique + using Type_ = typename std::remove_const::type; + network_address::interface* const self_ = self.get(); // avoid clang warning in typeid + if (!self_ || typeid(implementation) != typeid(*self_)) + throw std::bad_cast{}; + return static_cast*>(self_)->value; + } public: - network_address() {} - network_address(ipv4_network_address *address): boost::shared_ptr(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() : ""; } - std::string host_str() const { return (*this) ? (*this)->host_str() : ""; } - 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 Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); } - template 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 + network_address(const T& src) + : self(std::make_shared>(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() : ""; } + std::string host_str() const { return self ? self->host_str() : ""; } + 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 const Type &as() const { return as_mutable(); } BEGIN_KV_SERIALIZE_MAP() uint8_t type = is_store ? this_ref.get_type_id() : 0; - epee::serialization::selector::serialize(type, stg, hparent_section, "type"); + if (!epee::serialization::selector::serialize(type, stg, hparent_section, "type")) + return false; switch (type) { case ipv4_network_address::ID: + { if (!is_store) - const_cast(this_ref).reset(new ipv4_network_address(0, 0)); - KV_SERIALIZE(template as()); + { + const_cast(this_ref) = ipv4_network_address{0, 0}; + auto &addr = this_ref.template as_mutable(); + if (epee::serialization::selector::serialize(addr, stg, hparent_section, "addr")) + MDEBUG("Found as addr: " << this_ref.str()); + else if (epee::serialization::selector::serialize(addr, stg, hparent_section, "template as()")) + MDEBUG("Found as template as(): " << this_ref.str()); + else if (epee::serialization::selector::serialize(addr, stg, hparent_section, "template as_mutable()")) + MDEBUG("Found as template as_mutable(): " << this_ref.str()); + else + { + MWARNING("Address not found"); + return false; + } + } + else + { + auto &addr = this_ref.template as_mutable(); + if (!epee::serialization::selector::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) { diff --git a/src/Native/libcryptonote/contrib/epee/include/net/network_throttle-detail.hpp b/src/Native/libcryptonote/contrib/epee/include/net/network_throttle-detail.hpp new file mode 100644 index 000000000..955668d62 --- /dev/null +++ b/src/Native/libcryptonote/contrib/epee/include/net/network_throttle-detail.hpp @@ -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 + + diff --git a/src/Native/libcryptonote/contrib/epee/include/net/network_throttle.hpp b/src/Native/libcryptonote/contrib/epee/include/net/network_throttle.hpp new file mode 100644 index 000000000..7df79a908 --- /dev/null +++ b/src/Native/libcryptonote/contrib/epee/include/net/network_throttle.hpp @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "syncobj.h" + +#include "net/net_utils_base.h" +#include "misc_log_ex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "misc_language.h" +#include "pragma_comp_defs.h" +#include +#include +#include + +#include +#include +#include + +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 + + + diff --git a/src/Native/libcryptonote/contrib/epee/include/profile_tools.h b/src/Native/libcryptonote/contrib/epee/include/profile_tools.h index f285fe48b..a0b5f77f4 100644 --- a/src/Native/libcryptonote/contrib/epee/include/profile_tools.h +++ b/src/Native/libcryptonote/contrib/epee/include/profile_tools.h @@ -28,6 +28,8 @@ #ifndef _PROFILE_TOOLS_H_ #define _PROFILE_TOOLS_H_ +#include "misc_os_dependent.h" + namespace epee { diff --git a/src/Native/libcryptonote/contrib/epee/include/readline_buffer.h b/src/Native/libcryptonote/contrib/epee/include/readline_buffer.h index cda7e34f9..87c8826cb 100644 --- a/src/Native/libcryptonote/contrib/epee/include/readline_buffer.h +++ b/src/Native/libcryptonote/contrib/epee/include/readline_buffer.h @@ -2,9 +2,7 @@ #include #include -#include #include -#include namespace rdln { diff --git a/src/Native/libcryptonote/contrib/epee/include/reg_exp_definer.h b/src/Native/libcryptonote/contrib/epee/include/reg_exp_definer.h index e2bed5c3f..eb11c9e10 100644 --- a/src/Native/libcryptonote/contrib/epee/include/reg_exp_definer.h +++ b/src/Native/libcryptonote/contrib/epee/include/reg_exp_definer.h @@ -29,7 +29,7 @@ #define _REG_EXP_DEFINER_H_ #include - +#include "syncobj.h" namespace epee { diff --git a/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization.h b/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization.h index d4413a71b..5791e1998 100644 --- a/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization.h +++ b/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization.h @@ -31,7 +31,6 @@ #include "misc_log_ex.h" #include "enableable.h" #include "keyvalue_serialization_overloads.h" -#include "serialization/serialization.h" namespace epee { diff --git a/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 1a58cab99..7087136cc 100644 --- a/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/src/Native/libcryptonote/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -26,6 +26,13 @@ #pragma once +#include +#include +#include +#include +#include +#include + namespace epee { namespace serialization @@ -73,7 +80,7 @@ namespace epee template 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& 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 @@ -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 + static bool kv_serialize(const std::deque& 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 + static bool kv_unserialize(std::deque& 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 static bool kv_serialize(const std::list& 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 + static bool kv_serialize(const std::set& 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 + static bool kv_unserialize(std::set& 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 @@ -268,6 +299,18 @@ namespace epee } //------------------------------------------------------------------------------------------------------------------- template + static bool kv_serialize(const std::deque& 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 + static bool kv_unserialize(std::deque& 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 static bool kv_serialize(const std::list& 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 + static bool kv_serialize(const std::set& 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 + static bool kv_unserialize(std::set& 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 struct base_serializable_types: public boost::mpl::vector::type @@ -353,6 +408,18 @@ namespace epee } //------------------------------------------------------------------------------------------------------------------- template + bool kv_serialize(const std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template bool kv_serialize(const std::list& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) { return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(d, stg, hparent_section, pname); @@ -363,5 +430,17 @@ namespace epee { return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_serialize(const std::set& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(std::set& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); + } } } diff --git a/src/Native/libcryptonote/contrib/epee/include/span.h b/src/Native/libcryptonote/contrib/epee/include/span.h index ea4ba63dd..452cc088f 100644 --- a/src/Native/libcryptonote/contrib/epee/include/span.h +++ b/src/Native/libcryptonote/contrib/epee/include/span.h @@ -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 constexpr bool has_padding() noexcept { - return !std::is_pod() || alignof(T) != 1; + return !std::is_standard_layout() || alignof(T) != 1; } //! \return Cast data from `src` as `span`. diff --git a/src/Native/libcryptonote/contrib/epee/include/storages/http_abstract_invoke.h b/src/Native/libcryptonote/contrib/epee/include/storages/http_abstract_invoke.h index 823ce6731..d93084ab0 100644 --- a/src/Native/libcryptonote/contrib/epee/include/storages/http_abstract_invoke.h +++ b/src/Native/libcryptonote/contrib/epee/include/storages/http_abstract_invoke.h @@ -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; diff --git a/src/Native/libcryptonote/contrib/epee/include/storages/levin_abstract_invoke2.h b/src/Native/libcryptonote/contrib/epee/include/storages/levin_abstract_invoke2.h index 8ced9d689..d77e7a1f8 100644 --- a/src/Native/libcryptonote/contrib/epee/include/storages/levin_abstract_invoke2.h +++ b/src/Native/libcryptonote/contrib/epee/include/storages/levin_abstract_invoke2.h @@ -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 @@ -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 - 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(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 in_struct; boost::value_initialized out_struct; - static_cast(in_struct).load(strg); + if (!static_cast(in_struct).load(strg)) + { + LOG_ERROR("Failed to load in_struct in command " << command); + return -1; + } int res = cb(command, static_cast(in_struct), static_cast(out_struct), context); serialization::portable_storage strg_out; static_cast(out_struct).store(strg_out); @@ -200,7 +206,11 @@ namespace epee return -1; } boost::value_initialized in_struct; - static_cast(in_struct).load(strg); + if (!static_cast(in_struct).load(strg)) + { + LOG_ERROR("Failed to load in_struct in notify " << command); + return -1; + } return cb(command, in_struct, context); } diff --git a/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_from_json.h b/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_from_json.h index 04b57376c..727f36552 100644 --- a/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_from_json.h +++ b/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_from_json.h @@ -25,6 +25,8 @@ // #pragma once +#include +#include #include "parserse_base_utils.h" #include "file_io_utils.h" diff --git a/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_to_bin.h b/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_to_bin.h index 5695143b0..9501bbc2a 100644 --- a/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_to_bin.h +++ b/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_to_bin.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 size_t pack_varint(t_stream& strm, size_t val) { //the first two bits always reserved for size information diff --git a/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_val_converters.h b/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_val_converters.h index e9b91c82b..36bb28627 100644 --- a/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_val_converters.h +++ b/src/Native/libcryptonote/contrib/epee/include/storages/portable_storage_val_converters.h @@ -28,6 +28,9 @@ #pragma once +#include +#include + #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 + { + 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(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 struct is_convertable: std::integral_constant::value && diff --git a/src/Native/libcryptonote/contrib/epee/include/string_tools.h b/src/Native/libcryptonote/contrib/epee/include/string_tools.h index ce7b2fb87..63705e401 100644 --- a/src/Native/libcryptonote/contrib/epee/include/string_tools.h +++ b/src/Native/libcryptonote/contrib/epee/include/string_tools.h @@ -35,6 +35,7 @@ # include #endif +#include #include #include #include @@ -42,8 +43,9 @@ #include #include #include -#include +#include #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(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 std::string pod_to_hex(const t_pod_type& s) { - static_assert(std::is_pod::value, "expected pod type"); + static_assert(std::is_standard_layout(), "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 + bool hex_to_pod(const std::string& hex_str, tools::scrubbed& 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) { diff --git a/src/Native/libcryptonote/contrib/epee/include/wipeable_string.h b/src/Native/libcryptonote/contrib/epee/include/wipeable_string.h new file mode 100644 index 000000000..70d1a9586 --- /dev/null +++ b/src/Native/libcryptonote/contrib/epee/include/wipeable_string.h @@ -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 +#include +#include + +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 buffer; + }; +} diff --git a/src/Native/libcryptonote/contrib/epee/src/hex.cpp b/src/Native/libcryptonote/contrib/epee/src/hex.cpp index cfbd3cf87..c143b2dc2 100644 --- a/src/Native/libcryptonote/contrib/epee/src/hex.cpp +++ b/src/Native/libcryptonote/contrib/epee/src/hex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017, The Monero Project +// Copyright (c) 2017-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/contrib/epee/src/memwipe.c b/src/Native/libcryptonote/contrib/epee/src/memwipe.c new file mode 100644 index 000000000..026ef7277 --- /dev/null +++ b/src/Native/libcryptonote/contrib/epee/src/memwipe.c @@ -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 +#include +#include + +#ifndef _WIN32 +#include +#endif + +#ifdef HAVE_EXPLICIT_BZERO +#include +#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 + * 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 diff --git a/src/Native/libcryptonote/contrib/epee/src/wipeable_string.cpp b/src/Native/libcryptonote/contrib/epee/src/wipeable_string.cpp new file mode 100644 index 000000000..6ed4ee8a2 --- /dev/null +++ b/src/Native/libcryptonote/contrib/epee/src/wipeable_string.cpp @@ -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 +#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 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; +} + +} diff --git a/src/Native/libcryptonote/crypto/CMakeLists.txt b/src/Native/libcryptonote/crypto/CMakeLists.txt new file mode 100644 index 000000000..71dcedcab --- /dev/null +++ b/src/Native/libcryptonote/crypto/CMakeLists.txt @@ -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() + + diff --git a/src/Native/libcryptonote/crypto/blake256.c b/src/Native/libcryptonote/crypto/blake256.c index 1e43f9c4d..d503c47e0 100644 --- a/src/Native/libcryptonote/crypto/blake256.c +++ b/src/Native/libcryptonote/crypto/blake256.c @@ -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]++; diff --git a/src/Native/libcryptonote/crypto/blake256.h b/src/Native/libcryptonote/crypto/blake256.h index 921fcd2fd..073772289 100644 --- a/src/Native/libcryptonote/crypto/blake256.h +++ b/src/Native/libcryptonote/crypto/blake256.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/chacha.c b/src/Native/libcryptonote/crypto/chacha.c new file mode 100644 index 000000000..5d3edb98d --- /dev/null +++ b/src/Native/libcryptonote/crypto/chacha.c @@ -0,0 +1,182 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include +#include +#ifndef _MSC_VER +#include +#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); +} diff --git a/src/Native/libcryptonote/crypto/chacha.h b/src/Native/libcryptonote/crypto/chacha.h new file mode 100644 index 000000000..7a120931a --- /dev/null +++ b/src/Native/libcryptonote/crypto/chacha.h @@ -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 +#include + +#define CHACHA_KEY_SIZE 32 +#define CHACHA_IV_SIZE 8 + +#if defined(__cplusplus) +#include + +#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; + +#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(&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(&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 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 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 diff --git a/src/Native/libcryptonote/crypto/crypto-ops-data.c b/src/Native/libcryptonote/crypto/crypto-ops-data.c index 4bd75b77c..4ff4310de 100644 --- a/src/Native/libcryptonote/crypto/crypto-ops-data.c +++ b/src/Native/libcryptonote/crypto/crypto-ops-data.c @@ -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} }; diff --git a/src/Native/libcryptonote/crypto/crypto-ops.c b/src/Native/libcryptonote/crypto/crypto-ops.c index 4edfee0ce..45d412ac6 100644 --- a/src/Native/libcryptonote/crypto/crypto-ops.c +++ b/src/Native/libcryptonote/crypto/crypto-ops.c @@ -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); diff --git a/src/Native/libcryptonote/crypto/crypto-ops.h b/src/Native/libcryptonote/crypto/crypto-ops.h index 37edf5b6d..dc3c60794 100644 --- a/src/Native/libcryptonote/crypto/crypto-ops.h +++ b/src/Native/libcryptonote/crypto/crypto-ops.h @@ -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 */ diff --git a/src/Native/libcryptonote/crypto/crypto.cpp b/src/Native/libcryptonote/crypto/crypto.cpp index 5fb670f87..105b00c18 100644 --- a/src/Native/libcryptonote/crypto/crypto.cpp +++ b/src/Native/libcryptonote/crypto/crypto.cpp @@ -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(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 &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 &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 buf(reinterpret_cast(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); diff --git a/src/Native/libcryptonote/crypto/crypto.h b/src/Native/libcryptonote/crypto/crypto.h index e99b6651f..81ebfb9e2 100644 --- a/src/Native/libcryptonote/crypto/crypto.h +++ b/src/Native/libcryptonote/crypto/crypto.h @@ -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 +#include #include #include +#include +#include +#include #include #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; POD_CLASS public_keyV { std::vector 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 &, const public_key &, const secret_key &, signature &); + friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional &, const public_key &, const secret_key &, signature &); + static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional &, const public_key &, const signature &); + friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional &, 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 &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 &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(); + const static crypto::secret_key null_skey = boost::value_initialized(); } CRYPTO_MAKE_HASHABLE(public_key) +CRYPTO_MAKE_HASHABLE(secret_key) CRYPTO_MAKE_HASHABLE(key_image) CRYPTO_MAKE_COMPARABLE(signature) diff --git a/src/Native/libcryptonote/crypto/generic-ops.h b/src/Native/libcryptonote/crypto/generic-ops.h index 1a135ffcf..62bc758c9 100644 --- a/src/Native/libcryptonote/crypto/generic-ops.h +++ b/src/Native/libcryptonote/crypto/generic-ops.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/groestl.h b/src/Native/libcryptonote/crypto/groestl.h index 89a073a4c..19837f309 100644 --- a/src/Native/libcryptonote/crypto/groestl.h +++ b/src/Native/libcryptonote/crypto/groestl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/groestl_tables.h b/src/Native/libcryptonote/crypto/groestl_tables.h index 8fa6d7a83..c4b368584 100644 --- a/src/Native/libcryptonote/crypto/groestl_tables.h +++ b/src/Native/libcryptonote/crypto/groestl_tables.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/hash-extra-blake.c b/src/Native/libcryptonote/crypto/hash-extra-blake.c index 236479880..d33103c97 100644 --- a/src/Native/libcryptonote/crypto/hash-extra-blake.c +++ b/src/Native/libcryptonote/crypto/hash-extra-blake.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/hash-extra-groestl.c b/src/Native/libcryptonote/crypto/hash-extra-groestl.c index b15075306..228853a44 100644 --- a/src/Native/libcryptonote/crypto/hash-extra-groestl.c +++ b/src/Native/libcryptonote/crypto/hash-extra-groestl.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/hash-extra-jh.c b/src/Native/libcryptonote/crypto/hash-extra-jh.c index 8950687d3..e765a18f3 100644 --- a/src/Native/libcryptonote/crypto/hash-extra-jh.c +++ b/src/Native/libcryptonote/crypto/hash-extra-jh.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/hash-extra-skein.c b/src/Native/libcryptonote/crypto/hash-extra-skein.c index e63e7da20..06d8f87cc 100644 --- a/src/Native/libcryptonote/crypto/hash-extra-skein.c +++ b/src/Native/libcryptonote/crypto/hash-extra-skein.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/hash-ops.h b/src/Native/libcryptonote/crypto/hash-ops.h index 6998da5a4..d77d55cf3 100644 --- a/src/Native/libcryptonote/crypto/hash-ops.h +++ b/src/Native/libcryptonote/crypto/hash-ops.h @@ -1,21 +1,21 @@ -// Copyright (c) 2014-2017, The Monero Project -// +// 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 @@ -25,7 +25,7 @@ // 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 @@ -79,8 +79,7 @@ enum { }; void cn_fast_hash(const void *data, size_t length, char *hash); -void cn_slow_hash(const void *data, size_t length, char *hash); -void cn_slow_hash_lite(const void *data, size_t length, char *hash); +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed); void hash_extra_blake(const void *data, size_t length, char *hash); void hash_extra_groestl(const void *data, size_t length, char *hash); diff --git a/src/Native/libcryptonote/crypto/hash.c b/src/Native/libcryptonote/crypto/hash.c index ed95391d8..42f272e34 100644 --- a/src/Native/libcryptonote/crypto/hash.c +++ b/src/Native/libcryptonote/crypto/hash.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/hash.h b/src/Native/libcryptonote/crypto/hash.h index 22991e513..8519af1f7 100644 --- a/src/Native/libcryptonote/crypto/hash.h +++ b/src/Native/libcryptonote/crypto/hash.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -31,9 +31,13 @@ #pragma once #include +#include +#include #include "common/pod-class.h" #include "generic-ops.h" +#include "hex.h" +#include "span.h" namespace crypto { @@ -61,20 +65,41 @@ namespace crypto { cn_fast_hash(data, length, reinterpret_cast(&hash)); } + inline void cn_fast_hash_old_sig(const void *data, std::size_t length, char *hash) { + cn_fast_hash(data, length, hash); + } + inline hash cn_fast_hash(const void *data, std::size_t length) { hash h; cn_fast_hash(data, length, reinterpret_cast(&h)); return h; } - inline void cn_slow_hash(const void *data, std::size_t length, hash &hash) { - cn_slow_hash(data, length, reinterpret_cast(&hash)); + inline void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant = 0) { + cn_slow_hash(data, length, reinterpret_cast(&hash), variant, 0/*prehashed*/); + } + + inline void cn_slow_hash_old_sig(const void *data, std::size_t length, char *hash, int variant = 0) { + cn_slow_hash(data, length, hash, variant, 0/*prehashed*/); + } + + inline void cn_slow_hash_prehashed(const void *data, std::size_t length, hash &hash, int variant = 0) { + cn_slow_hash(data, length, reinterpret_cast(&hash), variant, 1/*prehashed*/); } inline void tree_hash(const hash *hashes, std::size_t count, hash &root_hash) { tree_hash(reinterpret_cast(hashes), count, reinterpret_cast(&root_hash)); } + inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + + const static crypto::hash null_hash = boost::value_initialized(); + const static crypto::hash8 null_hash8 = boost::value_initialized(); } CRYPTO_MAKE_HASHABLE(hash) diff --git a/src/Native/libcryptonote/crypto/initializer.h b/src/Native/libcryptonote/crypto/initializer.h index 619038ae6..afbace726 100644 --- a/src/Native/libcryptonote/crypto/initializer.h +++ b/src/Native/libcryptonote/crypto/initializer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -31,8 +31,13 @@ #pragma once #if defined(__GNUC__) +#if defined(__sun) && defined(__SVR4) +#define INITIALIZER(name) __attribute__((constructor)) static void name(void) +#define FINALIZER(name) __attribute__((destructor)) static void name(void) +#else #define INITIALIZER(name) __attribute__((constructor(101))) static void name(void) #define FINALIZER(name) __attribute__((destructor(101))) static void name(void) +#endif #define REGISTER_FINALIZER(name) ((void) 0) #elif defined(_MSC_VER) diff --git a/src/Native/libcryptonote/crypto/keccak.c b/src/Native/libcryptonote/crypto/keccak.c index 090d563a2..95fb3d33d 100644 --- a/src/Native/libcryptonote/crypto/keccak.c +++ b/src/Native/libcryptonote/crypto/keccak.c @@ -2,9 +2,25 @@ // 19-Nov-11 Markku-Juhani O. Saarinen // A baseline Keccak (3rd round) implementation. +#include +#include #include "hash-ops.h" #include "keccak.h" +#ifndef _WIN32 +#include +#endif + +static void local_abort(const char *msg) +{ + fprintf(stderr, "%s\n", msg); +#ifdef NDEBUG + _exit(1); +#else + abort(); +#endif +} + const uint64_t keccakf_rndc[24] = { 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, @@ -73,12 +89,18 @@ void keccakf(uint64_t st[25], int rounds) // compute a keccak hash (md) of given byte length from "in" typedef uint64_t state_t[25]; -int keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen) +void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen) { state_t st; uint8_t temp[144]; size_t i, rsiz, rsizw; + static_assert(HASH_DATA_AREA <= sizeof(temp), "Bad keccak preconditions"); + if (mdlen <= 0 || (mdlen > 100 && sizeof(st) != (size_t)mdlen)) + { + local_abort("Bad keccak use"); + } + rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; rsizw = rsiz / 8; @@ -91,6 +113,11 @@ int keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen) } // last block and padding + if (inlen + 1 >= sizeof(temp) || inlen > rsiz || rsiz - inlen + inlen + 1 >= sizeof(temp) || rsiz == 0 || rsiz - 1 >= sizeof(temp) || rsizw * 8 > sizeof(temp)) + { + local_abort("Bad keccak use"); + } + memcpy(temp, in, inlen); temp[inlen++] = 1; memset(temp + inlen, 0, rsiz - inlen); @@ -102,8 +129,6 @@ int keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen) keccakf(st, KECCAK_ROUNDS); memcpy(md, st, mdlen); - - return 0; } void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md) diff --git a/src/Native/libcryptonote/crypto/keccak.h b/src/Native/libcryptonote/crypto/keccak.h index fbd8e1904..fb9d8bd04 100644 --- a/src/Native/libcryptonote/crypto/keccak.h +++ b/src/Native/libcryptonote/crypto/keccak.h @@ -16,7 +16,7 @@ #endif // compute a keccak hash (md) of given byte length from "in" -int keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen); +void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen); // update the state void keccakf(uint64_t st[25], int norounds); diff --git a/src/Native/libcryptonote/crypto/oaes_lib.c b/src/Native/libcryptonote/crypto/oaes_lib.c index f83a44b08..aa7c3ee4b 100644 --- a/src/Native/libcryptonote/crypto/oaes_lib.c +++ b/src/Native/libcryptonote/crypto/oaes_lib.c @@ -53,6 +53,12 @@ #include #endif +#ifdef _MSC_VER +#define GETPID() _getpid() +#else +#define GETPID() getpid() +#endif + #include "oaes_config.h" #include "oaes_lib.h" @@ -478,7 +484,7 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] ) sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d", gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday, gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.millitm, - _test + timer.millitm, getpid() ); + _test + timer.millitm, GETPID() ); #else struct timeval timer; struct tm *gmTimer; @@ -490,7 +496,7 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] ) sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d", gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday, gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.tv_usec/1000, - _test + timer.tv_usec/1000, getpid() ); + _test + timer.tv_usec/1000, GETPID() ); #endif if( _test ) @@ -510,13 +516,7 @@ static uint32_t oaes_get_seed(void) _test = (char *) calloc( sizeof( char ), timer.millitm ); _ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday + gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm + - (uintptr_t)(_test + timer.millitm) + -#if !defined(_MSC_VER) - getpid(); -#else - _getpid(); -#endif - + (uintptr_t) ( _test + timer.millitm ) + GETPID(); #else struct timeval timer; struct tm *gmTimer; @@ -528,7 +528,7 @@ static uint32_t oaes_get_seed(void) _test = (char *) calloc( sizeof( char ), timer.tv_usec/1000 ); _ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday + gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.tv_usec/1000 + - (uintptr_t) ( _test + timer.tv_usec/1000 ) + getpid(); + (uintptr_t) ( _test + timer.tv_usec/1000 ) + GETPID(); #endif if( _test ) diff --git a/src/Native/libcryptonote/crypto/random.c b/src/Native/libcryptonote/crypto/random.c index 691c31f62..9e1a70a2d 100644 --- a/src/Native/libcryptonote/crypto/random.c +++ b/src/Native/libcryptonote/crypto/random.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -42,10 +42,15 @@ static void generate_system_random_bytes(size_t n, void *result); #include #include +#include static void generate_system_random_bytes(size_t n, void *result) { HCRYPTPROV prov; +#ifdef NDEBUG +#define must_succeed(x) do if (!(x)) { fprintf(stderr, "Failed: " #x); _exit(1); } while (0) +#else #define must_succeed(x) do if (!(x)) abort(); while (0) +#endif must_succeed(CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)); must_succeed(CryptGenRandom(prov, (DWORD)n, result)); must_succeed(CryptReleaseContext(prov, 0)); diff --git a/src/Native/libcryptonote/crypto/random.h b/src/Native/libcryptonote/crypto/random.h index 75d23fd04..6468136cc 100644 --- a/src/Native/libcryptonote/crypto/random.h +++ b/src/Native/libcryptonote/crypto/random.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/skein_port.h b/src/Native/libcryptonote/crypto/skein_port.h index a06ef30a2..a50a28e6b 100644 --- a/src/Native/libcryptonote/crypto/skein_port.h +++ b/src/Native/libcryptonote/crypto/skein_port.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/crypto/slow-hash.c b/src/Native/libcryptonote/crypto/slow-hash.c index b92b6e6c3..4a8ebbf9d 100644 --- a/src/Native/libcryptonote/crypto/slow-hash.c +++ b/src/Native/libcryptonote/crypto/slow-hash.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -32,6 +32,11 @@ #include #include #include +#include + +#ifndef _WIN32 +#include +#endif #include "common/int-util.h" #include "hash-ops.h" @@ -47,7 +52,47 @@ extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey); -#if defined(__x86_64__) || (defined(_MSC_VER) && defined(_WIN64)) +#define VARIANT1_1(p) \ + do if (variant > 0) \ + { \ + const uint8_t tmp = ((const uint8_t*)(p))[11]; \ + static const uint32_t table = 0x75310; \ + const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ + ((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \ + } while(0) + +#define VARIANT1_2(p) \ + do if (variant > 0) \ + { \ + xor64(p, tweak1_2); \ + } while(0) + +#define VARIANT1_CHECK() \ + do if (length < 43) \ + { \ + fprintf(stderr, "Cryptonight variants need at least 43 bytes of data"); \ + _exit(1); \ + } while(0) + +#define NONCE_POINTER (((const uint8_t*)data)+35) + +#define VARIANT1_PORTABLE_INIT() \ + uint8_t tweak1_2[8]; \ + do if (variant > 0) \ + { \ + VARIANT1_CHECK(); \ + memcpy(&tweak1_2, &state.hs.b[192], sizeof(tweak1_2)); \ + xor64(tweak1_2, NONCE_POINTER); \ + } while(0) + +#define VARIANT1_INIT64() \ + if (variant > 0) \ + { \ + VARIANT1_CHECK(); \ + } \ + const uint64_t tweak1_2 = variant > 0 ? (state.hs.w[24] ^ (*((const uint64_t*)NONCE_POINTER))) : 0 + +#if !defined NO_AES && (defined(__x86_64__) || (defined(_MSC_VER) && defined(_WIN64))) // Optimised code below, uses x86-specific intrinsics, SSE2, AES-NI // Fall back to more portable code is down at the bottom @@ -125,6 +170,7 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp _mm_store_si128(R128(c), _c); \ _b = _mm_xor_si128(_b, _c); \ _mm_store_si128(R128(&hp_state[j]), _b); \ + VARIANT1_1(&hp_state[j]); \ j = state_index(c); \ p = U64(&hp_state[j]); \ b[0] = p[0]; b[1] = p[1]; \ @@ -133,6 +179,7 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp p = U64(&hp_state[j]); \ p[0] = a[0]; p[1] = a[1]; \ a[0] ^= b[0]; a[1] ^= b[1]; \ + VARIANT1_2(p + 1); \ _b = _c; \ #if defined(_MSC_VER) @@ -183,6 +230,11 @@ STATIC INLINE void xor_blocks(uint8_t *a, const uint8_t *b) U64(a)[1] ^= U64(b)[1]; } +STATIC INLINE void xor64(uint64_t *a, const uint64_t b) +{ + *a ^= b; +} + /** * @brief uses cpuid to determine if the CPU supports the AES instructions * @return true if the CPU supports AES, false otherwise @@ -515,8 +567,7 @@ void slow_hash_free_state(void) * @param length the length in bytes of the data * @param hash a pointer to a buffer in which the final 256 bit hash will be stored */ - -void cn_slow_hash(const void *data, size_t length, char *hash) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) { RDATA_ALIGN16 uint8_t expandedKey[240]; /* These buffers are aligned to use later with SSE functions */ @@ -543,10 +594,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash) slow_hash_allocate_state(); /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */ - - hash_process(&state.hs, data, length); + if (prehashed) { + memcpy(&state.hs, data, length); + } else { + hash_process(&state.hs, data, length); + } memcpy(text, state.init, INIT_SIZE_BYTE); + VARIANT1_INIT64(); + /* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill * the 2MB large random access buffer. */ @@ -645,7 +701,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) extra_hashes[state.hs.b[0] & 3](&state, 200, hash); } -#elif defined(__arm__) || defined(__aarch64__) +#elif !defined NO_AES && (defined(__arm__) || defined(__aarch64__)) void slow_hash_allocate_state(void) { // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c @@ -670,6 +726,11 @@ void slow_hash_free_state(void) #define U64(x) ((uint64_t *) (x)) +STATIC INLINE void xor64(uint64_t *a, const uint64_t b) +{ + *a ^= b; +} + #pragma pack(push, 1) union cn_slow_hash_state { @@ -706,6 +767,7 @@ union cn_slow_hash_state vst1q_u8((uint8_t *)c, _c); \ _b = veorq_u8(_b, _c); \ vst1q_u8(&hp_state[j], _b); \ + VARIANT1_1(&hp_state[j]); \ j = state_index(c); \ p = U64(&hp_state[j]); \ b[0] = p[0]; b[1] = p[1]; \ @@ -714,6 +776,7 @@ union cn_slow_hash_state p = U64(&hp_state[j]); \ p[0] = a[0]; p[1] = a[1]; \ a[0] ^= b[0]; a[1] ^= b[1]; \ + VARIANT1_2(p + 1); \ _b = _c; \ @@ -845,7 +908,7 @@ STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, const u } } -void cn_slow_hash(const void *data, size_t length, char *hash) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) { RDATA_ALIGN16 uint8_t expandedKey[240]; RDATA_ALIGN16 uint8_t hp_state[MEMORY]; @@ -868,9 +931,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash) /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */ - hash_process(&state.hs, data, length); + if (prehashed) { + memcpy(&state.hs, data, length); + } else { + hash_process(&state.hs, data, length); + } memcpy(text, state.init, INIT_SIZE_BYTE); + VARIANT1_INIT64(); + /* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill * the 2MB large random access buffer. */ @@ -1039,7 +1108,7 @@ STATIC INLINE void xor_blocks(uint8_t* a, const uint8_t* b) U64(a)[1] ^= U64(b)[1]; } -void cn_slow_hash(const void *data, size_t length, char *hash) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) { uint8_t text[INIT_SIZE_BYTE]; uint8_t a[AES_BLOCK_SIZE]; @@ -1065,9 +1134,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash) long_state = (uint8_t *)malloc(MEMORY); #endif - hash_process(&state.hs, data, length); + if (prehashed) { + memcpy(&state.hs, data, length); + } else { + hash_process(&state.hs, data, length); + } memcpy(text, state.init, INIT_SIZE_BYTE); + VARIANT1_INIT64(); + aes_ctx = (oaes_ctx *) oaes_alloc(); oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE); @@ -1097,6 +1172,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) xor_blocks(b, p); swap_blocks(b, p); swap_blocks(a, b); + VARIANT1_1(p); // Iteration 2 p = &long_state[state_index(a)]; @@ -1106,6 +1182,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) swap_blocks(b, p); xor_blocks(b, p); swap_blocks(a, b); + VARIANT1_2(U64(p) + 1); } memcpy(text, state.init, INIT_SIZE_BYTE); @@ -1200,6 +1277,15 @@ static void xor_blocks(uint8_t* a, const uint8_t* b) { } } +static void xor64(uint8_t* left, const uint8_t* right) +{ + size_t i; + for (i = 0; i < 8; ++i) + { + left[i] ^= right[i]; + } +} + #pragma pack(push, 1) union cn_slow_hash_state { union hash_state hs; @@ -1210,7 +1296,7 @@ union cn_slow_hash_state { }; #pragma pack(pop) -void cn_slow_hash(const void *data, size_t length, char *hash) { +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) { uint8_t long_state[MEMORY]; union cn_slow_hash_state state; uint8_t text[INIT_SIZE_BYTE]; @@ -1222,11 +1308,17 @@ void cn_slow_hash(const void *data, size_t length, char *hash) { uint8_t aes_key[AES_KEY_SIZE]; oaes_ctx *aes_ctx; - hash_process(&state.hs, data, length); + if (prehashed) { + memcpy(&state.hs, data, length); + } else { + hash_process(&state.hs, data, length); + } memcpy(text, state.init, INIT_SIZE_BYTE); memcpy(aes_key, state.hs.b, AES_KEY_SIZE); aes_ctx = (oaes_ctx *) oaes_alloc(); + VARIANT1_PORTABLE_INIT(); + oaes_key_import_data(aes_ctx, aes_key, AES_KEY_SIZE); for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) { for (j = 0; j < INIT_SIZE_BLK; j++) { @@ -1254,6 +1346,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) { copy_block(&long_state[j * AES_BLOCK_SIZE], c); assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE)); swap_blocks(a, b); + VARIANT1_1(&long_state[j * AES_BLOCK_SIZE]); /* Iteration 2 */ j = e2i(a, MEMORY / AES_BLOCK_SIZE); copy_block(c, &long_state[j * AES_BLOCK_SIZE]); @@ -1261,6 +1354,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) { sum_half_blocks(b, d); swap_blocks(b, c); xor_blocks(b, c); + VARIANT1_2(c + 8); copy_block(&long_state[j * AES_BLOCK_SIZE], c); assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE)); swap_blocks(a, b); diff --git a/src/Native/libcryptonote/crypto/tree-hash.c b/src/Native/libcryptonote/crypto/tree-hash.c index 88561308f..e6d6a267c 100644 --- a/src/Native/libcryptonote/crypto/tree-hash.c +++ b/src/Native/libcryptonote/crypto/tree-hash.c @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -34,15 +34,15 @@ #include "hash-ops.h" -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__MINGW32__) && !defined(_MSC_VER) +#ifdef _MSC_VER +#include +#elif !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) #include #else #include #endif -#if defined(_MSC_VER) -#define alloca(x) _alloca(x) -#endif/*** +/*** * Round to power of two, for count>=3 and for count being not too large (as reasonable for tree hash calculations) */ size_t tree_hash_cnt(size_t count) { diff --git a/src/Native/libcryptonote/cryptonote_basic/CMakeLists.txt b/src/Native/libcryptonote/cryptonote_basic/CMakeLists.txt new file mode 100644 index 000000000..d50a9df67 --- /dev/null +++ b/src/Native/libcryptonote/cryptonote_basic/CMakeLists.txt @@ -0,0 +1,79 @@ +# 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. + +if(APPLE) + find_library(IOKIT_LIBRARY IOKit) + mark_as_advanced(IOKIT_LIBRARY) + list(APPEND EXTRA_LIBRARIES ${IOKIT_LIBRARY}) +endif() + +set(cryptonote_basic_sources + account.cpp + cryptonote_basic_impl.cpp + cryptonote_format_utils.cpp + difficulty.cpp + hardfork.cpp + miner.cpp) + +set(cryptonote_basic_headers) + +set(cryptonote_basic_private_headers + account.h + account_boost_serialization.h + connection_context.h + cryptonote_basic.h + cryptonote_basic_impl.h + cryptonote_boost_serialization.h + cryptonote_format_utils.h + cryptonote_stat_info.h + difficulty.h + hardfork.h + miner.h + tx_extra.h + verification_context.h) + +monero_private_headers(cryptonote_basic + ${cryptonote_basic_private_headers}) +monero_add_library(cryptonote_basic + ${cryptonote_basic_sources} + ${cryptonote_basic_headers} + ${cryptonote_basic_private_headers}) +target_link_libraries(cryptonote_basic + PUBLIC + common + cncrypto + checkpoints + device + ${Boost_DATE_TIME_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_SERIALIZATION_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + PRIVATE + ${EXTRA_LIBRARIES}) diff --git a/src/Native/libcryptonote/cryptonote_basic/account.cpp b/src/Native/libcryptonote/cryptonote_basic/account.cpp index dd875402f..bab991d19 100644 --- a/src/Native/libcryptonote/cryptonote_basic/account.cpp +++ b/src/Native/libcryptonote/cryptonote_basic/account.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -50,6 +50,17 @@ DISABLE_VS_WARNINGS(4244 4345) namespace cryptonote { + + //----------------------------------------------------------------- + hw::device& account_keys::get_device() const { + return *m_device; + } + //----------------------------------------------------------------- + void account_keys::set_device( hw::device &hwdev) { + m_device = &hwdev; + MCDEBUG("device", "account_keys::set_device device type: "< &multisig_keys) + { + m_keys.m_account_address.m_spend_public_key = spend_public_key; + m_keys.m_view_secret_key = view_secret_key; + m_keys.m_spend_secret_key = spend_secret_key; + m_keys.m_multisig_keys = multisig_keys; + return crypto::secret_key_to_public_key(view_secret_key, m_keys.m_account_address.m_view_public_key); + } + //----------------------------------------------------------------- + void account_base::finalize_multisig(const crypto::public_key &spend_public_key) + { + m_keys.m_account_address.m_spend_public_key = spend_public_key; + } + //----------------------------------------------------------------- const account_keys& account_base::get_keys() const { return m_keys; } //----------------------------------------------------------------- - std::string account_base::get_public_address_str(bool testnet) const + std::string account_base::get_public_address_str(network_type nettype) const { //TODO: change this code into base 58 - return get_account_address_as_str(testnet, m_keys.m_account_address); + return get_account_address_as_str(nettype, false, m_keys.m_account_address); } //----------------------------------------------------------------- - std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const + std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const { //TODO: change this code into base 58 - return get_account_integrated_address_as_str(testnet, m_keys.m_account_address, payment_id); + return get_account_integrated_address_as_str(nettype, m_keys.m_account_address, payment_id); } //----------------------------------------------------------------- } diff --git a/src/Native/libcryptonote/cryptonote_basic/account.h b/src/Native/libcryptonote/cryptonote_basic/account.h index e0d5447a2..df4344730 100644 --- a/src/Native/libcryptonote/cryptonote_basic/account.h +++ b/src/Native/libcryptonote/cryptonote_basic/account.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -42,12 +42,20 @@ namespace cryptonote account_public_address m_account_address; crypto::secret_key m_spend_secret_key; crypto::secret_key m_view_secret_key; + std::vector m_multisig_keys; + hw::device *m_device = &hw::get_device("default"); BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_account_address) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys) END_KV_SERIALIZE_MAP() + + account_keys& operator=(account_keys const&) = default; + + hw::device& get_device() const ; + void set_device( hw::device &hwdev) ; }; /************************************************************************/ @@ -58,11 +66,17 @@ namespace cryptonote public: account_base(); crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false); + void create_from_device(const std::string &device_name) ; void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey); void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey); + bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector &multisig_keys); + void finalize_multisig(const crypto::public_key &spend_public_key); const account_keys& get_keys() const; - std::string get_public_address_str(bool testnet) const; - std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const; + std::string get_public_address_str(uint8_t nettype) const; + std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, uint8_t nettype) const; + + hw::device& get_device() const {return m_keys.get_device();} + void set_device( hw::device &hwdev) {m_keys.set_device(hwdev);} uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } @@ -71,6 +85,7 @@ namespace cryptonote bool store(const std::string& file_path); void forget_spend_key(); + const std::vector &get_multisig_keys() const { return m_keys.m_multisig_keys; } template inline void serialize(t_archive &a, const unsigned int /*ver*/) diff --git a/src/Native/libcryptonote/cryptonote_basic/account_boost_serialization.h b/src/Native/libcryptonote/cryptonote_basic/account_boost_serialization.h index d2f541638..7379d787f 100644 --- a/src/Native/libcryptonote/cryptonote_basic/account_boost_serialization.h +++ b/src/Native/libcryptonote/cryptonote_basic/account_boost_serialization.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/cryptonote_basic/blobdatatype.h b/src/Native/libcryptonote/cryptonote_basic/blobdatatype.h new file mode 100644 index 000000000..7d6ff0187 --- /dev/null +++ b/src/Native/libcryptonote/cryptonote_basic/blobdatatype.h @@ -0,0 +1,36 @@ +// 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 + +namespace cryptonote +{ + typedef std::string blobdata; +} diff --git a/src/Native/libcryptonote/cryptonote_basic/connection_context.h b/src/Native/libcryptonote/cryptonote_basic/connection_context.h index 3283543e2..5cd1709ab 100644 --- a/src/Native/libcryptonote/cryptonote_basic/connection_context.h +++ b/src/Native/libcryptonote/cryptonote_basic/connection_context.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -40,7 +40,7 @@ namespace cryptonote struct cryptonote_connection_context: public epee::net_utils::connection_context_base { cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0), - m_last_known_hash(cryptonote::null_hash) {} + m_last_request_time(boost::posix_time::microsec_clock::universal_time()), m_callback_request_count(0), m_last_known_hash(crypto::null_hash) {} enum state { diff --git a/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic.h b/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic.h index 873bf5374..c5a2ea6f1 100644 --- a/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic.h +++ b/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -36,7 +36,6 @@ #include // memcmp #include #include -#include "serialization/serialization.h" #include "serialization/variant.h" #include "serialization/vector.h" #include "serialization/binary_archive.h" @@ -50,14 +49,10 @@ #include "misc_language.h" #include "tx_extra.h" #include "ringct/rctTypes.h" +#include "device/device.hpp" namespace cryptonote { - - const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash); - const static crypto::hash8 null_hash8 = AUTO_VAL_INIT(null_hash8); - const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey); - typedef std::vector ring_signature; @@ -264,7 +259,7 @@ namespace cryptonote ar.tag("rctsig_prunable"); ar.begin_object(); r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), - vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); + vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); if (!r || !ar.stream().good()) return false; ar.end_object(); } @@ -416,33 +411,45 @@ namespace cryptonote KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key) END_KV_SERIALIZE_MAP() - }; - struct integrated_address - { - account_public_address adr; - crypto::hash8 payment_id; - - BEGIN_SERIALIZE_OBJECT() - FIELD(adr) - FIELD(payment_id) - END_SERIALIZE() - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(adr) - KV_SERIALIZE(payment_id) - END_KV_SERIALIZE_MAP() + bool operator==(const account_public_address& rhs) const + { + return m_spend_public_key == rhs.m_spend_public_key && + m_view_public_key == rhs.m_view_public_key; + } + + bool operator!=(const account_public_address& rhs) const + { + return !(*this == rhs); + } }; + struct integrated_address + { + account_public_address adr; + crypto::hash8 payment_id; + + BEGIN_SERIALIZE_OBJECT() + FIELD(adr) + FIELD(payment_id) + END_SERIALIZE() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(adr) + KV_SERIALIZE(payment_id) + END_KV_SERIALIZE_MAP() + }; + + struct keypair { crypto::public_key pub; crypto::secret_key sec; - static inline keypair generate() + static inline keypair generate(hw::device &hwdev) { keypair k; - generate_keys(k.pub, k.sec); + hwdev.generate_keys(k.pub, k.sec); return k; } }; @@ -450,6 +457,21 @@ namespace cryptonote } +namespace std { + template <> + struct hash + { + std::size_t operator()(const cryptonote::account_public_address& addr) const + { + // https://stackoverflow.com/a/17017281 + size_t res = 17; + res = res * 31 + hash()(addr.m_spend_public_key); + res = res * 31 + hash()(addr.m_view_public_key); + return res; + } + }; +} + BLOB_SERIALIZER(cryptonote::txout_to_key); BLOB_SERIALIZER(cryptonote::txout_to_scripthash); diff --git a/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.cpp b/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.cpp index a59f96956..9a9362466 100644 --- a/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -34,7 +34,7 @@ using namespace epee; #include "cryptonote_basic_impl.h" #include "string_tools.h" #include "serialization/binary_utils.h" -#include "serialization/vector.h" +#include "serialization/container.h" #include "cryptonote_format_utils.h" #include "cryptonote_config.h" #include "misc_language.h" @@ -157,24 +157,26 @@ namespace cryptonote { } //----------------------------------------------------------------------- std::string get_account_address_as_str( - bool testnet + uint8_t nettype + , bool subaddress , account_public_address const & adr ) { - uint64_t address_prefix = testnet ? - config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX; + uint64_t address_prefix = nettype == TESTNET ? + (subaddress ? config::testnet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX) : nettype == STAGENET ? + (subaddress ? config::stagenet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::stagenet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX) : + (subaddress ? config::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX); return tools::base58::encode_addr(address_prefix, t_serializable_object_to_blob(adr)); } //----------------------------------------------------------------------- std::string get_account_integrated_address_as_str( - bool testnet + uint8_t nettype , account_public_address const & adr , crypto::hash8 const & payment_id ) { - uint64_t integrated_address_prefix = testnet ? - config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; + uint64_t integrated_address_prefix = nettype == TESTNET ? config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : nettype == STAGENET ? config::stagenet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; integrated_address iadr = { adr, payment_id @@ -193,18 +195,21 @@ namespace cryptonote { return true; } //----------------------------------------------------------------------- - bool get_account_integrated_address_from_str( - account_public_address& adr - , bool& has_payment_id - , crypto::hash8& payment_id - , bool testnet + bool get_account_address_from_str( + address_parse_info& info + , uint8_t nettype , std::string const & str ) { - uint64_t address_prefix = testnet ? - config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX; - uint64_t integrated_address_prefix = testnet ? - config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; + uint64_t address_prefix = nettype == TESTNET ? + config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : nettype == STAGENET ? + config::stagenet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX; + uint64_t integrated_address_prefix = nettype == TESTNET ? + config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : nettype == STAGENET ? + config::stagenet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX; + uint64_t subaddress_prefix = nettype == TESTNET ? + config::testnet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : nettype == STAGENET ? + config::stagenet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX; if (2 * sizeof(public_address_outer_blob) != str.size()) { @@ -218,18 +223,27 @@ namespace cryptonote { if (integrated_address_prefix == prefix) { - has_payment_id = true; + info.is_subaddress = false; + info.has_payment_id = true; } else if (address_prefix == prefix) { - has_payment_id = false; + info.is_subaddress = false; + info.has_payment_id = false; + } + else if (subaddress_prefix == prefix) + { + info.is_subaddress = true; + info.has_payment_id = false; } else { - LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix << " or " << integrated_address_prefix); + LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix + << " or " << integrated_address_prefix + << " or " << subaddress_prefix); return false; } - if (has_payment_id) + if (info.has_payment_id) { integrated_address iadr; if (!::serialization::parse_binary(data, iadr)) @@ -237,19 +251,19 @@ namespace cryptonote { LOG_PRINT_L1("Account public address keys can't be parsed"); return false; } - adr = iadr.adr; - payment_id = iadr.payment_id; + info.address = iadr.adr; + info.payment_id = iadr.payment_id; } else { - if (!::serialization::parse_binary(data, adr)) + if (!::serialization::parse_binary(data, info.address)) { LOG_PRINT_L1("Account public address keys can't be parsed"); return false; } } - if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key)) + if (!crypto::check_key(info.address.m_spend_public_key) || !crypto::check_key(info.address.m_view_public_key)) { LOG_PRINT_L1("Failed to validate address keys"); return false; @@ -284,51 +298,27 @@ namespace cryptonote { } //we success - adr = blob.m_address; - has_payment_id = false; + info.address = blob.m_address; + info.is_subaddress = false; + info.has_payment_id = false; } return true; } - //----------------------------------------------------------------------- - bool get_account_address_from_str( - account_public_address& adr - , bool testnet - , std::string const & str - ) - { - bool has_payment_id; - crypto::hash8 payment_id; - return get_account_integrated_address_from_str(adr, has_payment_id, payment_id, testnet, str); - } //-------------------------------------------------------------------------------- bool get_account_address_from_str_or_url( - cryptonote::account_public_address& address - , bool& has_payment_id - , crypto::hash8& payment_id - , bool testnet + address_parse_info& info + , uint8_t nettype , const std::string& str_or_url , std::function&, bool)> dns_confirm ) { - if (get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, str_or_url)) + if (get_account_address_from_str(info, nettype, str_or_url)) return true; bool dnssec_valid; std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, dns_confirm); return !address_str.empty() && - get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_str); - } - //-------------------------------------------------------------------------------- - bool get_account_address_from_str_or_url( - cryptonote::account_public_address& address - , bool testnet - , const std::string& str_or_url - , std::function&, bool)> dns_confirm - ) - { - bool has_payment_id; - crypto::hash8 payment_id; - return get_account_address_from_str_or_url(address, has_payment_id, payment_id, testnet, str_or_url, dns_confirm); + get_account_address_from_str(info, nettype, address_str); } //-------------------------------------------------------------------------------- bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) { diff --git a/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.h b/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.h index 7a2259b32..4ec2b403d 100644 --- a/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/Native/libcryptonote/cryptonote_basic/cryptonote_basic_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -33,8 +33,6 @@ #include "cryptonote_basic.h" #include "crypto/crypto.h" #include "crypto/hash.h" -#include "hex.h" -#include "span.h" namespace cryptonote { @@ -77,6 +75,14 @@ namespace cryptonote { } } + struct address_parse_info + { + account_public_address address; + bool is_subaddress; + bool has_payment_id; + crypto::hash8 payment_id; + }; + /************************************************************************/ /* Cryptonote helper functions */ /************************************************************************/ @@ -88,42 +94,26 @@ namespace cryptonote { uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); std::string get_account_address_as_str( - bool testnet + uint8_t nettype + , bool subaddress , const account_public_address& adr ); std::string get_account_integrated_address_as_str( - bool testnet + uint8_t nettype , const account_public_address& adr , const crypto::hash8& payment_id ); - bool get_account_integrated_address_from_str( - account_public_address& adr - , bool& has_payment_id - , crypto::hash8& payment_id - , bool testnet - , const std::string& str - ); - bool get_account_address_from_str( - account_public_address& adr - , bool testnet + address_parse_info& info + , uint8_t nettype , const std::string& str ); bool get_account_address_from_str_or_url( - cryptonote::account_public_address& address - , bool& has_payment_id - , crypto::hash8& payment_id - , bool testnet - , const std::string& str_or_url - , std::function&, bool)> dns_confirm = return_first_address - ); - - bool get_account_address_from_str_or_url( - cryptonote::account_public_address& address - , bool testnet + address_parse_info& info + , uint8_t nettype , const std::string& str_or_url , std::function&, bool)> dns_confirm = return_first_address ); @@ -136,26 +126,3 @@ namespace cryptonote { bool parse_hash256(const std::string str_hash, crypto::hash& hash); -namespace crypto { - 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; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } -} diff --git a/src/Native/libcryptonote/cryptonote_basic/cryptonote_boost_serialization.h b/src/Native/libcryptonote/cryptonote_basic/cryptonote_boost_serialization.h index 6e4ac9b72..143133163 100644 --- a/src/Native/libcryptonote/cryptonote_basic/cryptonote_boost_serialization.h +++ b/src/Native/libcryptonote/cryptonote_basic/cryptonote_boost_serialization.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -83,6 +83,11 @@ namespace boost { a & reinterpret_cast(x); } + template + inline void serialize(Archive &a, crypto::hash8 &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } template inline void serialize(Archive &a, cryptonote::txout_to_script &x, const boost::serialization::version_type ver) @@ -206,6 +211,23 @@ namespace boost a & x.Ci; } + template + inline void serialize(Archive &a, rct::Bulletproof &x, const boost::serialization::version_type ver) + { + a & x.V; + a & x.A; + a & x.S; + a & x.T1; + a & x.T2; + a & x.taux; + a & x.mu; + a & x.L; + a & x.R; + a & x.a; + a & x.b; + a & x.t; + } + template inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver) { @@ -230,6 +252,21 @@ namespace boost // a & x.senderPk; // not serialized, as we do not use it in monero currently } + template + inline void serialize(Archive &a, rct::multisig_kLRki &x, const boost::serialization::version_type ver) + { + a & x.k; + a & x.L; + a & x.R; + a & x.ki; + } + + template + inline void serialize(Archive &a, rct::multisig_out &x, const boost::serialization::version_type ver) + { + a & x.c; + } + template inline typename std::enable_if::type serializeOutPk(Archive &a, rct::ctkeyV &outPk_, const boost::serialization::version_type ver) { @@ -258,11 +295,11 @@ namespace boost a & x.type; if (x.type == rct::RCTTypeNull) return; - if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple) + if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof) throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); // a & x.message; message is not serialized, as it can be reconstructed from the tx data // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets - if (x.type == rct::RCTTypeSimple) + if (x.type == rct::RCTTypeSimple) // moved to prunable with bulletproofs a & x.pseudoOuts; a & x.ecdhInfo; serializeOutPk(a, x.outPk, ver); @@ -273,7 +310,11 @@ namespace boost inline void serialize(Archive &a, rct::rctSigPrunable &x, const boost::serialization::version_type ver) { a & x.rangeSigs; + if (x.rangeSigs.empty()) + a & x.bulletproofs; a & x.MGs; + if (x.rangeSigs.empty()) + a & x.pseudoOuts; } template @@ -282,7 +323,7 @@ namespace boost a & x.type; if (x.type == rct::RCTTypeNull) return; - if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple) + if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof) throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); // a & x.message; message is not serialized, as it can be reconstructed from the tx data // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets @@ -293,7 +334,11 @@ namespace boost a & x.txnFee; //-------------- a & x.p.rangeSigs; + if (x.p.rangeSigs.empty()) + a & x.p.bulletproofs; a & x.p.MGs; + if (x.type == rct::RCTTypeSimpleBulletproof) + a & x.p.pseudoOuts; } } } diff --git a/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.cpp b/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.cpp index 745dfb72e..934767960 100644 --- a/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -32,8 +32,11 @@ using namespace epee; #include +#include +#include "wipeable_string.h" +#include "string_tools.h" +#include "serialization/string.h" #include "cryptonote_format_utils.h" -#include "cryptonote_config.h" #include "crypto/crypto.h" #include "crypto/hash.h" #include "ringct/rctSigs.h" @@ -45,6 +48,8 @@ using namespace epee; // #define ENABLE_HASH_CASH_INTEGRITY_CHECK +using namespace crypto; + static const uint64_t valid_decomposed_outputs[] = { (uint64_t)1, (uint64_t)2, (uint64_t)3, (uint64_t)4, (uint64_t)5, (uint64_t)6, (uint64_t)7, (uint64_t)8, (uint64_t)9, // 1 piconero (uint64_t)10, (uint64_t)20, (uint64_t)30, (uint64_t)40, (uint64_t)50, (uint64_t)60, (uint64_t)70, (uint64_t)80, (uint64_t)90, @@ -75,6 +80,31 @@ static std::atomic tx_hashes_cached_count(0); static std::atomic block_hashes_calculated_count(0); static std::atomic block_hashes_cached_count(0); +#define CHECK_AND_ASSERT_THROW_MES_L1(expr, message) {if(!(expr)) {MWARNING(message); throw std::runtime_error(message);}} + +namespace cryptonote +{ + static inline unsigned char *operator &(ec_point &point) { + return &reinterpret_cast(point); + } + static inline const unsigned char *operator &(const ec_point &point) { + return &reinterpret_cast(point); + } + + // a copy of rct::addKeys, since we can't link to libringct to avoid circular dependencies + static void add_public_key(crypto::public_key &AB, const crypto::public_key &A, const crypto::public_key &B) { + ge_p3 B2, A2; + CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&B2, &B) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast(__LINE__)); + CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A2, &A) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast(__LINE__)); + ge_cached tmp2; + ge_p3_to_cached(&tmp2, &B2); + ge_p1p1 tmp3; + ge_add(&tmp3, &A2, &tmp2); + ge_p1p1_to_p3(&A2, &tmp3); + ge_p3_tobytes(&AB, &A2); + } +} + namespace cryptonote { //--------------------------------------------------------------- @@ -129,18 +159,58 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki) + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) { - crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); - bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); - CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); + if (ack.m_spend_secret_key == crypto::null_skey) + { + // for watch-only wallet, simply copy the known output pubkey + in_ephemeral.pub = out_key; + in_ephemeral.sec = crypto::null_skey; + } + else + { + // derive secret key with subaddress - step 1: original CN derivation + crypto::secret_key scalar_step1; + hwdev.derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1); // computes Hs(a*R || idx) + b + + // step 2: add Hs(a || index_major || index_minor) + crypto::secret_key subaddr_sk; + crypto::secret_key scalar_step2; + if (received_index.is_zero()) + { + scalar_step2 = scalar_step1; // treat index=(0,0) as a special case representing the main address + } + else + { + subaddr_sk = hwdev.get_subaddress_secret_key(ack.m_view_secret_key, received_index); + hwdev.sc_secret_add(scalar_step2, scalar_step1,subaddr_sk); + } - r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub); - CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")"); + in_ephemeral.sec = scalar_step2; + + if (ack.m_multisig_keys.empty()) + { + // when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase + CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive public key"); + } + else + { + // when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation + CHECK_AND_ASSERT_MES(hwdev.derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key"); + // and don't forget to add the contribution from the subaddress part + if (!received_index.is_zero()) + { + crypto::public_key subaddr_pk; + CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(subaddr_sk, subaddr_pk), false, "Failed to derive public key"); + add_public_key(in_ephemeral.pub, in_ephemeral.pub, subaddr_pk); + } + } - crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec); + CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key, + false, "key image helper precomp: given output pubkey doesn't match the derived one"); + } - crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); + hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); return true; } //--------------------------------------------------------------- @@ -271,9 +341,53 @@ namespace cryptonote //--------------------------------------------------------------- bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key) { - tx.extra.resize(tx.extra.size() + 1 + sizeof(crypto::public_key)); - tx.extra[tx.extra.size() - 1 - sizeof(crypto::public_key)] = TX_EXTRA_TAG_PUBKEY; - *reinterpret_cast(&tx.extra[tx.extra.size() - sizeof(crypto::public_key)]) = tx_pub_key; + return add_tx_pub_key_to_extra(tx.extra, tx_pub_key); + } + //--------------------------------------------------------------- + bool add_tx_pub_key_to_extra(transaction_prefix& tx, const crypto::public_key& tx_pub_key) + { + return add_tx_pub_key_to_extra(tx.extra, tx_pub_key); + } + //--------------------------------------------------------------- + bool add_tx_pub_key_to_extra(std::vector& tx_extra, const crypto::public_key& tx_pub_key) + { + tx_extra.resize(tx_extra.size() + 1 + sizeof(crypto::public_key)); + tx_extra[tx_extra.size() - 1 - sizeof(crypto::public_key)] = TX_EXTRA_TAG_PUBKEY; + *reinterpret_cast(&tx_extra[tx_extra.size() - sizeof(crypto::public_key)]) = tx_pub_key; + return true; + } + //--------------------------------------------------------------- + std::vector get_additional_tx_pub_keys_from_extra(const std::vector& tx_extra) + { + // parse + std::vector tx_extra_fields; + parse_tx_extra(tx_extra, tx_extra_fields); + // find corresponding field + tx_extra_additional_pub_keys additional_pub_keys; + if(!find_tx_extra_field_by_type(tx_extra_fields, additional_pub_keys)) + return {}; + return additional_pub_keys.data; + } + //--------------------------------------------------------------- + std::vector get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx) + { + return get_additional_tx_pub_keys_from_extra(tx.extra); + } + //--------------------------------------------------------------- + bool add_additional_tx_pub_keys_to_extra(std::vector& tx_extra, const std::vector& additional_pub_keys) + { + // convert to variant + tx_extra_field field = tx_extra_additional_pub_keys{ additional_pub_keys }; + // serialize + std::ostringstream oss; + binary_archive ar(oss); + bool r = ::do_serialize(ar, field); + CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra additional tx pub keys"); + // append + std::string tx_extra_str = oss.str(); + size_t pos = tx_extra.size(); + tx_extra.resize(tx_extra.size() + tx_extra_str.size()); + memcpy(&tx_extra[pos], tx_extra_str.data(), tx_extra_str.size()); return true; } //--------------------------------------------------------------- @@ -360,30 +474,6 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) - { - crypto::key_derivation derivation; - crypto::hash hash; - char data[33]; /* A hash, and an extra byte */ - - if (!generate_key_derivation(public_key, secret_key, derivation)) - return false; - - memcpy(data, &derivation, 32); - data[32] = ENCRYPTED_PAYMENT_ID_TAIL; - cn_fast_hash(data, 33, hash); - - for (size_t b = 0; b < 8; ++b) - payment_id.data[b] ^= hash.data[b]; - - return true; - } - bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) - { - // Encryption and decryption are the same operation (xor with a key) - return encrypt_payment_id(payment_id, public_key, secret_key); - } - //--------------------------------------------------------------- bool get_inputs_money_amount(const transaction& tx, uint64_t& money) { money = 0; @@ -479,48 +569,27 @@ namespace cryptonote res.insert(8, "...."); return res; } - //--------------------------------------------------------------- - bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index) - { - crypto::key_derivation derivation; - generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation); - crypto::public_key pk; - derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); - return pk == out_key.key; - } - //--------------------------------------------------------------- - bool is_out_to_acc_precomp(const crypto::public_key& spend_public_key, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index) - { - crypto::public_key pk; - derive_public_key(derivation, output_index, spend_public_key, pk); - return pk == out_key.key; - } - //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered) - { - crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); - if(null_pkey == tx_pub_key) - return false; - return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered); - } - //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered) + boost::optional is_out_to_acc_precomp(const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector& additional_derivations, size_t output_index, hw::device &hwdev) { - money_transfered = 0; - size_t i = 0; - for(const tx_out& o: tx.vout) + // try the shared tx pubkey + crypto::public_key subaddress_spendkey; + hwdev.derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey); + auto found = subaddresses.find(subaddress_spendkey); + if (found != subaddresses.end()) + return subaddress_receive_info{ found->second, derivation }; + // try additional tx pubkeys if available + if (!additional_derivations.empty()) { - CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" ); - if(is_out_to_acc(acc, boost::get(o.target), tx_pub_key, i)) - { - outs.push_back(i); - money_transfered += o.amount; - } - i++; + CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations"); + hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey); + found = subaddresses.find(subaddress_spendkey); + if (found != subaddresses.end()) + return subaddress_receive_info{ found->second, additional_derivations[output_index] }; } - return true; + return boost::none; } //--------------------------------------------------------------- + //--------------------------------------------------------------- void get_blob_hash(const blobdata& blob, crypto::hash& res) { cn_fast_hash(blob.data(), blob.size(), res); @@ -632,7 +701,7 @@ namespace cryptonote // prunable rct if (t.rct_signatures.type == rct::RCTTypeNull) { - hashes[2] = cryptonote::null_hash; + hashes[2] = crypto::null_hash; } else { @@ -768,7 +837,8 @@ namespace cryptonote return true; } blobdata bd = get_block_hashing_blob(b); - crypto::cn_slow_hash(bd.data(), bd.size(), res); + const int cn_variant = b.major_version >= 7 ? b.major_version - 6 : 0; + crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant); return true; } //--------------------------------------------------------------- @@ -869,4 +939,20 @@ namespace cryptonote block_hashes_calculated = block_hashes_calculated_count; block_hashes_cached = block_hashes_cached_count; } + //--------------------------------------------------------------- + crypto::secret_key encrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase) + { + crypto::hash hash; + crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash); + sc_add((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data); + return key; + } + //--------------------------------------------------------------- + crypto::secret_key decrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase) + { + crypto::hash hash; + crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash); + sc_sub((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data); + return key; + } } diff --git a/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.h b/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.h index d8ccf8eec..79466e9c4 100644 --- a/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.h +++ b/src/Native/libcryptonote/cryptonote_basic/cryptonote_format_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -29,12 +29,19 @@ // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once -#include "cryptonote_protocol/cryptonote_protocol_defs.h" +#include "blobdatatype.h" #include "cryptonote_basic_impl.h" #include "account.h" +#include "subaddress_index.h" #include "include_base_utils.h" #include "crypto/crypto.h" #include "crypto/hash.h" +#include + +namespace epee +{ + class wipeable_string; +} namespace cryptonote { @@ -44,8 +51,6 @@ namespace cryptonote bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx); - bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); - bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); template bool find_tx_extra_field_by_type(const std::vector& tx_extra_fields, T& field, size_t index = 0) @@ -63,19 +68,30 @@ namespace cryptonote crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0); crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index = 0); bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key); + bool add_tx_pub_key_to_extra(transaction_prefix& tx, const crypto::public_key& tx_pub_key); + bool add_tx_pub_key_to_extra(std::vector& tx_extra, const crypto::public_key& tx_pub_key); + std::vector get_additional_tx_pub_keys_from_extra(const std::vector& tx_extra); + std::vector get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx); + bool add_additional_tx_pub_keys_to_extra(std::vector& tx_extra, const std::vector& additional_pub_keys); bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce); bool remove_field_from_tx_extra(std::vector& tx_extra, const std::type_info &type); void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id); void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id); bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id); - bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index); - bool is_out_to_acc_precomp(const crypto::public_key& spend_public_key, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered); + bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector& additional_tx_public_keys, size_t output_index); + struct subaddress_receive_info + { + subaddress_index index; + crypto::key_derivation derivation; + }; + boost::optional is_out_to_acc_precomp(const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector& additional_derivations, size_t output_index, hw::device &hwdev); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, const std::vector& additional_tx_public_keys, std::vector& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered); bool get_tx_fee(const transaction& tx, uint64_t & fee); uint64_t get_tx_fee(const transaction& tx); - bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki); + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); void get_blob_hash(const blobdata& blob, crypto::hash& res); crypto::hash get_blob_hash(const blobdata& blob); std::string short_hash_str(const crypto::hash& h); @@ -212,8 +228,9 @@ namespace cryptonote bool is_valid_decomposed_amount(uint64_t amount); void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached); + crypto::secret_key encrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase); + crypto::secret_key decrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase); #define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \ CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ specific_type& variable_name = boost::get(variant_var); - } diff --git a/src/Native/libcryptonote/cryptonote_basic/cryptonote_stat_info.h b/src/Native/libcryptonote/cryptonote_basic/cryptonote_stat_info.h index 7ebf86878..c0be2144e 100644 --- a/src/Native/libcryptonote/cryptonote_basic/cryptonote_stat_info.h +++ b/src/Native/libcryptonote/cryptonote_basic/cryptonote_stat_info.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/cryptonote_basic/difficulty.cpp b/src/Native/libcryptonote/cryptonote_basic/difficulty.cpp index 863aa4359..cb2a00a12 100644 --- a/src/Native/libcryptonote/cryptonote_basic/difficulty.cpp +++ b/src/Native/libcryptonote/cryptonote_basic/difficulty.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/cryptonote_basic/difficulty.h b/src/Native/libcryptonote/cryptonote_basic/difficulty.h index aeb1c030d..b06538467 100644 --- a/src/Native/libcryptonote/cryptonote_basic/difficulty.h +++ b/src/Native/libcryptonote/cryptonote_basic/difficulty.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/cryptonote_basic/hardfork.cpp b/src/Native/libcryptonote/cryptonote_basic/hardfork.cpp index 546af2076..95f1ecab9 100644 --- a/src/Native/libcryptonote/cryptonote_basic/hardfork.cpp +++ b/src/Native/libcryptonote/cryptonote_basic/hardfork.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/cryptonote_basic/hardfork.h b/src/Native/libcryptonote/cryptonote_basic/hardfork.h index 6c6fbcb84..ee5ec0596 100644 --- a/src/Native/libcryptonote/cryptonote_basic/hardfork.h +++ b/src/Native/libcryptonote/cryptonote_basic/hardfork.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -79,7 +79,6 @@ namespace cryptonote * returns true if no error, false otherwise * * @param version the major block version for the fork - * @param voting_version the minor block version for the fork, used for voting * @param height The height the hardfork takes effect * @param time Approximate time of the hardfork (seconds since epoch) */ diff --git a/src/Native/libcryptonote/cryptonote_basic/miner.cpp b/src/Native/libcryptonote/cryptonote_basic/miner.cpp index 3c5811d61..f949bbd2b 100644 --- a/src/Native/libcryptonote/cryptonote_basic/miner.cpp +++ b/src/Native/libcryptonote/cryptonote_basic/miner.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -32,14 +32,17 @@ #include #include #include +#include #include -#include "misc_language.h" #include "include_base_utils.h" +#include "misc_language.h" +#include "syncobj.h" #include "cryptonote_basic_impl.h" #include "cryptonote_format_utils.h" #include "file_io_utils.h" #include "common/command_line.h" #include "string_coding.h" +#include "string_tools.h" #include "storages/portable_storage_template_helper.h" #include "boost/logic/tribool.hpp" @@ -53,6 +56,19 @@ #include #endif +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "miner" @@ -182,7 +198,8 @@ namespace cryptonote { uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0); float hr = static_cast(total_hr)/static_cast(m_last_hash_rates.size()); - std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL; + const auto precision = std::cout.precision(); + std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << precision << ENDL; } } m_last_hr_merge_time = misc_utils::get_tick_count(); @@ -201,7 +218,7 @@ namespace cryptonote command_line::add_arg(desc, arg_bg_mining_miner_target_percentage); } //----------------------------------------------------------------------------------------------------- - bool miner::init(const boost::program_options::variables_map& vm, bool testnet) + bool miner::init(const boost::program_options::variables_map& vm, network_type nettype) { if(command_line::has_arg(vm, arg_extra_messages)) { @@ -228,11 +245,13 @@ namespace cryptonote if(command_line::has_arg(vm, arg_start_mining)) { - if(!cryptonote::get_account_address_from_str(m_mine_address, testnet, command_line::get_arg(vm, arg_start_mining))) + address_parse_info info; + if(!cryptonote::get_account_address_from_str(info, nettype, command_line::get_arg(vm, arg_start_mining)) || info.is_subaddress) { LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled"); return false; } + m_mine_address = info.address; m_threads_total = 1; m_do_mining = true; if(command_line::has_arg(vm, arg_mining_threads)) @@ -289,8 +308,7 @@ namespace cryptonote return false; } - if(!m_template_no) - request_block_template();//lets update block template + request_block_template();//lets update block template boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0); boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0); @@ -584,7 +602,7 @@ namespace cryptonote // this should take care of the case where mining is started with bg-enabled, // and then the user decides to un-check background mining, and just do // regular full-speed mining. I might just be over-doing it and thinking up - // non-existant use-cases, so if the concensus is to simplify, we can remove all this fluff. + // non-existant use-cases, so if the consensus is to simplify, we can remove all this fluff. /* while( !m_is_background_mining_enabled ) { @@ -606,21 +624,15 @@ namespace cryptonote continue; // if interrupted because stop called, loop should end .. } - boost::tribool battery_powered(on_battery_power()); - bool on_ac_power = false; - if(indeterminate( battery_powered )) + bool on_ac_power = m_ignore_battery; + if(!m_ignore_battery) { - // name could be better, only ignores battery requirement if we failed - // to get the status of the system - if( m_ignore_battery ) + boost::tribool battery_powered(on_battery_power()); + if(!indeterminate( battery_powered )) { - on_ac_power = true; + on_ac_power = !battery_powered; } } - else - { - on_ac_power = !battery_powered; - } if( m_is_background_mining_started ) { @@ -734,8 +746,6 @@ namespace cryptonote #elif defined(__linux__) - const std::string STR_CPU("cpu"); - const std::size_t STR_CPU_LEN = STR_CPU.size(); const std::string STAT_FILE_PATH = "/proc/stat"; if( !epee::file_io_utils::is_file_exist(STAT_FILE_PATH) ) @@ -784,9 +794,36 @@ namespace cryptonote return true; + #elif defined(__FreeBSD__) + + struct statinfo s; + size_t n = sizeof(s.cp_time); + if( sysctlbyname("kern.cp_time", s.cp_time, &n, NULL, 0) == -1 ) + { + LOG_ERROR("sysctlbyname(\"kern.cp_time\"): " << strerror(errno)); + return false; + } + if( n != sizeof(s.cp_time) ) + { + LOG_ERROR("sysctlbyname(\"kern.cp_time\") output is unexpectedly " + << n << " bytes instead of the expected " << sizeof(s.cp_time) + << " bytes."); + return false; + } + + idle_time = s.cp_time[CP_IDLE]; + total_time = + s.cp_time[CP_USER] + + s.cp_time[CP_NICE] + + s.cp_time[CP_SYS] + + s.cp_time[CP_INTR] + + s.cp_time[CP_IDLE]; + + return true; + #endif - return false; // unsupported systemm.. + return false; // unsupported system } //----------------------------------------------------------------------------------------------------- bool miner::get_process_time(uint64_t& total_time) @@ -806,7 +843,7 @@ namespace cryptonote return true; } - #elif (defined(__linux__) && defined(_SC_CLK_TCK)) || defined(__APPLE__) + #elif (defined(__linux__) && defined(_SC_CLK_TCK)) || defined(__APPLE__) || defined(__FreeBSD__) struct tms tms; if ( times(&tms) != (clock_t)-1 ) @@ -817,7 +854,7 @@ namespace cryptonote #endif - return false; // unsupported system.. + return false; // unsupported system } //----------------------------------------------------------------------------------------------------- uint8_t miner::get_percent_of_total(uint64_t other, uint64_t total) @@ -858,19 +895,6 @@ namespace cryptonote const boost::filesystem::path& power_supply_path = iter->path(); if (boost::filesystem::is_directory(power_supply_path)) { - std::ifstream power_supply_present_stream((power_supply_path / "present").string()); - if (power_supply_present_stream.fail()) - { - LOG_PRINT_L0("Unable to read from " << power_supply_path << " to check if power supply present"); - continue; - } - - if (power_supply_present_stream.get() != '1') - { - LOG_PRINT_L4("Power supply not present at " << power_supply_path); - continue; - } - boost::filesystem::path power_supply_type_path = power_supply_path / "type"; if (boost::filesystem::is_regular_file(power_supply_type_path)) { @@ -941,6 +965,70 @@ namespace cryptonote } return on_battery; + #elif defined(__FreeBSD__) + int ac; + size_t n = sizeof(ac); + if( sysctlbyname("hw.acpi.acline", &ac, &n, NULL, 0) == -1 ) + { + if( errno != ENOENT ) + { + LOG_ERROR("Cannot query battery status: " + << "sysctlbyname(\"hw.acpi.acline\"): " << strerror(errno)); + return boost::logic::tribool(boost::logic::indeterminate); + } + + // If sysctl fails with ENOENT, then try querying /dev/apm. + + static const char* dev_apm = "/dev/apm"; + const int fd = open(dev_apm, O_RDONLY); + if( fd == -1 ) { + LOG_ERROR("Cannot query battery status: " + << "open(): " << dev_apm << ": " << strerror(errno)); + return boost::logic::tribool(boost::logic::indeterminate); + } + + apm_info info; + if( ioctl(fd, APMIO_GETINFO, &info) == -1 ) { + close(fd); + LOG_ERROR("Cannot query battery status: " + << "ioctl(" << dev_apm << ", APMIO_GETINFO): " << strerror(errno)); + return boost::logic::tribool(boost::logic::indeterminate); + } + + close(fd); + + // See apm(8). + switch( info.ai_acline ) + { + case 0: // off-line + case 2: // backup power + return boost::logic::tribool(true); + case 1: // on-line + return boost::logic::tribool(false); + } + switch( info.ai_batt_stat ) + { + case 0: // high + case 1: // low + case 2: // critical + return boost::logic::tribool(true); + case 3: // charging + return boost::logic::tribool(false); + } + + LOG_ERROR("Cannot query battery status: " + << "sysctl hw.acpi.acline is not available and /dev/apm returns " + << "unexpected ac-line status (" << info.ai_acline << ") and " + << "battery status (" << info.ai_batt_stat << ")."); + return boost::logic::tribool(boost::logic::indeterminate); + } + if( n != sizeof(ac) ) + { + LOG_ERROR("sysctlbyname(\"hw.acpi.acline\") output is unexpectedly " + << n << " bytes instead of the expected " << sizeof(ac) << " bytes."); + return boost::logic::tribool(boost::logic::indeterminate); + } + return boost::logic::tribool(ac == 0); #endif LOG_ERROR("couldn't query power status"); diff --git a/src/Native/libcryptonote/cryptonote_basic/miner.h b/src/Native/libcryptonote/cryptonote_basic/miner.h index 964ee6a36..2bff784c7 100644 --- a/src/Native/libcryptonote/cryptonote_basic/miner.h +++ b/src/Native/libcryptonote/cryptonote_basic/miner.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -64,7 +64,7 @@ namespace cryptonote public: miner(i_miner_handler* phandler); ~miner(); - bool init(const boost::program_options::variables_map& vm, bool testnet); + bool init(const boost::program_options::variables_map& vm, network_type nettype); static void init_options(boost::program_options::options_description& desc); bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height); bool on_block_chain_update(); diff --git a/src/Native/libcryptonote/cryptonote_basic/subaddress_index.h b/src/Native/libcryptonote/cryptonote_basic/subaddress_index.h new file mode 100644 index 000000000..9b71448f9 --- /dev/null +++ b/src/Native/libcryptonote/cryptonote_basic/subaddress_index.h @@ -0,0 +1,102 @@ +// 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 "serialization/keyvalue_serialization.h" +#include +#include +#include + +namespace cryptonote +{ + struct subaddress_index + { + uint32_t major; + uint32_t minor; + bool operator==(const subaddress_index& rhs) const { return !memcmp(this, &rhs, sizeof(subaddress_index)); } + bool operator!=(const subaddress_index& rhs) const { return !(*this == rhs); } + bool is_zero() const { return major == 0 && minor == 0; } + + BEGIN_SERIALIZE_OBJECT() + FIELD(major) + FIELD(minor) + END_SERIALIZE() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(major) + KV_SERIALIZE(minor) + END_KV_SERIALIZE_MAP() + }; +} + +namespace cryptonote { + inline std::ostream& operator<<(std::ostream& out, const cryptonote::subaddress_index& subaddr_index) + { + return out << subaddr_index.major << '/' << subaddr_index.minor; + } +} + +namespace std +{ + template <> + struct hash + { + size_t operator()(const cryptonote::subaddress_index& index ) const + { + size_t res; + if (sizeof(size_t) == 8) + { + res = ((uint64_t)index.major << 32) | index.minor; + } + else + { + // https://stackoverflow.com/a/17017281 + res = 17; + res = res * 31 + hash()(index.major); + res = res * 31 + hash()(index.minor); + } + return res; + } + }; +} + +BOOST_CLASS_VERSION(cryptonote::subaddress_index, 0) + +namespace boost +{ + namespace serialization + { + template + inline void serialize(Archive &a, cryptonote::subaddress_index &x, const boost::serialization::version_type ver) + { + a & x.major; + a & x.minor; + } + } +} diff --git a/src/Native/libcryptonote/cryptonote_basic/tx_extra.h b/src/Native/libcryptonote/cryptonote_basic/tx_extra.h index 5a6c3176d..009e35ebe 100644 --- a/src/Native/libcryptonote/cryptonote_basic/tx_extra.h +++ b/src/Native/libcryptonote/cryptonote_basic/tx_extra.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -38,6 +38,7 @@ #define TX_EXTRA_TAG_PUBKEY 0x01 #define TX_EXTRA_NONCE 0x02 #define TX_EXTRA_MERGE_MINING_TAG 0x03 +#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04 #define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 @@ -159,6 +160,16 @@ namespace cryptonote } }; + // per-output additional tx pubkey for multi-destination transfers involving at least one subaddress + struct tx_extra_additional_pub_keys + { + std::vector data; + + BEGIN_SERIALIZE() + FIELD(data) + END_SERIALIZE() + }; + struct tx_extra_mysterious_minergate { std::string data; @@ -172,11 +183,12 @@ namespace cryptonote // varint tag; // varint size; // varint data[]; - typedef boost::variant tx_extra_field; + typedef boost::variant tx_extra_field; } VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING); VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY); VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE); VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG); +VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS); VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG); diff --git a/src/Native/libcryptonote/cryptonote_basic/verification_context.h b/src/Native/libcryptonote/cryptonote_basic/verification_context.h index ce885ec1d..8d2b633a2 100644 --- a/src/Native/libcryptonote/cryptonote_basic/verification_context.h +++ b/src/Native/libcryptonote/cryptonote_basic/verification_context.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/cryptonote_config.h b/src/Native/libcryptonote/cryptonote_config.h index abfa665ff..0ad8a6005 100644 --- a/src/Native/libcryptonote/cryptonote_config.h +++ b/src/Native/libcryptonote/cryptonote_config.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -89,10 +89,10 @@ #define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing -#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 200 //by default, blocks count in blocks downloading -#define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT 3 //value of hop, after which we use only announce of new block +#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading +#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading -#define CRYPTONOTE_MEMPOOL_TX_LIVETIME 86400 //seconds, one day +#define CRYPTONOTE_MEMPOOL_TX_LIVETIME (86400*3) //seconds, three days #define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week #define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 1000 @@ -109,6 +109,7 @@ #define P2P_DEFAULT_INVOKE_TIMEOUT 60*2*1000 //2 minutes #define P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT 5000 //5 seconds #define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70 +#define P2P_DEFAULT_ANCHOR_CONNECTIONS_COUNT 2 #define P2P_FAILED_ADDR_FORGET_SECONDS (60*60) //1 hour #define P2P_IP_BLOCKTIME (60*60*24) //24 hour @@ -131,10 +132,15 @@ #define HF_VERSION_DYNAMIC_FEE 4 #define HF_VERSION_MIN_MIXIN_4 6 +#define HF_VERSION_MIN_MIXIN_6 7 #define HF_VERSION_ENFORCE_RCT 6 #define PER_KB_FEE_QUANTIZATION_DECIMALS 8 +#define HASH_OF_HASHES_STEP 256 + +#define DEFAULT_TXPOOL_MAX_SIZE 648000000ull // 3 days at 300000, in bytes + // New constants are intended to go here namespace config { @@ -146,8 +152,10 @@ namespace config uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18; uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 19; + uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 42; uint16_t const P2P_DEFAULT_PORT = 18080; uint16_t const RPC_DEFAULT_PORT = 18081; + uint16_t const ZMQ_RPC_DEFAULT_PORT = 18082; boost::uuids::uuid const NETWORK_ID = { { 0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10 } }; // Bender's nightmare @@ -158,12 +166,40 @@ namespace config { uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 53; uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 54; + uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 63; uint16_t const P2P_DEFAULT_PORT = 28080; uint16_t const RPC_DEFAULT_PORT = 28081; + uint16_t const ZMQ_RPC_DEFAULT_PORT = 28082; boost::uuids::uuid const NETWORK_ID = { { 0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x11 } }; // Bender's daydream - std::string const GENESIS_TX = "013c01ff0001ffffffffffff0f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd0880712101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b"; + std::string const GENESIS_TX = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1"; uint32_t const GENESIS_NONCE = 10001; } + + namespace stagenet + { + uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 24; + uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 25; + uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 36; + uint16_t const P2P_DEFAULT_PORT = 38080; + uint16_t const RPC_DEFAULT_PORT = 38081; + uint16_t const ZMQ_RPC_DEFAULT_PORT = 38082; + boost::uuids::uuid const NETWORK_ID = { { + 0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x12 + } }; // Bender's daydream + std::string const GENESIS_TX = "013c01ff0001ffffffffffff0302df5d56da0c7d643ddd1ce61901c7bdc5fb1738bfe39fbe69c28a3a7032729c0f2101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b"; + uint32_t const GENESIS_NONCE = 10002; + } +} + +namespace cryptonote +{ + enum network_type : uint8_t + { + MAINNET = 0, + TESTNET, + STAGENET, + FAKECHAIN + }; } diff --git a/src/Native/libcryptonote/device/device.hpp b/src/Native/libcryptonote/device/device.hpp new file mode 100644 index 000000000..b47460472 --- /dev/null +++ b/src/Native/libcryptonote/device/device.hpp @@ -0,0 +1,188 @@ +// 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. +// + + +/* Note about debug: + * To debug Device you can def the following : + * #define DEBUG_HWDEVICE + * Activate debug mechanism: + * - Add more trace + * - All computation done by device are checked by default device. + * Required IODUMMYCRYPT_HWDEVICE or IONOCRYPT_HWDEVICE for fully working + * #define IODUMMYCRYPT_HWDEVICE 1 + * - It assumes sensitive data encryption is is off on device side. a XOR with 0x55. This allow Ledger Class to make check on clear value + * #define IONOCRYPT_HWDEVICE 1 + * - It assumes sensitive data encryption is off on device side. + */ + + +#pragma once + +#include "crypto/crypto.h" +#include "crypto/chacha.h" +#include "ringct/rctTypes.h" + +#ifndef USE_DEVICE_LEDGER +#define USE_DEVICE_LEDGER 1 +#endif + +#if !defined(HAVE_PCSC) +#undef USE_DEVICE_LEDGER +#define USE_DEVICE_LEDGER 0 +#endif + +#if USE_DEVICE_LEDGER +#define WITH_DEVICE_LEDGER +#endif + +// forward declaration needed because this header is included by headers in libcryptonote_basic which depends on libdevice +namespace cryptonote +{ + struct account_public_address; + struct account_keys; + struct subaddress_index; +} + +namespace hw { + namespace { + //device funcion not supported + #define dfns() \ + throw std::runtime_error(std::string("device function not supported: ")+ std::string(__FUNCTION__) + \ + std::string(" (device.hpp line ")+std::to_string(__LINE__)+std::string(").")); \ + return false; + } + + + class device { + public: + + device() {} + device(const device &hwdev) {} + virtual ~device() {} + + explicit virtual operator bool() const = 0; + + static const int SIGNATURE_REAL = 0; + static const int SIGNATURE_FAKE = 1; + + + std::string name; + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + virtual bool set_name(const std::string &name) = 0; + virtual const std::string get_name() const = 0; + + virtual bool init(void) = 0; + virtual bool release() = 0; + + virtual bool connect(void) = 0; + virtual bool disconnect() = 0; + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0; + virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0; + virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) = 0; + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) = 0; + virtual crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) = 0; + virtual std::vector get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) = 0; + virtual cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) = 0; + virtual crypto::secret_key get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index) = 0; + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + virtual bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) = 0; + virtual bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) = 0; + virtual bool scalarmultBase(rct::key &aG, const rct::key &a) = 0; + virtual bool sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) = 0; + virtual crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) = 0; + virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0; + virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) = 0; + virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0; + virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0; + virtual bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) = 0; + virtual bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) = 0; + + // alternative prototypes available in libringct + rct::key scalarmultKey(const rct::key &P, const rct::key &a) + { + rct::key aP; + scalarmultKey(aP, P, a); + return aP; + } + + rct::key scalarmultBase(const rct::key &a) + { + rct::key aG; + scalarmultBase(aG, a); + return aG; + } + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + virtual bool open_tx(crypto::secret_key &tx_key) = 0; + + virtual bool set_signature_mode(unsigned int sig_mode) = 0; + + virtual bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) = 0; + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) + { + // Encryption and decryption are the same operation (xor with a key) + return encrypt_payment_id(payment_id, public_key, secret_key); + } + + virtual bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) = 0; + virtual bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) = 0; + + virtual bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, const bool is_subaddress, const size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) = 0; + + + virtual bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) = 0; + virtual bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) = 0; + virtual bool mlsag_prepare(rct::key &a, rct::key &aG) = 0; + virtual bool mlsag_hash(const rct::keyV &long_message, rct::key &c) = 0; + virtual bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) = 0; + + virtual bool close_tx(void) = 0; + } ; + + device& get_device(const std::string device_descriptor) ; +} + diff --git a/src/Native/libcryptonote/exports.cpp b/src/Native/libcryptonote/exports.cpp index 5081474df..2ea47f905 100644 --- a/src/Native/libcryptonote/exports.cpp +++ b/src/Native/libcryptonote/exports.cpp @@ -28,6 +28,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace cryptonote; +extern "C" void cn_slow_hash_lite(const void *data, size_t length, char *hash); + #ifdef _WIN32 #define MODULE_API __declspec(dllexport) #else @@ -65,7 +67,7 @@ extern "C" MODULE_API bool convert_blob_export(const char* input, unsigned int i // now hash it result = get_block_hashing_blob(block); - *outputSize = result.length(); + *outputSize = (int) result.length(); // output buffer big enough? if (result.length() > originalOutputSize) @@ -115,14 +117,14 @@ extern "C" MODULE_API uint64_t decode_integrated_address_export(const char* inpu return prefix; } -extern "C" MODULE_API void cn_slow_hash_export(const char* input, unsigned char *output, uint32_t inputSize) +extern "C" MODULE_API void cn_slow_hash_export(const char* input, unsigned char *output, uint32_t inputSize, uint32_t variant) { - cn_slow_hash((const void *) input, (const size_t) inputSize, (char *) output); + cn_slow_hash_old_sig((const void *) input, (const size_t) inputSize, (char *) output, variant); } extern "C" MODULE_API void cn_fast_hash_export(const char* input, unsigned char *output, uint32_t inputSize) { - cn_fast_hash((const void *)input, (const size_t) inputSize, (char *) output); + cn_fast_hash_old_sig((const void *)input, (const size_t) inputSize, (char *) output); } extern "C" MODULE_API void cn_slow_hash_lite_export(const char* input, unsigned char *output, uint32_t inputSize) diff --git a/src/Native/libcryptonote/libcryptonote.vcxproj b/src/Native/libcryptonote/libcryptonote.vcxproj index f04d72c5c..263a574b9 100644 --- a/src/Native/libcryptonote/libcryptonote.vcxproj +++ b/src/Native/libcryptonote/libcryptonote.vcxproj @@ -97,7 +97,7 @@ Level3 Disabled - WIN32;_DEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS + WIN32;_DEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGSWIN32_LEAN_AND_MEAN;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_WARNINGS true MultiThreadedDebug $(ProjectDir);$(ProjectDir)contrib\epee\include;;$(ProjectDir)contrib\easylogging;%(AdditionalIncludeDirectories) @@ -114,7 +114,7 @@ Level3 Disabled - _DEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS + _DEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGSWIN32_LEAN_AND_MEAN;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_WARNINGS true MultiThreadedDebug $(ProjectDir);$(ProjectDir)contrib\epee\include;;$(ProjectDir)contrib\easylogging;%(AdditionalIncludeDirectories) @@ -133,7 +133,7 @@ MaxSpeed true true - WIN32;NDEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS + WIN32;NDEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGSWIN32_LEAN_AND_MEAN;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_WARNINGS true MultiThreaded $(ProjectDir);$(ProjectDir)contrib\epee\include;;$(ProjectDir)contrib\easylogging;%(AdditionalIncludeDirectories) @@ -154,7 +154,7 @@ MaxSpeed true true - NDEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS + NDEBUG;netmultihashnative_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NEOSCRYPT_SHA256;NEOSCRYPT_BLAKE256;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGSWIN32_LEAN_AND_MEAN;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_WARNINGS true MultiThreaded $(ProjectDir);$(ProjectDir)contrib\epee\include;;$(ProjectDir)contrib\easylogging;%(AdditionalIncludeDirectories) @@ -172,10 +172,11 @@ + - + @@ -206,9 +207,10 @@ + - + diff --git a/src/Native/libcryptonote/libcryptonote.vcxproj.filters b/src/Native/libcryptonote/libcryptonote.vcxproj.filters index 02e8bd0bc..228959932 100644 --- a/src/Native/libcryptonote/libcryptonote.vcxproj.filters +++ b/src/Native/libcryptonote/libcryptonote.vcxproj.filters @@ -86,9 +86,6 @@ Header Files - - Header Files - Header Files @@ -113,6 +110,12 @@ Header Files + + Header Files + + + Header Files + @@ -181,9 +184,6 @@ Source Files - - Source Files - Source Files @@ -193,6 +193,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/src/Native/libcryptonote/serialization/binary_archive.h b/src/Native/libcryptonote/serialization/binary_archive.h index 0a267b081..f47a4494d 100644 --- a/src/Native/libcryptonote/serialization/binary_archive.h +++ b/src/Native/libcryptonote/serialization/binary_archive.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // @@ -82,7 +82,7 @@ struct binary_archive_base /* \struct binary_archive * - * \brief the actualy binary archive type + * \brief the actually binary archive type * * \detailed The boolean template argument /a W is the is_saving * parameter for binary_archive_base. diff --git a/src/Native/libcryptonote/serialization/binary_utils.h b/src/Native/libcryptonote/serialization/binary_utils.h index 08eba41da..79b30b337 100644 --- a/src/Native/libcryptonote/serialization/binary_utils.h +++ b/src/Native/libcryptonote/serialization/binary_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017, The Monero Project +// Copyright (c) 2014-2018, The Monero Project // // All rights reserved. // diff --git a/src/Native/libcryptonote/serialization/container.h b/src/Native/libcryptonote/serialization/container.h new file mode 100644 index 000000000..978a59d2a --- /dev/null +++ b/src/Native/libcryptonote/serialization/container.h @@ -0,0 +1,113 @@ +// Copyright (c) 2014-2017, 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 "serialization.h" + +namespace serialization +{ + namespace detail + { + template + bool serialize_container_element(Archive& ar, T& e) + { + return ::do_serialize(ar, e); + } + + template + bool serialize_container_element(Archive& ar, uint32_t& e) + { + ar.serialize_varint(e); + return true; + } + + template + bool serialize_container_element(Archive& ar, uint64_t& e) + { + ar.serialize_varint(e); + return true; + } + + template + void do_reserve(C &c, size_t N) {} + } +} + +template