diff --git a/src/NBitcoin/Crypto/ECKey.cs b/src/NBitcoin/Crypto/ECKey.cs index 66e08884f0..aeb9d5e1cb 100644 --- a/src/NBitcoin/Crypto/ECKey.cs +++ b/src/NBitcoin/Crypto/ECKey.cs @@ -191,4 +191,12 @@ private static ECPoint DecompressKey(BigInteger xBN, bool yBit) } } + + public static class ECKeyUtils + { + public static PubKey RecoverFromSignature(int recId, ECDSASignature sig, uint256 message, bool compressed) + { + return ECKey.RecoverFromSignature(recId, sig, message, compressed).GetPubKey(compressed); + } + } } diff --git a/src/Stratis.Bitcoin.Features.SmartContracts.Tests/Stratis.Bitcoin.Features.SmartContracts.Tests.csproj b/src/Stratis.Bitcoin.Features.SmartContracts.Tests/Stratis.Bitcoin.Features.SmartContracts.Tests.csproj index 89393855db..10a5178455 100644 --- a/src/Stratis.Bitcoin.Features.SmartContracts.Tests/Stratis.Bitcoin.Features.SmartContracts.Tests.csproj +++ b/src/Stratis.Bitcoin.Features.SmartContracts.Tests/Stratis.Bitcoin.Features.SmartContracts.Tests.csproj @@ -17,8 +17,8 @@ + - all runtime; build; native; contentfiles; analyzers diff --git a/src/Stratis.Bitcoin.Features.SmartContracts/SmartContractFeature.cs b/src/Stratis.Bitcoin.Features.SmartContracts/SmartContractFeature.cs index 917471ab08..00ac769217 100644 --- a/src/Stratis.Bitcoin.Features.SmartContracts/SmartContractFeature.cs +++ b/src/Stratis.Bitcoin.Features.SmartContracts/SmartContractFeature.cs @@ -118,6 +118,7 @@ public static IFullNodeBuilder AddSmartContracts(this IFullNodeBuilder fullNodeB services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Stratis.Bitcoin.Features.SmartContracts/Stratis.Bitcoin.Features.SmartContracts.csproj b/src/Stratis.Bitcoin.Features.SmartContracts/Stratis.Bitcoin.Features.SmartContracts.csproj index 29b239ca17..dbc320cce6 100644 --- a/src/Stratis.Bitcoin.Features.SmartContracts/Stratis.Bitcoin.Features.SmartContracts.csproj +++ b/src/Stratis.Bitcoin.Features.SmartContracts/Stratis.Bitcoin.Features.SmartContracts.csproj @@ -15,8 +15,8 @@ + - @@ -26,5 +26,4 @@ - diff --git a/src/Stratis.Bitcoin.Features.Wallet/WalletFeature.cs b/src/Stratis.Bitcoin.Features.Wallet/WalletFeature.cs index e972736eeb..068264bd80 100644 --- a/src/Stratis.Bitcoin.Features.Wallet/WalletFeature.cs +++ b/src/Stratis.Bitcoin.Features.Wallet/WalletFeature.cs @@ -99,8 +99,6 @@ private void AddInlineStats(StringBuilder log) log.AppendLine("Wallet Height".PadRight(LoggingConfiguration.ColumnLength) + $": {this.walletManager.WalletTipHeight}".PadRight(10) + $"(Hash: {this.walletManager.WalletTipHash})"); else log.AppendLine("Wallet Height".PadRight(LoggingConfiguration.ColumnLength) + ": No Wallet"); - - log.AppendLine(); } private void AddComponentStats(StringBuilder log) diff --git a/src/Stratis.Bitcoin/Connection/ConnectionManager.cs b/src/Stratis.Bitcoin/Connection/ConnectionManager.cs index 5ece69e57e..bc0d6021c3 100644 --- a/src/Stratis.Bitcoin/Connection/ConnectionManager.cs +++ b/src/Stratis.Bitcoin/Connection/ConnectionManager.cs @@ -316,6 +316,7 @@ void AddPeerInfo(StringBuilder peerBuilder, INetworkPeer peer) int inbound = this.ConnectedPeers.Count(x => x.Inbound); + builder.AppendLine(); builder.AppendLine($">> Connections (In:{inbound}) (Out:{this.ConnectedPeers.Count() - inbound})"); builder.AppendLine("Data Transfer".PadRight(LoggingConfiguration.ColumnLength, ' ') + $": Received: {totalRead.BytesToMegaBytes()} MB Sent: {totalWritten.BytesToMegaBytes()} MB"); diff --git a/src/Stratis.SmartContracts.CLR.Tests/AuctionTests.cs b/src/Stratis.SmartContracts.CLR.Tests/AuctionTests.cs index 36cfe45a97..2e851c27cc 100644 --- a/src/Stratis.SmartContracts.CLR.Tests/AuctionTests.cs +++ b/src/Stratis.SmartContracts.CLR.Tests/AuctionTests.cs @@ -44,6 +44,7 @@ public AuctionTests() null, getBalance, null, + null, null ); } @@ -88,7 +89,8 @@ public TestSmartContractState( IInternalTransactionExecutor transactionExecutor, Func getBalance, IInternalHashHelper hashHelper, - IContractLogger contractLogger) + IContractLogger contractLogger, + IEcRecoverProvider ecRecoverProvider) { this.Block = block; this.Message = message; @@ -99,6 +101,7 @@ public TestSmartContractState( this.GetBalance = getBalance; this.InternalHashHelper = hashHelper; this.ContractLogger = contractLogger; + this.EcRecoverProvider = ecRecoverProvider; } public IBlock Block { get; } @@ -110,6 +113,7 @@ public TestSmartContractState( public Func GetBalance { get; } public IInternalHashHelper InternalHashHelper { get; } public IContractLogger ContractLogger { get; } + public IEcRecoverProvider EcRecoverProvider { get; } } public class TestBlock : IBlock diff --git a/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTestContext.cs b/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTestContext.cs index fce7fe9b1c..85de0ef61d 100644 --- a/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTestContext.cs +++ b/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTestContext.cs @@ -31,6 +31,7 @@ public class ContractExecutorTestContext public IContractAssemblyCache ContractCache { get; } public ReflectionVirtualMachine Vm { get; } public ISmartContractStateFactory SmartContractStateFactory { get; } + public IEcRecoverProvider EcRecoverProvider { get; } public StateProcessor StateProcessor { get; } public Serializer Serializer { get; } @@ -50,7 +51,8 @@ public ContractExecutorTestContext() this.Vm = new ReflectionVirtualMachine(this.Validator, this.LoggerFactory, this.AssemblyLoader, this.ModuleDefinitionReader, this.ContractCache); this.StateProcessor = new StateProcessor(this.Vm, this.AddressGenerator); this.InternalTxExecutorFactory = new InternalExecutorFactory(this.LoggerFactory, this.StateProcessor); - this.SmartContractStateFactory = new SmartContractStateFactory(this.ContractPrimitiveSerializer, this.InternalTxExecutorFactory, this.Serializer); + this.EcRecoverProvider = new EcRecoverProvider(); + this.SmartContractStateFactory = new SmartContractStateFactory(this.ContractPrimitiveSerializer, this.InternalTxExecutorFactory, this.Serializer, this.EcRecoverProvider); } } } diff --git a/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTests.cs b/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTests.cs index a17cb0059b..f4bf09a20a 100644 --- a/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTests.cs +++ b/src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTests.cs @@ -41,6 +41,7 @@ public sealed class ContractExecutorTests private readonly IStateProcessor stateProcessor; private readonly ISmartContractStateFactory smartContractStateFactory; private readonly ISerializer serializer; + private readonly IEcRecoverProvider ecRecoverProvider; public ContractExecutorTests() { @@ -60,7 +61,8 @@ public ContractExecutorTests() this.vm = new ReflectionVirtualMachine(this.validator, this.loggerFactory, this.assemblyLoader, this.moduleDefinitionReader, this.contractCache); this.stateProcessor = new StateProcessor(this.vm, this.addressGenerator); this.internalTxExecutorFactory = new InternalExecutorFactory(this.loggerFactory, this.stateProcessor); - this.smartContractStateFactory = new SmartContractStateFactory(this.contractPrimitiveSerializer, this.internalTxExecutorFactory, this.serializer); + this.ecRecoverProvider = new EcRecoverProvider(); + this.smartContractStateFactory = new SmartContractStateFactory(this.contractPrimitiveSerializer, this.internalTxExecutorFactory, this.serializer, this.ecRecoverProvider); this.callDataSerializer = new CallDataSerializer(this.contractPrimitiveSerializer); diff --git a/src/Stratis.SmartContracts.CLR.Tests/ContractLogHolderTests.cs b/src/Stratis.SmartContracts.CLR.Tests/ContractLogHolderTests.cs index a76d10c283..d4dfdd6af1 100644 --- a/src/Stratis.SmartContracts.CLR.Tests/ContractLogHolderTests.cs +++ b/src/Stratis.SmartContracts.CLR.Tests/ContractLogHolderTests.cs @@ -29,11 +29,11 @@ public void Store_Structs_And_Get_Logs() var contractAddress1 = new uint160(1); var contractAddress2 = new uint160(2); - var state1 = new TestSmartContractState(null, new TestMessage { ContractAddress = contractAddress1.ToAddress() }, null, null, null, null, null, null, null); + var state1 = new TestSmartContractState(null, new TestMessage { ContractAddress = contractAddress1.ToAddress() }, null, null, null, null, null, null, null, null); var log1 = new Example1("Jordan", 12345); var log2 = new Example1("John", 123); - var state2 = new TestSmartContractState(null, new TestMessage { ContractAddress = contractAddress2.ToAddress() }, null, null, null, null, null, null, null); + var state2 = new TestSmartContractState(null, new TestMessage { ContractAddress = contractAddress2.ToAddress() }, null, null, null, null, null, null, null, null); var log3 = new Example2("0x95D34980095380851902ccd9A1Fb4C813C2cb639".HexToAddress(), 16, "This is a test message."); this.logHolder.Log(state1, log1); diff --git a/src/Stratis.SmartContracts.CLR.Tests/ObserverInstanceRewriterTests.cs b/src/Stratis.SmartContracts.CLR.Tests/ObserverInstanceRewriterTests.cs index b43b4ccb6c..c62ae9aafc 100644 --- a/src/Stratis.SmartContracts.CLR.Tests/ObserverInstanceRewriterTests.cs +++ b/src/Stratis.SmartContracts.CLR.Tests/ObserverInstanceRewriterTests.cs @@ -128,7 +128,8 @@ public ObserverInstanceRewriterTests() new ContractLogHolder(), Mock.Of(), new InternalHashHelper(), - () => 1000); + () => 1000, + Mock.Of()); this.rewriter = new ObserverInstanceRewriter(); } diff --git a/src/Stratis.SmartContracts.CLR.Tests/ObserverTests.cs b/src/Stratis.SmartContracts.CLR.Tests/ObserverTests.cs index 9e4896992a..7b194e7b43 100644 --- a/src/Stratis.SmartContracts.CLR.Tests/ObserverTests.cs +++ b/src/Stratis.SmartContracts.CLR.Tests/ObserverTests.cs @@ -127,7 +127,8 @@ public ObserverTests() new ContractLogHolder(), Mock.Of(), new InternalHashHelper(), - () => 1000); + () => 1000, + Mock.Of()); this.rewriter = new ObserverRewriter(new Observer(this.gasMeter, new MemoryMeter(ReflectionVirtualMachine.MemoryUnitLimit))); } diff --git a/src/Stratis.SmartContracts.CLR.Tests/ReflectionVirtualMachineTests.cs b/src/Stratis.SmartContracts.CLR.Tests/ReflectionVirtualMachineTests.cs index 5920e692e8..cfd83ba90b 100644 --- a/src/Stratis.SmartContracts.CLR.Tests/ReflectionVirtualMachineTests.cs +++ b/src/Stratis.SmartContracts.CLR.Tests/ReflectionVirtualMachineTests.cs @@ -45,7 +45,8 @@ public ReflectionVirtualMachineTests() new ContractLogHolder(), Mock.Of(), new InternalHashHelper(), - () => 1000); + () => 1000, + Mock.Of()); this.gasMeter = new GasMeter((RuntimeObserver.Gas)50_000); } diff --git a/src/Stratis.SmartContracts.CLR.Validation/Stratis.SmartContracts.CLR.Validation.csproj b/src/Stratis.SmartContracts.CLR.Validation/Stratis.SmartContracts.CLR.Validation.csproj index a1640e41ac..f348678c6d 100644 --- a/src/Stratis.SmartContracts.CLR.Validation/Stratis.SmartContracts.CLR.Validation.csproj +++ b/src/Stratis.SmartContracts.CLR.Validation/Stratis.SmartContracts.CLR.Validation.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Stratis.SmartContracts.CLR/EcRecoverProvider.cs b/src/Stratis.SmartContracts.CLR/EcRecoverProvider.cs new file mode 100644 index 0000000000..61bad66b22 --- /dev/null +++ b/src/Stratis.SmartContracts.CLR/EcRecoverProvider.cs @@ -0,0 +1,48 @@ +using NBitcoin; +using NBitcoin.Crypto; +using Stratis.SmartContracts.Core.Hashing; + +namespace Stratis.SmartContracts.CLR +{ + /// + /// Holds logic for the equivalent of the ECRECOVER opcode. + /// + /// This is static for now but when we know more about how we are going to use it we will adjust as necessary. + /// + public class EcRecoverProvider : IEcRecoverProvider + { + private static uint256 GetUint256FromMessage(byte[] message) + { + return new uint256(HashHelper.Keccak256(message)); + } + + /// + /// Retrieves the base58 address of the signer of an ECDSA signature. + /// + /// + /// The ECDSA signature prepended with header information specifying the correct value of recId. + /// The base58 address for the signer of a signature. + public Address GetSigner(byte[] message, byte[] signature) + { + // TODO: Error handling for incorrect signature format etc. + + uint256 hashedUint256 = GetUint256FromMessage(message); + PubKey pubKey = PubKey.RecoverCompact(hashedUint256, signature); + + return pubKey.Hash.ToBytes().ToAddress(); + } + + /// + /// Signs a message, returning an ECDSA signature. + /// + /// The private key used to sign the message. + /// The complete message to be signed. + /// The ECDSA signature prepended with header information specifying the correct value of recId. + public static byte[] SignMessage(Key privateKey, byte[] message) + { + uint256 hashedUint256 = GetUint256FromMessage(message); + + return privateKey.SignCompact(hashedUint256); + } + } +} diff --git a/src/Stratis.SmartContracts.CLR/SmartContractState.cs b/src/Stratis.SmartContracts.CLR/SmartContractState.cs index 4770fd6792..dc1b35bc80 100644 --- a/src/Stratis.SmartContracts.CLR/SmartContractState.cs +++ b/src/Stratis.SmartContracts.CLR/SmartContractState.cs @@ -15,7 +15,8 @@ public SmartContractState( IContractLogger contractLogger, IInternalTransactionExecutor internalTransactionExecutor, IInternalHashHelper internalHashHelper, - Func getBalance) + Func getBalance, + IEcRecoverProvider ecRecoverProvider) { this.Block = block; this.Message = message; @@ -25,6 +26,7 @@ public SmartContractState( this.InternalTransactionExecutor = internalTransactionExecutor; this.InternalHashHelper = internalHashHelper; this.GetBalance = getBalance; + this.EcRecoverProvider = ecRecoverProvider; } public IBlock Block { get; } @@ -34,6 +36,7 @@ public SmartContractState( public IPersistentState PersistentState { get; } public ISerializer Serializer { get; } + public IEcRecoverProvider EcRecoverProvider { get; } public IContractLogger ContractLogger { get; } diff --git a/src/Stratis.SmartContracts.CLR/SmartContractStateFactory.cs b/src/Stratis.SmartContracts.CLR/SmartContractStateFactory.cs index 59f6eb6de7..74d35eaa43 100644 --- a/src/Stratis.SmartContracts.CLR/SmartContractStateFactory.cs +++ b/src/Stratis.SmartContracts.CLR/SmartContractStateFactory.cs @@ -9,13 +9,17 @@ public class SmartContractStateFactory : ISmartContractStateFactory { private readonly ISerializer serializer; + private readonly IEcRecoverProvider ecRecoverProvider; + public SmartContractStateFactory(IContractPrimitiveSerializer primitiveSerializer, IInternalExecutorFactory internalTransactionExecutorFactory, - ISerializer serializer) + ISerializer serializer, + IEcRecoverProvider ecRecoverProvider) { this.serializer = serializer; this.PrimitiveSerializer = primitiveSerializer; this.InternalTransactionExecutorFactory = internalTransactionExecutorFactory; + this.ecRecoverProvider = ecRecoverProvider; } public IContractPrimitiveSerializer PrimitiveSerializer { get; } @@ -44,7 +48,8 @@ public ISmartContractState Create(IState state, RuntimeObserver.IGasMeter gasMet contractLogger, this.InternalTransactionExecutorFactory.Create(gasMeter, state), new InternalHashHelper(), - () => state.GetBalance(address)); + () => state.GetBalance(address), + this.ecRecoverProvider); return contractState; } diff --git a/src/Stratis.SmartContracts.IntegrationTests/ECRecoverTests.cs b/src/Stratis.SmartContracts.IntegrationTests/ECRecoverTests.cs new file mode 100644 index 0000000000..0a3dacfda4 --- /dev/null +++ b/src/Stratis.SmartContracts.IntegrationTests/ECRecoverTests.cs @@ -0,0 +1,145 @@ +using System.Threading.Tasks; +using Stratis.Bitcoin.Features.SmartContracts.Models; +using Stratis.SmartContracts.CLR; +using Stratis.SmartContracts.CLR.Compilation; +using Stratis.SmartContracts.CLR.Serialization; +using Stratis.SmartContracts.Core; +using Stratis.SmartContracts.Tests.Common.MockChain; +using Xunit; +using Key = NBitcoin.Key; + +namespace Stratis.SmartContracts.IntegrationTests +{ + public class ECRecoverTests + { + // 2 things to test: + + // 1) That we have the ECDSA code and can make it available. + + [Fact] + public void CanSignAndRetrieveSender() + { + using (PoWMockChain chain = new PoWMockChain(1)) + { + var network = chain.Nodes[0].CoreNode.FullNode.Network; + var privateKey = new Key(); + Address address = privateKey.PubKey.GetAddress(network).ToString().ToAddress(network); + byte[] message = new byte[] {0x69, 0x76, 0xAA}; + + // Sign a message + byte[] offChainSignature = EcRecoverProvider.SignMessage(privateKey, message); + + var ecRecover = new EcRecoverProvider(); + // Get the address out of the signature + Address recoveredAddress = ecRecover.GetSigner(message, offChainSignature); + + // Check that the address matches that generated from the private key. + Assert.Equal(address, recoveredAddress); + } + } + + [Fact] + public void CanCallEcRecoverContractWithValidSignatureAsync() + { + using (PoWMockChain chain = new PoWMockChain(2)) + { + var node1 = chain.Nodes[0]; + + node1.MineBlocks(1); + + var network = chain.Nodes[0].CoreNode.FullNode.Network; + + var privateKey = new Key(); + string address = privateKey.PubKey.GetAddress(network).ToString(); + byte[] message = new byte[] { 0x69, 0x76, 0xAA }; + byte[] signature = EcRecoverProvider.SignMessage(privateKey, message); + + // TODO: If the incorrect parameters are passed to the constructor, the contract does not get properly created ('Method does not exist on contract'), but a success response is still returned? + + byte[] contract = ContractCompiler.CompileFile("SmartContracts/EcRecoverContract.cs").Compilation; + string[] createParameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, address) }; + BuildCreateContractTransactionResponse createResult = node1.SendCreateContractTransaction(contract, 1, createParameters); + + Assert.NotNull(createResult); + Assert.True(createResult.Success); + + node1.WaitMempoolCount(1); + node1.MineBlocks(1); + + string[] callParameters = new string[] + { + string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, message.ToHexString()), + string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, signature.ToHexString()) + }; + + BuildCallContractTransactionResponse response = node1.SendCallContractTransaction("CheckThirdPartySignature", createResult.NewContractAddress, 1, callParameters); + Assert.NotNull(response); + Assert.True(response.Success); + + node1.WaitMempoolCount(1); + node1.MineBlocks(1); + + ReceiptResponse receipt = node1.GetReceipt(response.TransactionId.ToString()); + + Assert.NotNull(receipt); + Assert.True(receipt.Success); + Assert.Equal("True", receipt.ReturnValue); + } + } + + [Fact] + public void CanCallEcRecoverContractWithInvalidSignatureAsync() + { + using (PoWMockChain chain = new PoWMockChain(2)) + { + var node1 = chain.Nodes[0]; + + node1.MineBlocks(1); + + var network = chain.Nodes[0].CoreNode.FullNode.Network; + + var privateKey = new Key(); + string address = privateKey.PubKey.GetAddress(network).ToString(); + byte[] message = new byte[] { 0x69, 0x76, 0xAA }; + + // Make the signature with a key unrelated to the third party signer for the contract. + byte[] signature = EcRecoverProvider.SignMessage(new Key(), message); + + // TODO: If the incorrect parameters are passed to the constructor, the contract does not get properly created ('Method does not exist on contract'), but a success response is still returned? + + byte[] contract = ContractCompiler.CompileFile("SmartContracts/EcRecoverContract.cs").Compilation; + string[] createParameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, address) }; + BuildCreateContractTransactionResponse createResult = node1.SendCreateContractTransaction(contract, 1, createParameters); + + Assert.NotNull(createResult); + Assert.True(createResult.Success); + + node1.WaitMempoolCount(1); + node1.MineBlocks(1); + + string[] callParameters = new string[] + { + string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, message.ToHexString()), + string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, signature.ToHexString()) + }; + + BuildCallContractTransactionResponse response = node1.SendCallContractTransaction("CheckThirdPartySignature", createResult.NewContractAddress, 1, callParameters); + Assert.NotNull(response); + Assert.True(response.Success); + + node1.WaitMempoolCount(1); + node1.MineBlocks(1); + + ReceiptResponse receipt = node1.GetReceipt(response.TransactionId.ToString()); + + Assert.NotNull(receipt); + Assert.True(receipt.Success); + Assert.Equal("False", receipt.ReturnValue); + } + } + + // 2) That we can enable the method in new contracts without affecting the older contracts + + // TODO + } +} diff --git a/src/Stratis.SmartContracts.IntegrationTests/PoW/SmartContractMinerTests.cs b/src/Stratis.SmartContracts.IntegrationTests/PoW/SmartContractMinerTests.cs index d379e7120d..fd6187ddee 100644 --- a/src/Stratis.SmartContracts.IntegrationTests/PoW/SmartContractMinerTests.cs +++ b/src/Stratis.SmartContracts.IntegrationTests/PoW/SmartContractMinerTests.cs @@ -180,6 +180,7 @@ public class TestContext private StateProcessor stateProcessor; private SmartContractStateFactory smartContractStateFactory; public IBlockExecutionResultCache executionCache; + private IEcRecoverProvider ecRecoverProvider; public SmartContractPowConsensusFactory ConsensusFactory { get; private set; } #endregion @@ -348,7 +349,8 @@ private void InitializeSmartContractComponents(string callingMethod) this.internalTxExecutorFactory = new InternalExecutorFactory(this.loggerFactory, this.stateProcessor); this.primitiveSerializer = new ContractPrimitiveSerializer(this.network); this.serializer = new Serializer(this.primitiveSerializer); - this.smartContractStateFactory = new SmartContractStateFactory(this.primitiveSerializer, this.internalTxExecutorFactory, this.serializer); + this.ecRecoverProvider = new EcRecoverProvider(); + this.smartContractStateFactory = new SmartContractStateFactory(this.primitiveSerializer, this.internalTxExecutorFactory, this.serializer, this.ecRecoverProvider); this.stateFactory = new StateFactory(this.smartContractStateFactory); this.ExecutorFactory = new ReflectionExecutorFactory(this.loggerFactory, this.callDataSerializer, this.refundProcessor, this.transferProcessor, this.stateFactory, this.stateProcessor, this.primitiveSerializer); } diff --git a/src/Stratis.SmartContracts.IntegrationTests/SmartContracts/EcRecoverContract.cs b/src/Stratis.SmartContracts.IntegrationTests/SmartContracts/EcRecoverContract.cs new file mode 100644 index 0000000000..ecde22a2b4 --- /dev/null +++ b/src/Stratis.SmartContracts.IntegrationTests/SmartContracts/EcRecoverContract.cs @@ -0,0 +1,28 @@ + +using Stratis.SmartContracts; + +public class EcRecoverContract : SmartContract +{ + public Address ThirdPartySigner + { + get + { + return this.PersistentState.GetAddress(nameof(this.ThirdPartySigner)); + } + set + { + this.PersistentState.SetAddress(nameof(this.ThirdPartySigner), value); + } + } + + public EcRecoverContract(ISmartContractState state, Address thirdPartySigner) : base(state) + { + this.ThirdPartySigner = thirdPartySigner; + } + + public bool CheckThirdPartySignature(byte[] message, byte[] signature) + { + Address signerOfMessage = this.EcRecover(message, signature); + return (signerOfMessage == this.ThirdPartySigner); + } +} diff --git a/src/Stratis.SmartContracts.IntegrationTests/Stratis.SmartContracts.IntegrationTests.csproj b/src/Stratis.SmartContracts.IntegrationTests/Stratis.SmartContracts.IntegrationTests.csproj index 671aa63789..dd50563b98 100644 --- a/src/Stratis.SmartContracts.IntegrationTests/Stratis.SmartContracts.IntegrationTests.csproj +++ b/src/Stratis.SmartContracts.IntegrationTests/Stratis.SmartContracts.IntegrationTests.csproj @@ -90,6 +90,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest