Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECRecover contract upgrade #414

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/NBitcoin/Crypto/ECKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ private void SaveAll()

private void AddInlineStats(StringBuilder benchLog)
{
benchLog.AppendLine("AddressIndexer.Height: ".PadRight(LoggingConfiguration.ColumnLength + 1) + this.IndexerTip.Height.ToString().PadRight(9) +
benchLog.AppendLine("AddressIndexer Height".PadRight(LoggingConfiguration.ColumnLength) + $": {this.IndexerTip.Height}".PadRight(9) +
"AddressCache%: " + this.addressIndexRepository.GetLoadPercentage().ToString().PadRight(8) +
"OutPointCache%: " + this.outpointsRepository.GetLoadPercentage().ToString().PadRight(8) +
$"Ms/block: {Math.Round(this.averageTimePerBlock.Average, 2)}");
Expand Down Expand Up @@ -673,7 +673,7 @@ public LastBalanceDecreaseTransactionModel GetLastBalanceDecreaseTransaction(str
// Height 0 is used as a placeholder height for compacted address balance records, so ignore them if they are the only record.
if (lastBalanceHeight == 0)
return null;

ChainedHeader header = this.chainIndexer.GetHeader(lastBalanceHeight);

if (header == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Stratis.SmartContracts" Version="2.0.0" />
<PackageReference Include="Stratis.SmartContracts" Version="2.0.1-dev" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ public static IFullNodeBuilder AddSmartContracts(this IFullNodeBuilder fullNodeB
services.AddSingleton<SmartContractTransactionPolicy>();
services.AddSingleton<IStateProcessor, StateProcessor>();
services.AddSingleton<ISmartContractStateFactory, SmartContractStateFactory>();
services.AddSingleton<IEcRecoverProvider, EcRecoverProvider>();
services.AddSingleton<ILocalExecutor, LocalExecutor>();
services.AddSingleton<IBlockExecutionResultCache, BlockExecutionResultCache>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<ItemGroup>
<PackageReference Include="CSharpFunctionalExtensions" Version="1.10.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="3.0.1" />
<PackageReference Include="Stratis.SmartContracts" Version="2.0.0" />
<PackageReference Include="Stratis.SmartContracts" Version="2.0.1-dev" />
</ItemGroup>

<ItemGroup>
Expand All @@ -24,5 +24,4 @@
<ProjectReference Include="..\Stratis.SmartContracts.Core\Stratis.SmartContracts.Core.csproj" />
<ProjectReference Include="..\Stratis.SmartContracts.CLR\Stratis.SmartContracts.CLR.csproj" />
</ItemGroup>

</Project>
2 changes: 0 additions & 2 deletions src/Stratis.Bitcoin.Features.Wallet/WalletFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,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)
Expand Down
1 change: 1 addition & 0 deletions src/Stratis.Bitcoin/Connection/ConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
23 changes: 16 additions & 7 deletions src/Stratis.CirrusDnsD/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Stratis.Bitcoin;
using Stratis.Bitcoin.Builder;
using Stratis.Bitcoin.Configuration;
using Stratis.Bitcoin.Consensus;
using Stratis.Bitcoin.Features.Api;
using Stratis.Bitcoin.Features.BlockStore;
using Stratis.Bitcoin.Features.Dns;
Expand All @@ -12,8 +13,10 @@
using Stratis.Bitcoin.Features.SmartContracts;
using Stratis.Bitcoin.Features.SmartContracts.PoA;
using Stratis.Bitcoin.Features.SmartContracts.Wallet;
using Stratis.Bitcoin.Networks;
using Stratis.Bitcoin.Utilities;
using Stratis.Features.Collateral;
using Stratis.Features.Collateral.CounterChain;
using Stratis.Features.SQLiteWalletRepository;
using Stratis.Sidechains.Networks;

Expand Down Expand Up @@ -67,26 +70,32 @@ public static async Task Main(string[] args)

private static IFullNode GetSideChainFullNode(NodeSettings nodeSettings)
{
IFullNode node = new FullNodeBuilder()
.UseNodeSettings(nodeSettings)
.UseBlockStore()
DbType dbType = nodeSettings.GetDbType();

IFullNodeBuilder nodeBuilder = new FullNodeBuilder()
.UseNodeSettings(nodeSettings, dbType)
.UseBlockStore(dbType)
.UseMempool()
.AddSmartContracts(options =>
{
options.UseReflectionExecutor();
options.UsePoAWhitelistedContracts();
})
.AddPoAFeature()
.UsePoAConsensus()
.UsePoAConsensus(dbType)
.CheckCollateralCommitment()

// This needs to be set so that we can check the magic bytes during the Strat to Strax changeover.
// Perhaps we can introduce a block height check rather?
.SetCounterChainNetwork(StraxNetwork.MainChainNetworks[nodeSettings.Network.NetworkType]())

.UseSmartContractWallet()
.AddSQLiteWalletRepository()
.UseApi()
.AddRPC()
.UseDns()
.Build();
.UseDns();

return node;
return nodeBuilder.Build();
}

private static IFullNode GetDnsNode(NodeSettings nodeSettings)
Expand Down
1 change: 1 addition & 0 deletions src/Stratis.CirrusDnsD/Stratis.CirrusDnsD.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<ItemGroup>
<ProjectReference Include="..\Stratis.Bitcoin.Features.Api\Stratis.Bitcoin.Features.Api.csproj" />
<ProjectReference Include="..\Stratis.Bitcoin.Features.Dns\Stratis.Bitcoin.Features.Dns.csproj" />
<ProjectReference Include="..\Stratis.Bitcoin.Networks\Stratis.Bitcoin.Networks.csproj" />
<ProjectReference Include="..\Stratis.Bitcoin\Stratis.Bitcoin.csproj" />
<ProjectReference Include="..\Stratis.Features.Collateral\Stratis.Features.Collateral.csproj" />
<ProjectReference Include="..\Stratis.Features.SQLiteWalletRepository\Stratis.Features.SQLiteWalletRepository.csproj" />
Expand Down
6 changes: 5 additions & 1 deletion src/Stratis.SmartContracts.CLR.Tests/AuctionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public AuctionTests()
null,
getBalance,
null,
null,
null
);
}
Expand Down Expand Up @@ -88,7 +89,8 @@ public TestSmartContractState(
IInternalTransactionExecutor transactionExecutor,
Func<ulong> getBalance,
IInternalHashHelper hashHelper,
IContractLogger contractLogger)
IContractLogger contractLogger,
IEcRecoverProvider ecRecoverProvider)
{
this.Block = block;
this.Message = message;
Expand All @@ -99,6 +101,7 @@ public TestSmartContractState(
this.GetBalance = getBalance;
this.InternalHashHelper = hashHelper;
this.ContractLogger = contractLogger;
this.EcRecoverProvider = ecRecoverProvider;
}

public IBlock Block { get; }
Expand All @@ -110,6 +113,7 @@ public TestSmartContractState(
public Func<ulong> GetBalance { get; }
public IInternalHashHelper InternalHashHelper { get; }
public IContractLogger ContractLogger { get; }
public IEcRecoverProvider EcRecoverProvider { get; }
}

public class TestBlock : IBlock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand All @@ -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.Network);
this.SmartContractStateFactory = new SmartContractStateFactory(this.ContractPrimitiveSerializer, this.InternalTxExecutorFactory, this.Serializer, this.EcRecoverProvider);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -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.network);
this.smartContractStateFactory = new SmartContractStateFactory(this.contractPrimitiveSerializer, this.internalTxExecutorFactory, this.serializer, this.ecRecoverProvider);

