Exemple #1
0
        static void SignInput(TxIn txin, Key key, SegWitCoin coin, int index, Transaction transaction)
        {
            if (coin.SegWitAddress.AddressType == AddressType.PubKeyHash)
            {
                Script  scriptCode    = GetScriptCode(coin.SegWitAddress.GetScriptPubKey());
                uint256 signatureHash = GetHashToSign(transaction, index, scriptCode, coin.UtxoValue);
                byte[]  finalSig      = GetSignature(signatureHash, key);
                txin.WitScript = new WitScript(Op.GetPushOp(finalSig), Op.GetPushOp(key.PubKey.Compress().ToBytes()));
            }
            else if (coin.SegWitAddress is ColdStakingAddress coldStakingAddress)
            {
                Script  scriptCode    = coldStakingAddress.GetRedeemScript();
                uint256 signatureHash = GetHashToSign(transaction, index, scriptCode, coin.UtxoValue);
                byte[]  finalSig      = GetSignature(signatureHash, key);

                var isColdPubKey = coldStakingAddress.AddressType == AddressType.ColdStakingCold;
                var publicKey    = key.PubKey.Compress();
                var scriptSig    = new Script(Op.GetPushOp(finalSig), isColdPubKey ? OP_0 : OP_1, Op.GetPushOp(publicKey.ToBytes()));
                txin.WitScript = scriptSig + new WitScript(Op.GetPushOp(coldStakingAddress.GetRedeemScript().ToBytes(true)));
            }
            else if (coin.SegWitAddress is MultiSigAddress multiSigAddress)
            {
                var scriptCoin = coin.ToCoin().ToScriptCoin(multiSigAddress.GetRedeemScript());
                transaction.Sign(C.Network, new[] { key }, new[] { scriptCoin });
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Exemple #2
0
        static void CheckTransaction(Transaction tx, SegWitCoin kernelCoin)
        {
            var txData = new PrecomputedTransactionData(tx);

            for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
            {
                TxIn input = tx.Inputs[inputIndex];

                TxOut spentOut = new TxOut(kernelCoin.UtxoValue, kernelCoin.SegWitAddress.GetScriptPubKey());

                var checker = new TransactionChecker(tx, inputIndex, spentOut, txData);
                var ctx     = new ScriptEvaluationContext
                {
                    ScriptVerify = ScriptVerify.Mandatory | ScriptVerify.DerSig | ScriptVerify.CheckLockTimeVerify |
                                   ScriptVerify.Witness /* todo | ScriptVerify.CheckColdStakeVerify*/
                };
                bool verifyScriptResult = ctx.VerifyScript(input.ScriptSig, spentOut.ScriptPubKey, checker);

                if (verifyScriptResult == false)
                {
                    throw new InvalidOperationException(
                              $"Verify script for transaction '{tx.GetHash()}' input {inputIndex} failed, ScriptSig = '{input.ScriptSig}', ScriptPubKey = '{spentOut.ScriptPubKey}', script evaluation error = '{ctx.Error}'");
                }
            }
        }
Exemple #3
0
        public static Transaction CreateAndSignCoinstakeTransaction(SegWitCoin kernelCoin, long totalReward, uint currentBlockTime, string passphrase, out Key privateKey)
        {
            var tx = CreateCoinstakeTransaction(kernelCoin, totalReward, currentBlockTime, passphrase, out privateKey);

            SigningService.SignInputs(tx, new[] { privateKey }, new[] { kernelCoin });

            return(tx);
        }
Exemple #4
0
        public static Coin ToCoin(this SegWitCoin segWitCoin)
        {
            var outpoint = new OutPoint(segWitCoin.UtxoTxHash, segWitCoin.UtxoTxN);
            var txOut    = new TxOut(segWitCoin.UtxoValue, segWitCoin.SegWitAddress.GetScriptPubKey());
            var coin     = new Coin(outpoint, txOut);

            return(coin);
        }
Exemple #5
0
        public static Transaction CreateCoinstakeTransaction(SegWitCoin kernelCoin, long totalReward, uint currentBlockTime, string passphrase, out Key privateKey)
        {
            Transaction tx = C.Network.CreateTransaction();

            if (kernelCoin.SegWitAddress is ColdStakingAddress coldStakingAddress &&
                coldStakingAddress.AddressType == AddressType.ColdStakingHot)
            {
                privateKey = new Key(coldStakingAddress.StakingKey);
            }
Exemple #6
0
 public static void SignScriptAddress(Transaction tx, Key privateKey, SegWitCoin kernelCoin)
 {
     if (kernelCoin.SegWitAddress is MultiSigAddress multiSigAddress)
     {
         var sc = kernelCoin.ToCoin().ToScriptCoin(multiSigAddress.GetRedeemScript());
         tx.Sign(C.Network, new[] { privateKey }, new[] { sc });
     }
     else if (kernelCoin.SegWitAddress is ColdStakingAddress coldStakingAddress)
     {
         var sc = kernelCoin.ToCoin().ToScriptCoin(coldStakingAddress.GetRedeemScript());
         tx.Sign(C.Network, new[] { privateKey }, new[] { sc }, new[] { new ColdStakingBuilderExtension(staking: true) });
     }
 }
Exemple #7
0
        void PushToCoinsCache(RPCUnspentOutput[] unspentOutputs, RPCFilename dumpFilePath, bool export = false)
        {
            this.stopwatch.Restart();

            try
            {
                var dump = File.ReadAllText(dumpFilePath.filename);
                File.Delete(dumpFilePath.filename);
                var lookup = ParseDump(dump);

                var coins = new List <SegWitCoin>();
                foreach (var utxo in unspentOutputs)
                {
                    if (utxo.confirmations < (export ? 0 : 125))
                    {
                        continue;
                    }

                    if (lookup.ContainsKey(utxo.address))
                    {
                        var coin = new SegWitCoin(lookup[utxo.address], uint256.Parse(utxo.txid), utxo.vout, (long)(utxo.amount * C.SatoshisPerCoin), UtxoType.NotSet);
                        coins.Add(coin);
                    }
                    else
                    {
                        this.logger.LogWarning($"For utxo {utxo.txid}-{utxo.vout}, its address {utxo.address} was not found in the lookup.");
                    }
                }

                if (export)
                {
                    Export(coins);
                }

                CoinCache.ReplaceCoins(coins);

                this.logger.LogInformation($"Cached {coins.Count} mature coins for staking - {stopwatch.ElapsedMilliseconds} ms.");
            }
            catch (Exception e)
            {
                this.logger.LogError($"Error processing  wallet dump file {e.Message}");
                throw;
            }
        }
Exemple #8
0
 public static Key GetPrivateKey(this SegWitCoin segWitCoin, string passphrase)
 {
     return(new Key(VCL.DecryptWithPassphrase(passphrase, segWitCoin.SegWitAddress.GetEncryptedPrivateKey())));
 }
        public static Balance GetBalance(ConcurrentDictionary <int, BlockMetadata> blocks, int syncedHeight, HashSet <MemoryPoolEntry> memoryPoolEntries, Func <string, ISegWitAddress> getOwnAddress,
                                         string matchAddress = null, AddressType matchAddressType = AddressType.MatchAll)
        {
            var balance = new Balance();

            var spent = new Dictionary <string, UtxoMetadata>();

            // process all confirmed transactions first, oldest to newest
            foreach (var(height, block) in blocks)
            {
                foreach (var tx in block.Transactions)
                {
                    bool isImmatureForSpending = false;

                    if (tx.TxType.HasCoinbaseMaturity())
                    {
                        var confirmationsSpending = syncedHeight - height + 1;                                // if the tip is at 100 and my tx is height 90, it's 11 confirmations
                        isImmatureForSpending = confirmationsSpending < C.Network.Consensus.CoinbaseMaturity; // ok
                    }

                    var confirmationsStaking = syncedHeight - height + 1; // if the tip is at 100 and my tx is height 90, it's 11 confirmations
                    var isImmatureForStaking = confirmationsStaking < C.Network.Consensus.MaxReorgLength;

                    if (tx.Received != null)
                    {
                        foreach (UtxoMetadata utxo in tx.Received.Values)
                        {
                            for (var address = getOwnAddress(utxo.Address).Match(matchAddress, matchAddressType);
                                 address != null; address = null)
                            {
                                balance.TotalReceived += utxo.Satoshis;

                                var coin = new SegWitCoin(address, utxo.HashTx, utxo.Index, utxo.Satoshis);

                                if (!isImmatureForSpending)
                                {
                                    balance.Spendable += utxo.Satoshis;
                                    balance.SpendableCoins.AddSafe(utxo.GetKey(), coin);
                                }
                                if (!isImmatureForStaking)
                                {
                                    balance.Stakable += utxo.Satoshis;
                                    balance.StakingCoins.AddSafe(utxo.GetKey(), coin);
                                }
                            }
                        }
                    }

                    if (tx.Spent != null)
                    {
                        foreach ((string txIdN, UtxoMetadata utxo) in tx.Spent)
                        {
                            for (var address = getOwnAddress(utxo.Address).Match(matchAddress, matchAddressType);
                                 address != null;
                                 address = null)
                            {
                                balance.TotalSpent += utxo.Satoshis;
                                spent.AddSafe(txIdN, utxo);
                            }
                        }
                    }
                }
            }

            // unconfirmed transactions - add them last, ordered by time, so that they come last in coin selection
            // when unconfirmed outputs get spent, to allow the memory pool and network to recognize
            // the new unspent outputs.
            foreach (MemoryPoolEntry entry in memoryPoolEntries.OrderBy(x => x.TransactionTime))
            {
                var tx = entry.Transaction;
                if (tx.Received != null)
                {
                    foreach (UtxoMetadata utxo in tx.Received.Values)
                    {
                        ISegWitAddress address = getOwnAddress(utxo.Address);

                        balance.TotalReceivedPending += utxo.Satoshis;

                        var coin = new SegWitCoin(address, utxo.HashTx, utxo.Index, utxo.Satoshis);
                        balance.SpendableCoins.AddSafe(utxo.GetKey(), coin);
                    }
                }

                if (tx.Spent != null)
                {
                    foreach (var(txIdN, utxo) in tx.Spent)
                    {
                        for (var address = getOwnAddress(utxo.Address).Match(matchAddress, matchAddressType);
                             address != null;
                             address = null)
                        {
                            balance.TotalSpent += utxo.Satoshis;
                            spent.AddSafe(txIdN, utxo);
                        }
                    }
                }
            }

            // remove what is already spent
            foreach (var utxoId in spent)
            {
                if (balance.SpendableCoins.ContainsKey(utxoId.Key))
                {
                    balance.Spendable -= utxoId.Value.Satoshis;
                    balance.SpendableCoins.Remove(utxoId.Key);
                }
                if (balance.StakingCoins.ContainsKey(utxoId.Key))
                {
                    balance.Stakable -= utxoId.Value.Satoshis;
                    balance.StakingCoins.Remove(utxoId.Key);
                }
            }

            // last balance updates
            balance.Confirmed = balance.TotalReceived - balance.TotalSpent;
            balance.Pending   = balance.TotalReceivedPending - balance.TotalSpentPending;
            balance.Total     = balance.Confirmed + balance.Pending;

            return(balance);
        }