Skip to content

Commit 8c70661

Browse files
authored
Refactor Bitcoin networks and support MutinyNet (MetacoSA#1222)
This PR refactors Network and its Bitcoin networks, in that it pulls them to the NetworkSet class to reduce its coupling and make their instantiation similar to how every other network is created. It is IMO a much cleaner result. Additioanlly, it adds support for MutinyNet, a custom signet network with 30s blocks and many covenant soft forks activated. Most of LN testing infra runs on Mutinynet, and is very useful.
1 parent 52fb9fb commit 8c70661

9 files changed

+1972
-1608
lines changed

Diff for: NBitcoin.Tests/NetworkTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public void CanGetNetworkFromName()
1818
Assert.Equal(Network.GetNetwork("regtest"), Network.RegTest);
1919
Assert.Equal(Network.GetNetwork("testnet"), Network.TestNet);
2020
Assert.Equal(Network.GetNetwork("testnet3"), Network.TestNet);
21+
Assert.Equal(Network.GetNetwork("signet"), Bitcoin.Instance.Signet);
22+
Assert.Equal(Network.GetNetwork("mutinynet"), Bitcoin.Instance.Mutinynet);
2123
Assert.Null(Network.GetNetwork("invalid"));
2224
}
2325

Diff for: NBitcoin/Bitcoin.Mainnet.cs

+1,498
Large diffs are not rendered by default.

