Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions src/Blockcore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Networks.Impleum"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Networks.BCP", "Networks\Blockcore.Networks.BCP\Blockcore.Networks.BCP.csproj", "{120500DF-C04F-43CC-9A1E-523A6429301F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Networks.Strax", "Networks\Blockcore.Networks.Strax\Blockcore.Networks.Strax.csproj", "{17330538-D54C-44B0-85AD-D652453FAD65}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Networks.X1", "Networks\Blockcore.Networks.X1\Blockcore.Networks.X1.csproj", "{9A2BA15A-C316-42B4-8E4D-E01B4873190C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Networks.XRC", "Networks\Blockcore.Networks.XRC\Blockcore.Networks.XRC.csproj", "{4615D1C6-14CD-47CA-8B78-A462A37057F6}"
Expand Down Expand Up @@ -364,6 +366,10 @@ Global
{120500DF-C04F-43CC-9A1E-523A6429301F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{120500DF-C04F-43CC-9A1E-523A6429301F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{120500DF-C04F-43CC-9A1E-523A6429301F}.Release|Any CPU.Build.0 = Release|Any CPU
{17330538-D54C-44B0-85AD-D652453FAD65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17330538-D54C-44B0-85AD-D652453FAD65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17330538-D54C-44B0-85AD-D652453FAD65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17330538-D54C-44B0-85AD-D652453FAD65}.Release|Any CPU.Build.0 = Release|Any CPU
{9A2BA15A-C316-42B4-8E4D-E01B4873190C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A2BA15A-C316-42B4-8E4D-E01B4873190C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A2BA15A-C316-42B4-8E4D-E01B4873190C}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -440,6 +446,7 @@ Global
{4275AF0C-587B-4C9D-A100-0F2DD1702674} = {64694A14-97E0-4CBC-8032-754F9353B2DD}
{64E9C309-867E-45F6-A88E-7BC061305D0B} = {3B56C02B-4468-4268-B797-851562789FCC}
{120500DF-C04F-43CC-9A1E-523A6429301F} = {3B56C02B-4468-4268-B797-851562789FCC}
{17330538-D54C-44B0-85AD-D652453FAD65} = {3B56C02B-4468-4268-B797-851562789FCC}
{9A2BA15A-C316-42B4-8E4D-E01B4873190C} = {3B56C02B-4468-4268-B797-851562789FCC}
{4615D1C6-14CD-47CA-8B78-A462A37057F6} = {3B56C02B-4468-4268-B797-851562789FCC}
{074057D3-A1BE-409D-B4B4-F01CFA434D58} = {3B56C02B-4468-4268-B797-851562789FCC}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<AssemblyTitle>Blockcore.Networks.Strax</AssemblyTitle>
<AssemblyName>Blockcore.Networks.Strax</AssemblyName>
<PackageId>Blockcore.Networks.Strax</PackageId>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<IsPackable>true</IsPackable>
</PropertyGroup>

<ItemGroup>
<EmbeddedResource Include="icon.png" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Features\Blockcore.Features.Consensus\Blockcore.Features.Consensus.csproj" />
<ProjectReference Include="..\..\Features\Blockcore.Features.MemoryPool\Blockcore.Features.MemoryPool.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Blockcore.Base.Deployments;
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Consensus.TransactionInfo;

namespace Blockcore.Networks.Strax.Deployments
{
/// <summary>
/// BIP9 deployments for the Strax network.
/// </summary>
public class StraxBIP9Deployments : BIP9DeploymentsArray
{
// The position of each deployment in the deployments array. Note that this is decoupled from the actual position of the flag bit for the deployment in the block version.
public const int CSV = 0;
public const int Segwit = 1;
public const int ColdStaking = 2;

// The number of deployments.
public const int NumberOfDeployments = 3;

/// <summary>
/// Constructs the BIP9 deployments array.
/// </summary>
public StraxBIP9Deployments() : base(NumberOfDeployments)
{
}

/// <summary>
/// Gets the deployment flags to set when the deployment activates.
/// </summary>
/// <param name="deployment">The deployment number.</param>
/// <returns>The deployment flags.</returns>
public override BIP9DeploymentFlags GetFlags(int deployment)
{
// The flags get combined in the caller, so it is ok to make a fresh object here.
var flags = new BIP9DeploymentFlags();

switch (deployment)
{
case ColdStaking:
flags.ScriptFlags = ScriptVerify.CheckColdStakeVerify;
break;

case CSV:
// Start enforcing BIP68 (sequence locks), BIP112 (CHECKSEQUENCEVERIFY) and BIP113 (Median Time Past) using versionbits logic.
flags.ScriptFlags = ScriptVerify.CheckSequenceVerify;
flags.LockTimeFlags = Transaction.LockTimeFlags.VerifySequence | Transaction.LockTimeFlags.MedianTimePast;
break;

case Segwit:
// Start enforcing WITNESS rules using versionbits logic.
flags.ScriptFlags = ScriptVerify.Witness;
break;
}

return flags;
}
}
}
178 changes: 178 additions & 0 deletions src/Networks/Blockcore.Networks.Strax/Federation/Federation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Networks.Strax.ScriptTemplates;
using NBitcoin;

namespace Blockcore.Networks.Strax.Federation
{
public interface IFederation
{
Script MultisigScript { get; }
FederationId Id { get; }

(PubKey[] transactionSigningKeys, int signaturesRequired) GetFederationDetails();
}

/// <summary>
/// Compares two byte arrays for equality.
/// </summary>
public sealed class ByteArrayComparer : IEqualityComparer<byte[]>, IComparer<byte[]>
{
public int Compare(byte[] first, byte[] second)
{
int firstLen = first?.Length ?? -1;
int secondLen = second?.Length ?? -1;
int commonLen = Math.Min(firstLen, secondLen);

for (int i = 0; i < commonLen; i++)
{
if (first[i] == second[i])
continue;

return (first[i] < second[i]) ? -1 : 1;
}

return firstLen.CompareTo(secondLen);
}

public bool Equals(byte[] first, byte[] second)
{
return this.Compare(first, second) == 0;
}

public int GetHashCode(byte[] obj)
{
ulong hash = 17;

foreach (byte objByte in obj)
{
hash = (hash << 5) - hash + objByte;
}

return (int)hash;
}
}

public class FederationId : IBitcoinSerializable
{
byte[] federationId;
ByteArrayComparer comparer;

public FederationId()
{
}

public FederationId(byte[] value)
{
this.federationId = value;
this.comparer = new ByteArrayComparer();
}

public void ReadWrite(BitcoinStream s)
{
s.ReadWrite(ref this.federationId);
}

public override bool Equals(object obj)
{
return this.comparer.Equals(((FederationId)obj).federationId, this.federationId);
}

public override int GetHashCode()
{
return this.comparer.GetHashCode(this.federationId);
}
}

public class Federation : IFederation
{
private PubKey[] transactionSigningKeys;

private int signaturesRequired;

public Script MultisigScript { get; private set; }

public FederationId Id { get; private set; }

/// <summary>
/// Creates a new federation from a set of transaction signing keys.
/// </summary>
/// <param name="transactionSigningPubKeys">A list of transaction signing PubKeys.</param>
/// <param name="signaturesRequired">The amount of signatures required to ensure that the transaction is fully signed.</param>
public Federation(IEnumerable<PubKey> transactionSigningPubKeys, int? signaturesRequired = null)
{
// Ensures that the federation id will always map to the same members in the same order.
this.transactionSigningKeys = transactionSigningPubKeys.OrderBy(k => k.ToHex()).ToArray();
this.signaturesRequired = signaturesRequired ?? (this.transactionSigningKeys.Length + 1) / 2;

// The federationId is derived by XOR'ing all the genesis federation members.
byte[] federationId = this.transactionSigningKeys.First().ToBytes();
foreach (PubKey pubKey in this.transactionSigningKeys.Skip(1))
{
byte[] pubKeyBytes = pubKey.ToBytes();
for (int i = 0; i < federationId.Length; i++)
federationId[i] ^= pubKeyBytes[i];
}

this.Id = new FederationId(federationId);
this.MultisigScript = PayToFederationTemplate.Instance.GenerateScriptPubKey(this.Id);
}

public (PubKey[] transactionSigningKeys, int signaturesRequired) GetFederationDetails()
{
// Until dynamic membership is implemented we just return the genesis members.
return (this.transactionSigningKeys, this.signaturesRequired);
}
}

public interface IFederations
{
/// <summary>
/// Registers a new federation with transaction signing keys.
/// </summary>
/// <param name="federation">The federation to be registered.</param>
void RegisterFederation(IFederation federation);

IFederation GetFederation(FederationId federationId);

IFederation GetFederation(byte[] federationId);

IFederation GetOnlyFederation();
}

public class Federations : IFederations
{
private readonly Dictionary<FederationId, IFederation> federations;

public Federations()
{
this.federations = new Dictionary<FederationId, IFederation>();
}

public IFederation GetFederation(FederationId federationId)
{
return this.federations.TryGetValue(federationId, out IFederation federation) ? federation : null;
}

public IFederation GetFederation(byte[] federationId)
{
return this.federations.TryGetValue(new FederationId(federationId), out IFederation federation) ? federation : null;
}

// TODO: Deprectate this method when multiple federations are supported.
public IFederation GetOnlyFederation()
{
return this.federations.First().Value;
}

public void RegisterFederation(IFederation federation)
{
// TODO: Remove this when multiple federations are supported.
this.federations.Clear();

this.federations[federation.Id] = federation;
}
}
}
13 changes: 13 additions & 0 deletions src/Networks/Blockcore.Networks.Strax/Networks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Blockcore.Networks.Strax
{
public static class Networks
{
public static NetworksSelector Strax
{
get
{
return new NetworksSelector(() => new StraxMain(), () => new StraxTest(), () => new StraxRegTest());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using Blockcore.Consensus.ScriptInfo;
using Blockcore.Networks.Strax.ScriptTemplates;

namespace Blockcore.Networks.Strax.Policies
{
/// <summary>
/// Strax-specific standard transaction definitions.
/// </summary>
public class StraxStandardScriptsRegistry : StandardScriptsRegistry
{
public const int MaxOpReturnRelay = 83;

// Need a network-specific version of the template list
private static readonly List<ScriptTemplate> standardTemplates = new List<ScriptTemplate>
{
new PayToPubkeyHashTemplate(),
new PayToPubkeyTemplate(),
new PayToScriptHashTemplate(),
new PayToMultiSigTemplate(),
new PayToFederationTemplate(),
new TxNullDataTemplate(MaxOpReturnRelay),
new PayToWitTemplate()
};

public override List<ScriptTemplate> GetScriptTemplates => standardTemplates;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Blockcore.Consensus;
using Blockcore.Consensus.Chain;
using Blockcore.Consensus.Rules;
using Blockcore.Features.Consensus.Rules.CommonRules;
using Blockcore.Utilities;
using Microsoft.Extensions.Logging;

namespace Blockcore.Networks.Strax.Rules
{
/// <summary>
/// Checks if <see cref="StraxMain"/> network block's header has a valid block version.
/// </summary>
public class StratisHeaderVersionRule : HeaderVersionRule
{
/// <inheritdoc />
/// <exception cref="ConsensusErrors.BadVersion">Thrown if block's version is outdated or otherwise invalid.</exception>
public override void Run(RuleContext context)
{
Guard.NotNull(context.ValidationContext.ChainedHeaderToValidate, nameof(context.ValidationContext.ChainedHeaderToValidate));

ChainedHeader chainedHeader = context.ValidationContext.ChainedHeaderToValidate;

// A version of precisely 7 is what was generated by the legacy stratisX C++ nodes.

// The stratisX block validation rules mandate if (!IsProtocolV3(nTime)) && (nVersion > 7), then reject block.
// Further, if (IsProtocolV2(nHeight) && nVersion < 7), then reject block.
// And lastly, if (!IsProtocolV2(nHeight) && nVersion > 6), then reject block.

// Protocol version determination is based on either the block height or timestamp as shown:
// IsProtocolV2(nHeight) { return TestNet() || nHeight > 0; }
// IsProtocolV3(nTime) { return TestNet() || nTime > 1470467000; }

// The Stratis mainnet genesis block has nTime = 1470713393, so V3 is applied immediately and this supersedes V2.
// The block versions have therefore been version 7 since genesis on Stratis mainnet.

// Whereas BIP9 mandates that the top bits of version be 001. So a standard node should never generate
// block versions above 7 and below 0x20000000.

// The acceptable common subset of the rules is therefore that the block version must be >= 7.

if (chainedHeader.Header.Version < 7)
{
this.Logger.LogTrace("(-)[BAD_VERSION]");
ConsensusErrors.BadVersion.Throw();
}
}
}
}
Loading