this.callDataSerializer = new CallDataSerializer(this.contractPrimitiveSerializer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ public ObserverInstanceRewriterTests()
new ContractLogHolder(),
Mock.Of<IInternalTransactionExecutor>(),
new InternalHashHelper(),
() => 1000);
() => 1000,
Mock.Of<IEcRecoverProvider>());

this.rewriter = new ObserverInstanceRewriter();
}
Expand Down
3 changes: 2 additions & 1 deletion src/Stratis.SmartContracts.CLR.Tests/ObserverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ public ObserverTests()
new ContractLogHolder(),
Mock.Of<IInternalTransactionExecutor>(),
new InternalHashHelper(),
() => 1000);
() => 1000,
Mock.Of<IEcRecoverProvider>());

this.rewriter = new ObserverRewriter(new Observer(this.gasMeter, new MemoryMeter(ReflectionVirtualMachine.MemoryUnitLimit)));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Reflection;
using System.Text;
using CSharpFunctionalExtensions;
using Moq;
using NBitcoin;
using Stratis.SmartContracts.CLR.Caching;
Expand Down Expand Up @@ -46,7 +45,8 @@ public ReflectionVirtualMachineTests()
new ContractLogHolder(),
Mock.Of<IInternalTransactionExecutor>(),
new InternalHashHelper(),
() => 1000);
() => 1000,
Mock.Of<IEcRecoverProvider>());
this.gasMeter = new GasMeter((RuntimeObserver.Gas)50_000);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.10.1" />
<PackageReference Include="Stratis.SmartContracts" Version="2.0.0" />
<PackageReference Include="Stratis.SmartContracts" Version="2.0.1-dev" />
<PackageReference Include="Stratis.SmartContracts.Standards" Version="2.0.0" />
</ItemGroup>

