diff --git a/NBitcoin.Altcoins/Bitcoinplus.cs b/NBitcoin.Altcoins/Bitcoinplus.cs
index 4f3ddfdcb5..16ce60464a 100644
--- a/NBitcoin.Altcoins/Bitcoinplus.cs
+++ b/NBitcoin.Altcoins/Bitcoinplus.cs
@@ -338,11 +338,7 @@ private void DeserializeTxn(BitcoinStream stream, bool witSupported)
stream.ReadWrite(ref vinTemp);
vinTemp.Transaction = this;
- var hasNoDummy = (nVersionTemp & NoDummyInput) != 0 && vinTemp.Count == 0;
- if (witSupported && hasNoDummy)
- nVersionTemp = nVersionTemp & ~NoDummyInput;
-
- if (vinTemp.Count == 0 && witSupported && !hasNoDummy)
+ if (vinTemp.Count == 0 && witSupported)
{
/* We read a dummy or an empty vin. */
stream.ReadWrite(ref flags);
@@ -392,8 +388,7 @@ private void DeserializeTxn(BitcoinStream stream, bool witSupported)
private void SerializeTxn(BitcoinStream stream, bool witSupported)
{
byte flags = 0;
- var version = (witSupported && (this.Inputs.Count == 0 && this.Outputs.Count > 0)) ? this.Version | NoDummyInput : this.Version;
- stream.ReadWrite(ref version);
+ stream.ReadWrite(ref nVersion);
// POS Timestamp
var time = this.Time;
diff --git a/NBitcoin.Altcoins/Litecoin.cs b/NBitcoin.Altcoins/Litecoin.cs
index 9ee0b53fa6..2f7d42d22b 100644
--- a/NBitcoin.Altcoins/Litecoin.cs
+++ b/NBitcoin.Altcoins/Litecoin.cs
@@ -161,9 +161,7 @@ public override ConsensusFactory GetConsensusFactory()
public override void ReadWrite(BitcoinStream stream)
{
var witSupported = (((uint)stream.TransactionOptions & (uint)TransactionOptions.Witness) != 0) &&
- stream.ProtocolCapabilities.SupportWitness;
-
- //var mwebSupported = false; //when mweb is supported in nbitcoin this is to be fixed
+ stream.ProtocolCapabilities.SupportWitness;
byte flags = 0;
if (!stream.Serializing)
@@ -172,11 +170,8 @@ public override void ReadWrite(BitcoinStream stream)
/* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
stream.ReadWrite(ref vin);
vin.Transaction = this;
- var hasNoDummy = (nVersion & NoDummyInput) != 0 && vin.Count == 0;
- if (witSupported && hasNoDummy)
- nVersion = nVersion & ~NoDummyInput;
- if (vin.Count == 0 && witSupported && !hasNoDummy)
+ if (vin.Count == 0 && witSupported)
{
/* We read a dummy or an empty vin. */
stream.ReadWrite(ref flags);
@@ -224,8 +219,10 @@ public override void ReadWrite(BitcoinStream stream)
}
else
{
- var version = (witSupported && (vin.Count == 0 && vout.Count > 0)) ? nVersion | NoDummyInput : nVersion;
- stream.ReadWrite(ref version);
+ if (Inputs.Count == 0 && !stream.AllowNoInputs)
+ throw new InvalidOperationException("The transaction must have at least one input");
+
+ stream.ReadWrite(ref nVersion);
if (witSupported)
{
@@ -238,8 +235,8 @@ public override void ReadWrite(BitcoinStream stream)
if (flags != 0)
{
/* Use extended format in case witnesses are to be serialized. */
- TxInList vinDummy = new TxInList();
- stream.ReadWrite(ref vinDummy);
+ byte marker = 0;
+ stream.ReadWrite(ref marker);
stream.ReadWrite(ref flags);
}
stream.ReadWrite(ref vin);
diff --git a/NBitcoin.Altcoins/NBitcoin.Altcoins.csproj b/NBitcoin.Altcoins/NBitcoin.Altcoins.csproj
index 67fa8d9fec..a93b462642 100644
--- a/NBitcoin.Altcoins/NBitcoin.Altcoins.csproj
+++ b/NBitcoin.Altcoins/NBitcoin.Altcoins.csproj
@@ -17,7 +17,7 @@
$(TargetFrameworkOverride)
1591;1573;1572;1584;1570;3021
true
- 3.0.28
+ 3.0.28.1
diff --git a/NBitcoin.Altcoins/Stratis.cs b/NBitcoin.Altcoins/Stratis.cs
index 01caa455e7..60724cf762 100644
--- a/NBitcoin.Altcoins/Stratis.cs
+++ b/NBitcoin.Altcoins/Stratis.cs
@@ -360,11 +360,8 @@ private void DeserializeTxn(BitcoinStream stream, bool witSupported)
// Try to read the vin. In case the dummy is there, this will be read as an empty vector.
stream.ReadWrite(ref vinTemp);
vinTemp.Transaction = this;
- var hasNoDummy = (nVersionTemp & NoDummyInput) != 0 && vinTemp.Count == 0;
- if (witSupported && hasNoDummy)
- nVersionTemp = nVersionTemp & ~NoDummyInput;
- if (vinTemp.Count == 0 && witSupported && !hasNoDummy)
+ if (vinTemp.Count == 0 && witSupported)
{
// We read a dummy or an empty vin.
stream.ReadWrite(ref flags);
@@ -414,8 +411,7 @@ private void DeserializeTxn(BitcoinStream stream, bool witSupported)
private void SerializeTxn(BitcoinStream stream, bool witSupported)
{
byte flags = 0;
- var version = (witSupported && (this.Inputs.Count == 0 && this.Outputs.Count > 0)) ? this.Version | NoDummyInput : this.Version;
- stream.ReadWrite(ref version);
+ stream.ReadWrite(ref nVersion);
// POS Timestamp
var time = this.Time;
diff --git a/NBitcoin.TestFramework/NBitcoin.TestFramework.csproj b/NBitcoin.TestFramework/NBitcoin.TestFramework.csproj
index 9741835410..8d26da9b69 100644
--- a/NBitcoin.TestFramework/NBitcoin.TestFramework.csproj
+++ b/NBitcoin.TestFramework/NBitcoin.TestFramework.csproj
@@ -1,7 +1,7 @@
- 3.0.28
+ 3.0.28.1
9.0
netstandard1.6;net472;netstandard2.0
netstandard2.1
diff --git a/NBitcoin.Tests/ChainTests.cs b/NBitcoin.Tests/ChainTests.cs
index b37446f0d1..09e0467885 100644
--- a/NBitcoin.Tests/ChainTests.cs
+++ b/NBitcoin.Tests/ChainTests.cs
@@ -608,7 +608,9 @@ public ChainedBlock AppendBlock(ChainedBlock previous, params ConcurrentChain[]
var nonce = RandomUtils.GetUInt32();
foreach (var chain in chains)
{
- var block = TestUtils.CreateFakeBlock(Network.Main.CreateTransaction());
+ var tx = Network.Main.CreateTransaction();
+ tx.Inputs.Add();
+ var block = TestUtils.CreateFakeBlock(tx);
block.Header.HashPrevBlock = previous == null ? chain.Tip.HashBlock : previous.HashBlock;
block.Header.Nonce = nonce;
if (!chain.TrySetTip(block.Header, out last))
diff --git a/NBitcoin.Tests/ColoredCoinsTests.cs b/NBitcoin.Tests/ColoredCoinsTests.cs
index 65fe59d34c..0dbb373884 100644
--- a/NBitcoin.Tests/ColoredCoinsTests.cs
+++ b/NBitcoin.Tests/ColoredCoinsTests.cs
@@ -151,6 +151,7 @@ public void CanColorizeSpecScenario()
Assert.True(destroyed[0].Id == a2.Id);
var prior = Network.Main.CreateTransaction();
+ prior.Inputs.Add();
prior.Outputs.Add(new TxOut(dust, a1.ScriptPubKey));
prior.Outputs.Add(new TxOut(dust, a2.ScriptPubKey));
prior.Outputs.Add(new TxOut(dust, h.ScriptPubKey));
diff --git a/NBitcoin.Tests/Generators/PSBTGenerator.cs b/NBitcoin.Tests/Generators/PSBTGenerator.cs
index bc378e9182..d9f901c4e3 100644
--- a/NBitcoin.Tests/Generators/PSBTGenerator.cs
+++ b/NBitcoin.Tests/Generators/PSBTGenerator.cs
@@ -38,7 +38,7 @@ from psbt in SanePSBT(network)
///
///
public static Gen SanePSBT(Network network) =>
- from inputN in Gen.Choose(0, 8)
+ from inputN in Gen.Choose(1, 8)
from scripts in Gen.ListOf(inputN, ScriptGenerator.RandomScriptSig())
from txOuts in Gen.Sequence(scripts.Select(sc => OutputFromRedeem(sc)))
from prevN in Gen.Choose(0, 5)
diff --git a/NBitcoin.Tests/PSBTTests.cs b/NBitcoin.Tests/PSBTTests.cs
index 25db349f38..dd69d875be 100644
--- a/NBitcoin.Tests/PSBTTests.cs
+++ b/NBitcoin.Tests/PSBTTests.cs
@@ -8,6 +8,8 @@
using System.Linq;
using static NBitcoin.Tests.Comparer;
using Xunit.Abstractions;
+using System.Net.Http;
+using System.Threading.Tasks;
namespace NBitcoin.Tests
{
@@ -52,6 +54,7 @@ public static void ShouldCalculateBalanceOfHDKey()
var bob = bobMaster.Derive(new KeyPath("4/5/6"));
var funding = network.CreateTransaction();
+ funding.Inputs.Add();
funding.Outputs.Add(Money.Coins(1.0m), alice);
funding.Outputs.Add(Money.Coins(1.5m), bob);
@@ -153,6 +156,15 @@ public static void ShouldParseValidDataDeterministically()
Assert.Equal(psbt, psbt2, ComparerInstance);
}
}
+
+ [Fact]
+ [Trait("UnitTest", "UnitTest")]
+ public void FixVersionParsingBug()
+ {
+ var tx = Transaction.Parse("39a75f190001010000000000000000000000000000000000000000000000000000000000000000ffffffff4903d7ae0d04970a256861627a637862fabe6d6d86846e235af48afb776d0a32cb278930b7dd601fb0e05011789ef233a3e0e7d1010000000000000012b299f4e40000000000ffffffffffffffff02ec12bb1200000000160014b6f3cfc20084e3b9f0d12b0e6f9da8fcbcf5a2d90000000000000000266a24aa21a9edc8a9c6157fb538507480083f8f5144e2f73d1bd9b6b5fabde17bd08ff524b7100120000000000000000000000000000000000000000000000000000000000000000000000000", Network.Main);
+ Assert.Equal("889d4fed1ec4a775d02082b5ff727f48d93013469db709d8d435e15b173118f3", tx.GetHash().ToString());
+ }
+
[Fact]
[Trait("UnitTest", "UnitTest")]
public void AddCoinsShouldNotRemoveInfoFromPSBT()
@@ -594,8 +606,9 @@ public void CanRebaseKeypathInPSBT()
var accountExtKey = masterExtkey.Derive(new KeyPath("0'/0'/0'"));
var accountRootedKeyPath = new KeyPath("0'/0'/0'").ToRootedKeyPath(masterExtkey);
uint hardenedFlag = 0x80000000U;
- retry:
+ retry:
Transaction funding = masterExtkey.Network.CreateTransaction();
+ funding.Inputs.Add();
funding.Outputs.Add(Money.Coins(2.0m), accountExtKey.Derive(0 | hardenedFlag).ScriptPubKey);
funding.Outputs.Add(Money.Coins(2.0m), accountExtKey.Derive(1 | hardenedFlag).ScriptPubKey);
diff --git a/NBitcoin.Tests/ProtocolTests.cs b/NBitcoin.Tests/ProtocolTests.cs
index 67fb4dec32..1aa2b05320 100644
--- a/NBitcoin.Tests/ProtocolTests.cs
+++ b/NBitcoin.Tests/ProtocolTests.cs
@@ -1102,7 +1102,9 @@ public void CanConnectMultipleTimeToServer()
public void CanRoundtripCmpctBlock()
{
Block block = Network.Main.Consensus.ConsensusFactory.CreateBlock();
- block.Transactions.Add(Network.Main.Consensus.ConsensusFactory.CreateTransaction());
+ var tx = Network.Main.Consensus.ConsensusFactory.CreateTransaction();
+ tx.Inputs.Add();
+ block.Transactions.Add(tx);
var cmpct = new CmpctBlockPayload(block);
cmpct.Clone();
}
diff --git a/NBitcoin.Tests/TestUtils.cs b/NBitcoin.Tests/TestUtils.cs
index c5f9de5b58..7ed95e920b 100644
--- a/NBitcoin.Tests/TestUtils.cs
+++ b/NBitcoin.Tests/TestUtils.cs
@@ -47,7 +47,9 @@ public static Block CreateFakeBlock(Transaction tx)
public static Block CreateFakeBlock()
{
- var block = TestUtils.CreateFakeBlock(Network.Main.CreateTransaction());
+ var tx = Network.Main.CreateTransaction();
+ tx.Inputs.Add();
+ var block = TestUtils.CreateFakeBlock(tx);
block.Header.HashPrevBlock = new uint256(RandomUtils.GetBytes(32));
block.Header.Nonce = RandomUtils.GetUInt32();
return block;
diff --git a/NBitcoin.Tests/script_tests.cs b/NBitcoin.Tests/script_tests.cs
index d1e2712749..05df96f837 100644
--- a/NBitcoin.Tests/script_tests.cs
+++ b/NBitcoin.Tests/script_tests.cs
@@ -149,6 +149,7 @@ public void BIP65_tests()
private void BIP65_testsCore(LockTime target, LockTime now, bool expectedResult)
{
Transaction tx = Network.CreateTransaction();
+ tx.Inputs.Add();
tx.Outputs.Add(new TxOut()
{
ScriptPubKey = new Script(Op.GetPushOp(target.Value), OpcodeType.OP_CHECKLOCKTIMEVERIFY)
@@ -736,6 +737,7 @@ public void script_CHECKMULTISIG12()
);
Transaction txFrom12 = Network.CreateTransaction();
+ txFrom12.Inputs.Add();
txFrom12.Outputs.Add(new TxOut());
txFrom12.Outputs[0].ScriptPubKey = scriptPubKey12;
@@ -780,6 +782,7 @@ public void script_CHECKMULTISIG23()
var txFrom23 = Network.CreateTransaction();
+ txFrom23.Inputs.Add();
txFrom23.Outputs.Add(new TxOut());
txFrom23.Outputs[0].ScriptPubKey = scriptPubKey23;
diff --git a/NBitcoin.Tests/transaction_tests.cs b/NBitcoin.Tests/transaction_tests.cs
index c7fcd72ee1..02e345c015 100644
--- a/NBitcoin.Tests/transaction_tests.cs
+++ b/NBitcoin.Tests/transaction_tests.cs
@@ -987,6 +987,7 @@ public void CanBuildShuffleColoredTransaction()
var repo = new NoSqlColoredTransactionRepository(new NoSqlTransactionRepository(), new InMemoryNoSqlRepository());
var init = Network.CreateTransaction();
+ init.Inputs.Add();
init.Outputs.Add("1.0", gold.PubKey);
init.Outputs.Add("1.0", silver.PubKey);
init.Outputs.Add("1.0", satoshi.PubKey);
@@ -1278,6 +1279,7 @@ public void CanBuildColoredTransaction()
var repo = new NoSqlColoredTransactionRepository();
var init = Network.CreateTransaction();
+ init.Inputs.Add();
init.Outputs.Add("1.0", gold.PubKey);
init.Outputs.Add("1.0", silver.PubKey);
init.Outputs.Add("1.0", satoshi.PubKey);
@@ -1374,6 +1376,7 @@ public void CanBuildColoredTransaction()
//Gold receive 2.5 BTC
tx = txBuilder.Network.Consensus.ConsensusFactory.CreateTransaction();
+ tx.Inputs.Add();
tx.Outputs.Add("2.5", gold.PubKey);
repo.Transactions.Put(tx.GetHash(), tx);
@@ -1761,6 +1764,7 @@ public void CanEstimateFees()
builder.SendEstimatedFees(rate);
signed = builder.BuildTransaction(true);
Assert.True(builder.Verify(signed, estimatedFees));
+ Assert.Equal(1174, builder.EstimateSize(signed));
}
private Coin RandomCoin(Money amount, IDestination dest, bool p2sh)
@@ -1919,23 +1923,6 @@ void BitcoinStreamCoverageCore(TItem[] input, BitcoinStreamCoverageCoreDe
AssertEx.CollectionEquals(before, input);
}
- [Fact]
- [Trait("UnitTest", "UnitTest")]
- public void CanSerializeInvalidTransactionsBackAndForth()
- {
- Transaction before = Network.CreateTransaction();
- var versionBefore = before.Version;
- before.Outputs.Add(new TxOut());
- Transaction after = AssertClone(before);
- Assert.Equal(before.Version, after.Version);
- Assert.Equal(versionBefore, after.Version);
- Assert.True(after.Outputs.Count == 1);
-
- before = Network.CreateTransaction();
- after = AssertClone(before);
- Assert.Equal(before.Version, versionBefore);
- }
-
private Transaction AssertClone(Transaction before)
{
Transaction after = before.Clone();
@@ -2095,6 +2082,7 @@ public void CanFilterUneconomicalCoins()
var bob = new Key();
//P2SH(P2WSH)
var previousTx = Network.CreateTransaction();
+ previousTx.Inputs.Add();
previousTx.Outputs.Add(new TxOut(Money.Coins(1.0m), alice.PubKey.ScriptPubKey.WitHash.ScriptPubKey.Hash));
var previousCoin = previousTx.Outputs.AsCoins().First();
@@ -2643,6 +2631,7 @@ public void CanBuildTransactionWithDustPrevention()
var bob = new Key();
var alice = new Key();
var tx = Network.CreateTransaction();
+ tx.Inputs.Add();
tx.Outputs.Add(Money.Coins(1.0m), bob);
var coins = tx.Outputs.AsCoins().ToArray();
@@ -2837,6 +2826,7 @@ public void CanMutateSignature()
public void CanUseLockTime()
{
var tx = Network.CreateTransaction();
+ tx.Inputs.Add();
tx.LockTime = new LockTime(4);
var clone = tx.Clone();
Assert.Equal(tx.LockTime, clone.LockTime);
@@ -3067,6 +3057,7 @@ public void witnessHasPushSizeLimit()
{
var bob = new Key().GetWif(Network.RegTest);
Transaction tx = Network.CreateTransaction();
+ tx.Inputs.Add();
tx.Outputs.Add(new TxOut(Money.Coins(1.0m), bob.PubKey.ScriptPubKey.WitHash));
ScriptCoin coin = new ScriptCoin(tx.Outputs.AsCoins().First(), bob.PubKey.ScriptPubKey);
diff --git a/NBitcoin/BitcoinStream.cs b/NBitcoin/BitcoinStream.cs
index 0c5f687430..8b80af49fc 100644
--- a/NBitcoin/BitcoinStream.cs
+++ b/NBitcoin/BitcoinStream.cs
@@ -592,6 +592,7 @@ public void CopyParameters(BitcoinStream from)
IsBigEndian = from.IsBigEndian;
MaxArraySize = from.MaxArraySize;
Type = from.Type;
+ AllowNoInputs = from.AllowNoInputs;
}
public SerializationType Type
@@ -630,6 +631,13 @@ public System.Threading.CancellationToken ReadCancellationToken
set;
}
+ ///
+ /// Allows serialization of transactions with no inputs.
+ /// Such transactions are not valid for deserialization, but may still be useful,
+ /// for example, when computing a transaction hash or estimating size.
+ ///
+ public bool AllowNoInputs { get; set; }
+
public void ReadWriteAsVarInt(ref uint val)
{
if (Serializing)
diff --git a/NBitcoin/IBitcoinSerializable.cs b/NBitcoin/IBitcoinSerializable.cs
index 682910a2f4..42b31e61b2 100644
--- a/NBitcoin/IBitcoinSerializable.cs
+++ b/NBitcoin/IBitcoinSerializable.cs
@@ -32,6 +32,7 @@ public static void ReadWrite(this IBitcoinSerializable serializable, Stream stre
public static int GetSerializedSize(this IBitcoinSerializable serializable, uint? version, SerializationType serializationType)
{
BitcoinStream s = new BitcoinStream(Stream.Null, true);
+ s.AllowNoInputs = true;
s.Type = serializationType;
s.ProtocolVersion = version;
s.ReadWrite(serializable);
@@ -40,6 +41,7 @@ public static int GetSerializedSize(this IBitcoinSerializable serializable, uint
public static int GetSerializedSize(this IBitcoinSerializable serializable, TransactionOptions options)
{
var bms = new BitcoinStream(Stream.Null, true);
+ bms.AllowNoInputs = true;
bms.TransactionOptions = options;
serializable.ReadWrite(bms);
return (int)bms.Counter.WrittenBytes;
diff --git a/NBitcoin/NBitcoin.csproj b/NBitcoin/NBitcoin.csproj
index 8c2ec5e652..6d2ef0c5dd 100644
--- a/NBitcoin/NBitcoin.csproj
+++ b/NBitcoin/NBitcoin.csproj
@@ -12,7 +12,7 @@
git
- 7.0.42.1
+ 7.0.42.2
9.0
diff --git a/NBitcoin/RPC/RPCClient.Wallet.cs b/NBitcoin/RPC/RPCClient.Wallet.cs
index 8386039496..272ce5e0ed 100644
--- a/NBitcoin/RPC/RPCClient.Wallet.cs
+++ b/NBitcoin/RPC/RPCClient.Wallet.cs
@@ -380,8 +380,12 @@ private string ToHex(Transaction tx)
// if there is inputs, then it can't be confusing
if (tx.Inputs.Count > 0)
return tx.ToHex();
- // if there is, do this ACK so that NBitcoin does not change the version number
- return Encoders.Hex.EncodeData(tx.ToBytes(70012 - 1));
+
+ var ms = new MemoryStream();
+ BitcoinStream bs = new BitcoinStream(ms, true);
+ bs.AllowNoInputs = true;
+ tx.ReadWrite(bs);
+ return Encoders.Hex.EncodeData(ms.ToArrayEfficient());
}
diff --git a/NBitcoin/Transaction.cs b/NBitcoin/Transaction.cs
index 6d07cb82e8..e234058ee1 100644
--- a/NBitcoin/Transaction.cs
+++ b/NBitcoin/Transaction.cs
@@ -339,6 +339,15 @@ public static TxIn CreateCoinbase(int height)
txin.ScriptSig = new Script(Op.GetPushOp(height)) + OpcodeType.OP_0;
return txin;
}
+
+ ///
+ /// Remove and from this input.
+ ///
+ public void RemoveSignatures()
+ {
+ ScriptSig = Script.Empty;
+ WitScript = WitScript.Empty;
+ }
}
public class TxOutCompressor : IBitcoinSerializable
@@ -1445,6 +1454,12 @@ public static Transaction Parse(string hex, Network network)
return Load(Encoders.Hex.DecodeData(hex), network);
}
+ public void RemoveSignatures()
+ {
+ foreach (var input in Inputs)
+ input.RemoveSignatures();
+ }
+
public static bool TryParse(string hex, Network network, out Transaction transaction)
{
if (hex == null)
@@ -1513,9 +1528,6 @@ public TxOutList Outputs
}
}
- //Since it is impossible to serialize a transaction with 0 input without problems during deserialization with wit activated, we fit a flag in the version to workaround it
- protected const uint NoDummyInput = (1 << 27);
-
#region IBitcoinSerializable Members
public virtual void ReadWrite(BitcoinStream stream)
@@ -1530,11 +1542,8 @@ public virtual void ReadWrite(BitcoinStream stream)
/* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
stream.ReadWrite(ref vin);
vin.Transaction = this;
- var hasNoDummy = (nVersion & NoDummyInput) != 0 && vin.Count == 0;
- if (witSupported && hasNoDummy)
- nVersion = nVersion & ~NoDummyInput;
- if (vin.Count == 0 && witSupported && !hasNoDummy)
+ if (vin.Count == 0 && witSupported)
{
/* We read a dummy or an empty vin. */
stream.ReadWrite(ref flags);
@@ -1574,8 +1583,9 @@ public virtual void ReadWrite(BitcoinStream stream)
}
else
{
- var version = (witSupported && (vin.Count == 0 && vout.Count > 0)) ? nVersion | NoDummyInput : nVersion;
- stream.ReadWrite(ref version);
+ if (Inputs.Count == 0 && !stream.AllowNoInputs)
+ throw new InvalidOperationException("The transaction must have at least one input");
+ stream.ReadWrite(ref nVersion);
if (witSupported)
{
@@ -1624,6 +1634,7 @@ public uint256 GetHash()
{
TransactionOptions = TransactionOptions.None,
ConsensusFactory = GetConsensusFactory(),
+ AllowNoInputs = true
};
stream.SerializationTypeScope(SerializationType.Hash);
this.ReadWrite(stream);
diff --git a/NBitcoin/TransactionBuilder.cs b/NBitcoin/TransactionBuilder.cs
index 5f96952c2a..392d850763 100644
--- a/NBitcoin/TransactionBuilder.cs
+++ b/NBitcoin/TransactionBuilder.cs
@@ -2426,10 +2426,9 @@ public void EstimateSizes(Transaction tx, out int witSize, out int baseSize)
if (tx == null)
throw new ArgumentNullException(nameof(tx));
var clone = tx.Clone();
- clone.Inputs.Clear();
- baseSize = clone.GetSerializedSize() - 1;
- baseSize += new Protocol.VarInt((ulong)tx.Inputs.Count).GetSerializedSize();
-
+ clone.RemoveSignatures();
+ baseSize = clone.GetSerializedSize();
+ baseSize -= clone.Inputs.Count; // The varint to push scriptSig is accounted later
witSize = 0;
int nonWitnessCount = 0;
bool hasWitness = tx.HasWitness;
@@ -2443,10 +2442,8 @@ public void EstimateSizes(Transaction tx, out int witSize, out int baseSize)
else
nonWitnessCount++;
EstimateScriptSigSize(coin, ref witSize, ref baseSize);
- baseSize += (32 + 4) + 4;
}
-
if (hasWitness)
{
witSize += 2; // 1 Dummy + 1 Flag