Diff for: NBitcoin/Bitcoin.MutinyNet.cs

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System;
2+
using System.IO;
3+
using NBitcoin.Crypto;
4+
5+
namespace NBitcoin
6+
{
7+
public partial class Bitcoin
8+
{
9+
static readonly ChainName MutinynetName = new("Mutinynet");
10+
11+
public Network Mutinynet => _Networks[MutinynetName];
12+
13+
private Network CreateMutinyNet()
14+
{
15+
NetworkBuilder builder = new NetworkBuilder();
16+
builder.SetChainName(MutinynetName);
17+
builder.SetNetworkSet(this);
18+
builder.SetConsensus(new Consensus()
19+
{
20+
SubsidyHalvingInterval = 210000,
21+
MajorityEnforceBlockUpgrade = 750,
22+
MajorityRejectBlockOutdated = 950,
23+
MajorityWindow = 1000,
24+
BIP34Hash = new uint256(),
25+
PowLimit = new Target(
26+
new uint256("00000377ae000000000000000000000000000000000000000000000000000000")),
27+
PowTargetTimespan = TimeSpan.FromSeconds(14 * 24 * 60 * 60),
28+
PowTargetSpacing = TimeSpan.FromSeconds(30),
29+
PowAllowMinDifficultyBlocks = false,
30+
PowNoRetargeting = false,
31+
RuleChangeActivationThreshold = 1916,
32+
MinerConfirmationWindow = 2016,
33+
CoinbaseMaturity = 100,
34+
SupportSegwit = true,
35+
SupportTaproot = true
36+
})
37+
.SetBase58Bytes(Base58Type.PUBKEY_ADDRESS, new byte[] {111})
38+
.SetBase58Bytes(Base58Type.SCRIPT_ADDRESS, new byte[] {196})
39+
.SetBase58Bytes(Base58Type.SECRET_KEY, new byte[] {239})
40+
.SetBase58Bytes(Base58Type.EXT_PUBLIC_KEY, new byte[] {0x04, 0x35, 0x87, 0xCF})
41+
.SetBase58Bytes(Base58Type.EXT_SECRET_KEY, new byte[] {0x04, 0x35, 0x83, 0x94})
42+
.SetBech32(Bech32Type.WITNESS_PUBKEY_ADDRESS, "tb")
43+
.SetBech32(Bech32Type.WITNESS_SCRIPT_ADDRESS, "tb")
44+
.SetBech32(Bech32Type.TAPROOT_ADDRESS, "tb")
45+
.SetMagic(GetMutinynetMagic())
46+
.SetPort(38333)
47+
.SetRPCPort(38332)
48+
.SetName("mutinynet")
49+
.AddAlias("bitcoin-mutinynet")
50+
.AddAlias("btc-mutinynet")
51+
#if !NOSOCKET
52+
.AddSeeds(new[]
53+
{
54+
new Protocol.NetworkAddress(System.Net.IPAddress.Parse("45.79.52.207"), 38333)
55+
})
56+
#endif
57+
.SetGenesis(
58+
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a008f4d5fae77031e8ad222030101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000");
59+
60+
var network = builder.BuildAndRegister();
61+
#if !NOFILEIO
62+
var data = Network.GetDefaultDataFolder("bitcoin");
63+
if (data != null)
64+
{
65+
var signetCookie = Path.Combine(data, "signet", ".cookie");
66+
RPC.RPCClient.RegisterDefaultCookiePath(network, signetCookie);
67+
}
68+
#endif
69+
_Networks.TryAdd(MutinynetName, network);
70+
return network;
71+
}
72+
73+
74+
private static uint GetMutinynetMagic()
75+
{
76+
var challengeBytes = DataEncoders.Encoders.Hex.DecodeData(
77+
"512102f7561d208dd9ae99bf497273e16f389bdbd6c4742ddb8e6b216e64fa2928ad8f51ae");
78+
var challenge = new Script(challengeBytes);
79+
MemoryStream ms = new MemoryStream();
80+
BitcoinStream bitcoinStream = new BitcoinStream(ms, true);
81+
bitcoinStream.ReadWrite(challenge);
82+
var h = Hashes.DoubleSHA256RawBytes(ms.ToArray(), 0, (int) ms.Length);
83+
return Utils.ToUInt32(h, true);
84+
}
85+
86+
}
87+
}

Diff for: NBitcoin/Bitcoin.Regtest.cs

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System;
2+
using System.Linq;
3+
using NBitcoin.DataEncoders;
4+
5+
namespace NBitcoin
6+
{
7+
public partial class Bitcoin
8+
{
9+
public Network Regtest => _Networks[ChainName.Regtest];
10+
11+
private Network CreateRegtest()
12+
{
13+
NetworkBuilder builder = new NetworkBuilder();
14+
builder.SetGenesis("0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000");
15+
builder.SetMagic(0xDAB5BFFA);
16+
builder.SetMaxP2PVersion(Network.BITCOIN_MAX_P2P_VERSION);
17+
builder.SetUriScheme(null);
18+
builder.SetChainName(ChainName.Regtest);
19+
builder.SetName("RegTest");
20+
builder.AddAlias("regtest");
21+
builder.AddAlias("reg");
22+
builder.AddAlias("regnet");
23+
builder.AddAlias("btc-regtest");
24+
builder.SetNetworkSet(this);
25+
builder.SetPort(18444);
26+
builder.SetRPCPort(18443);
27+
28+
for (var index = 0; index < Testnet.base58Prefixes.Length; index++)
29+
{
30+
var val = Testnet.base58Prefixes[index];
31+
builder.SetBase58Bytes((Base58Type)index, val);
32+
}
33+
34+
35+
36+
builder.SetBase58Bytes(Base58Type.PUBKEY_ADDRESS, new byte[] {(111)});
37+
builder.SetBase58Bytes( Base58Type.SCRIPT_ADDRESS,new byte[] {(196)});
38+
builder.SetBase58Bytes( Base58Type.SECRET_KEY,new byte[] {(239)});
39+
builder.SetBase58Bytes( Base58Type.EXT_PUBLIC_KEY, new byte[] {(0x04), (0x35), (0x87), (0xCF)});
40+
builder.SetBase58Bytes( Base58Type.EXT_SECRET_KEY, new byte[] {(0x04), (0x35), (0x83), (0x94)});
41+
builder.SetBase58Bytes( Base58Type.COLORED_ADDRESS, new byte[] {0x13});
42+
43+
44+
45+
var encoder = new Bech32Encoder("bcrt");
46+
47+
builder.SetBech32(Bech32Type.WITNESS_PUBKEY_ADDRESS, encoder);
48+
builder.SetBech32(Bech32Type.WITNESS_SCRIPT_ADDRESS, encoder);
49+
builder.SetBech32(Bech32Type.TAPROOT_ADDRESS, encoder);
50+
51+
52+
53+
var consensus = new Consensus()
54+
{
55+
SubsidyHalvingInterval = 150,
56+
MajorityEnforceBlockUpgrade = 750,
57+
MajorityRejectBlockOutdated = 950,
58+
MajorityWindow = 1000,
59+
BIP34Hash = new uint256(),
60+
PowLimit = new Target(new uint256("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")),
61+
MinimumChainWork = uint256.Zero,
62+
PowTargetTimespan = TimeSpan.FromSeconds(14 * 24 * 60 * 60), // two weeks
63+
PowTargetSpacing = TimeSpan.FromSeconds(10 * 60),
64+
PowAllowMinDifficultyBlocks = true,
65+
PowNoRetargeting = true,
66+
RuleChangeActivationThreshold = 108,
67+
MinerConfirmationWindow = 144,
68+
SupportTaproot = true,
69+
SupportSegwit = true,
70+
CoinType = 1,
71+
};
72+
73+
// Modify the testnet genesis block so the timestamp is valid for a later start.
74+
consensus.SetBlock(builder._Genesis);
75+
76+
consensus.BuriedDeployments[BuriedDeployments.BIP34] = 100000000;
77+
consensus.BuriedDeployments[BuriedDeployments.BIP65] = 100000000;
78+
consensus.BuriedDeployments[BuriedDeployments.BIP66] = 100000000;
79+
80+
consensus.BIP9Deployments[BIP9Deployments.TestDummy] = new BIP9DeploymentsParameters(28, 0, 999999999);
81+
consensus.BIP9Deployments[BIP9Deployments.CSV] = new BIP9DeploymentsParameters(0, 0, 999999999);
82+
consensus.BIP9Deployments[BIP9Deployments.Segwit] = new BIP9DeploymentsParameters(1, BIP9DeploymentsParameters.AlwaysActive, 999999999);
83+
84+
85+
builder.SetConsensus(consensus);
86+
var result = builder.BuildAndRegister();
87+
88+
_Networks.TryAdd(ChainName.Regtest, result);
89+
90+
assert(Regtest.Consensus.HashGenesisBlock ==
91+
uint256.Parse("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
92+
return result;
93+
}
94+
95+
96+
97+
}
98+
}

Diff for: NBitcoin/Bitcoin.Signet.cs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using NBitcoin.Crypto;
2+
using System;
3+
using System.IO;
4+
using System.Linq;
5+
6+
namespace NBitcoin
7+
{
8+
public partial class Bitcoin
9+
{
10+
static readonly ChainName SignetName = new ChainName("Signet");
11+
12+
public Network Signet => _Networks[SignetName];
13+
14+
private Network CreateSignet()
15+
{
16+
NetworkBuilder builder = new NetworkBuilder();
17+
builder.SetChainName(SignetName);
18+
builder.SetNetworkSet(this);
19+
builder.SetConsensus(new Consensus()
20+
{
21+
SubsidyHalvingInterval = 210000,
22+
MajorityEnforceBlockUpgrade = 750,
23+
MajorityRejectBlockOutdated = 950,
24+
MajorityWindow = 1000,
25+
BIP34Hash = new uint256(),
26+
PowLimit = new Target(
27+
new uint256("00000377ae000000000000000000000000000000000000000000000000000000")),
28+
PowTargetTimespan = TimeSpan.FromSeconds(14 * 24 * 60 * 60),
29+
PowTargetSpacing = TimeSpan.FromSeconds(10 * 60),
30+
PowAllowMinDifficultyBlocks = false,
31+
PowNoRetargeting = false,
32+
RuleChangeActivationThreshold = 1916,
33+
MinerConfirmationWindow = 2016,
34+
CoinbaseMaturity = 100,
35+
SupportSegwit = true,
36+
SupportTaproot = true
37+
})
38+
.SetBase58Bytes(Base58Type.PUBKEY_ADDRESS, new byte[] {111})
39+
.SetBase58Bytes(Base58Type.SCRIPT_ADDRESS, new byte[] {196})
40+
.SetBase58Bytes(Base58Type.SECRET_KEY, new byte[] {239})
41+
.SetBase58Bytes(Base58Type.EXT_PUBLIC_KEY, new byte[] {0x04, 0x35, 0x87, 0xCF})
42+
.SetBase58Bytes(Base58Type.EXT_SECRET_KEY, new byte[] {0x04, 0x35, 0x83, 0x94})
43+
.SetBech32(Bech32Type.WITNESS_PUBKEY_ADDRESS, "tb")
44+
.SetBech32(Bech32Type.WITNESS_SCRIPT_ADDRESS, "tb")
45+
.SetBech32(Bech32Type.TAPROOT_ADDRESS, "tb")
46+
.SetMagic(GetSignetMagic())
47+
.SetPort(38333)
48+
.SetRPCPort(38332)
49+
.SetName("signet")
50+
.AddAlias("bitcoin-signet")
51+
.AddAlias("btc-signet")
52+
#if !NOSOCKET
53+
.AddSeeds(new[]
54+
{
55+
"178.128.221.177",
56+
"2a01:7c8:d005:390::5"
57+
}.Select(o => new Protocol.NetworkAddress(System.Net.IPAddress.Parse(o))))
58+
#endif
59+
.SetGenesis(
60+
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a008f4d5fae77031e8ad222030101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000");
61+
62+
var network = builder.BuildAndRegister();
63+
#if !NOFILEIO
64+
var data = Network.GetDefaultDataFolder("bitcoin");
65+
if (data != null)
66+
{
67+
var signetCookie = Path.Combine(data, "signet", ".cookie");
68+
RPC.RPCClient.RegisterDefaultCookiePath(network, signetCookie);
69+
}
70+
#endif
71+
_Networks.TryAdd(SignetName, network);
72+
return network;
73+
}
74+
75+
private static uint GetSignetMagic()
76+
{
77+
var challengeBytes = DataEncoders.Encoders.Hex.DecodeData(
78+
"512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
79+
var challenge = new Script(challengeBytes);
80+
MemoryStream ms = new MemoryStream();
81+
BitcoinStream bitcoinStream = new BitcoinStream(ms, true);
82+
bitcoinStream.ReadWrite(challenge);
83+
var h = Hashes.DoubleSHA256RawBytes(ms.ToArray(), 0, (int) ms.Length);
84+
return Utils.ToUInt32(h, true);
85+
}
86+
87+
}
88+
}

0 commit comments

Comments
 (0)