Expand Down
55 changes: 55 additions & 0 deletions src/Stratis.SmartContracts.CLR/EcRecoverProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using NBitcoin;
using NBitcoin.Crypto;
using Stratis.SmartContracts.Core.Hashing;

namespace Stratis.SmartContracts.CLR
{
/// <summary>
/// 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.
/// </summary>
public class EcRecoverProvider : IEcRecoverProvider
{
private readonly Network network;

public EcRecoverProvider(Network network)
{
this.network = network;
}

private static uint256 GetUint256FromMessage(byte[] message)
{
return new uint256(HashHelper.Keccak256(message));
}

/// <summary>
/// Retrieves the base58 address of the signer of an ECDSA signature.
/// </summary>
/// <param name="message"></param>
/// <param name="signature">The ECDSA signature prepended with header information specifying the correct value of recId.</param>
/// <returns>The base58 address for the signer of a signature.</returns>
public Address GetSigner(byte[] message, byte[] signature)
{
// TODO: Error handling for incorrect signature format etc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be resolved before this can be used in production.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rowandh PubKey.RecoverCompact already detects incorrect format and raise an exception.

There is something else to do in here ?


uint256 hashedUint256 = GetUint256FromMessage(message);
PubKey pubKey = PubKey.RecoverCompact(hashedUint256, signature);

return pubKey.GetAddress(this.network).ToString().ToAddress(this.network);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this conversion can be done without using this.network.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}

/// <summary>
/// Signs a message, returning an ECDSA signature.
/// </summary>
/// <param name="privateKey">The private key used to sign the message.</param>
/// <param name="message">The complete message to be signed.</param>
/// <returns>The ECDSA signature prepended with header information specifying the correct value of recId.</returns>
public static byte[] SignMessage(Key privateKey, byte[] message)
{
uint256 hashedUint256 = GetUint256FromMessage(message);

return privateKey.SignCompact(hashedUint256);
}
}
}
5 changes: 4 additions & 1 deletion src/Stratis.SmartContracts.CLR/SmartContractState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public SmartContractState(
IContractLogger contractLogger,
IInternalTransactionExecutor internalTransactionExecutor,
IInternalHashHelper internalHashHelper,
Func<ulong> getBalance)
Func<ulong> getBalance,
IEcRecoverProvider ecRecoverProvider)
{
this.Block = block;
this.Message = message;
Expand All @@ -25,6 +26,7 @@ public SmartContractState(
this.InternalTransactionExecutor = internalTransactionExecutor;
this.InternalHashHelper = internalHashHelper;
this.GetBalance = getBalance;
this.EcRecoverProvider = ecRecoverProvider;
}

public IBlock Block { get; }
Expand All @@ -34,6 +36,7 @@ public SmartContractState(
public IPersistentState PersistentState { get; }

public ISerializer Serializer { get; }
public IEcRecoverProvider EcRecoverProvider { get; }

public IContractLogger ContractLogger { get; }

Expand Down
9 changes: 7 additions & 2 deletions src/Stratis.SmartContracts.CLR/SmartContractStateFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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;
}
Expand Down
Loading