public OperatingError VerifyMultisig(MultiSig multisig, UInt256 hash, bool useNewChainId) { /* don't allow null multisig or hash */ if (multisig is null || hash is null) { Logger.LogDebug("Multisig or hash is null"); return(OperatingError.InvalidMultisig); } /* check that all signatures are unique */ if (multisig.Signatures.Select(sig => sig.Key).Distinct().Count() != multisig.Signatures.Count) { Logger.LogDebug("Duplicate signature in multisig"); return(OperatingError.InvalidMultisig); } /* check count of unique validators */ if (multisig.Validators.Distinct().Count() != multisig.Validators.Count) { Logger.LogDebug("Duplicate validator in multisig"); return(OperatingError.InvalidMultisig); } /* verify every validator's signature */ var verified = 0; foreach (var entry in multisig.Signatures) { /* if there is no validator's public key than skip it */ if (!multisig.Validators.Contains(entry.Key)) { continue; } var publicKey = entry.Key.EncodeCompressed(); var sig = entry.Value.Encode(); try { /* if signature invalid that skip it */ if (!_crypto.VerifySignatureHashed(hash.ToBytes(), sig, publicKey, useNewChainId)) { Logger.LogWarning($"Invalid Multisig signature: hash: {hash.ToHex()}, sig: {sig.ToHex()}, publicKey: {publicKey.ToHex()}"); continue; } /* increment count of verified signatures */ ++verified; } catch (System.Exception) { // ignore } } // if we have required amount of signatures that return ok if (verified < multisig.Quorum) { Logger.LogWarning($"Quorum not reached: {verified} < {multisig.Quorum}"); } return(verified >= multisig.Quorum ? OperatingError.Ok : OperatingError.QuorumNotReached); }
public void TxDebug(uint path, params string[] seed) { Transaction tx = new Transaction("01000000000101fb1db914dd2be5311ebde6f86f1d49551057557fa22021a3a59623fa086836b2000000002322002029ccc4c03f9609ff9f79b0b7d3ade093ffd7da6d37c06edc65bfb898d4aee069ffffffff01e01dbe070000000017a914a9974100aeee974a20cda9a2f545704a0ab54fdc87040047304402204e4c8a3ebf889821e574edb805bb6b65523e5a000ee4729db7e7d2888741c5830220058df53eb3b6f052a8dab2f897901d85242297dfa6aafebeb577913c2782c16a01483045022100f03b655ffedbd262f98ed3a562b32bc676e565b457f3fe89f557b755f4ab0d7502200e6c3006351a220c8fcf0a563701537b8979ceb289170d16ff8da760083a62c80147522103a0b99131aca0a5c696fe9f7e63b987f185050d2e6b25f80731f9f0ab83702d862102103f9e18fb85e862a20ff9d7afb0172661296f08d988508a538a68c96a1c4a5752ae00000000"); List <ExtKey> keys = new List <ExtKey>(); Segwit segwit = new Segwit(NBitcoin.Network.TestNet); for (int i = 0; i < seed.Length; i++) { var key = GetKey(path, seed[i]); var address = segwit.GetP2SHAddress(key); keys.Add(key); //Console.WriteLine(address.ToString()); } MultiSig multi = new MultiSig(NBitcoin.Network.TestNet); var p2sh = multi.GetP2SHAddress(2, keys.ToArray()); Console.WriteLine(p2sh.ToString()); }
private (BlockHeader, MultiSig) BuildHeaderAndMultisig(UInt256 merkleRoot, Block?predecessor, UInt256 stateHash) { var blockIndex = predecessor !.Header.Index + 1; var header = new BlockHeader { Index = blockIndex, PrevBlockHash = predecessor !.Hash, MerkleRoot = merkleRoot, StateHash = stateHash, Nonce = blockIndex }; var keyPair = _privateWallet.EcdsaKeyPair; var headerSignature = Crypto.SignHashed( header.Keccak().ToBytes(), keyPair.PrivateKey.Encode(), HardforkHeights.IsHardfork_9Active(blockIndex) ).ToSignature(HardforkHeights.IsHardfork_9Active(blockIndex)); var multisig = new MultiSig { Quorum = 1, Validators = { _privateWallet.EcdsaKeyPair.PublicKey }, Signatures = { new MultiSig.Types.SignatureByValidator { Key = _privateWallet.EcdsaKeyPair.PublicKey, Value = headerSignature, } } }; return(header, multisig); }
public BlockBuilder WithMultisig(MultiSig multiSig) { _multiSig = multiSig; return(this); }
public void CreateBasicSwap(uint path, params string[] seed) { List <ExtKey> keys = new List <ExtKey>(); Segwit segwit = new Segwit(NBitcoin.Network.TestNet); for (int i = 0; i < seed.Length; i++) { var key = GetKey(path, seed[i]); var address = segwit.GetP2SHAddress(key); keys.Add(key); //Console.WriteLine(address.ToString()); } MultiSig multi = new MultiSig(NBitcoin.Network.TestNet); var p2sh = multi.GetP2SHAddress(2, keys.ToArray()); Console.WriteLine(p2sh.ToString()); //multi: b2366808fa2396a5a32120a27f55571055491d6ff8e6bd1e31e52bdd14b91dfb REST.BlockExplorer explorer = new REST.BlockExplorer("https://testnet.blockexplorer.com/"); //var tx = explorer.GetTransaction("b2366808fa2396a5a32120a27f55571055491d6ff8e6bd1e31e52bdd14b91dfb"); var response = explorer.GetUnspent(p2sh.ToString()); List <ExplorerUnspent> unspent = response.Convert <List <ExplorerUnspent> >(); List <Transaction> transactions = new List <Transaction>(); foreach (var item in unspent) { ExplorerResponse txResponse = explorer.GetTransaction(item.txid); RawFormat format = RawFormat.Satoshi; var tx = Transaction.Parse(txResponse.data, format, Network.TestNet); transactions.Add(tx); } //Create send transaction. //get redeem script var redeemScript = multi.GetRedeemScript(2, keys.ToArray()); Transaction received = transactions[0]; ScriptCoin coin = received.Outputs.AsCoins().First().ToScriptCoin(redeemScript); //create transaction: BitcoinAddress destination = BitcoinAddress.Create("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF"); //the faucet return address TransactionBuilder builder = new TransactionBuilder(); builder.AddCoins(coin); builder.Send(destination, Money.Coins(1.299m)); builder.SendFees(Money.Coins(0.001m)); builder.SetChange(destination); //builder. var unsigned = builder.BuildTransaction(sign: false); var signedA = builder.AddCoins(coin).AddKeys(keys[0].PrivateKey).SignTransaction(unsigned); Transaction signedB = builder.AddCoins(coin).AddKeys(keys[1].PrivateKey).SignTransaction(signedA); Transaction fullySigned = builder.AddCoins(coin).CombineSignatures(signedA, signedB); Console.WriteLine(fullySigned.ToHex()); Console.ReadLine(); }
public void NewCreateBasicSwap(uint path, params string[] seed) { List <ExtKey> keys = new List <ExtKey>(); Segwit segwit = new Segwit(NBitcoin.Network.TestNet); for (int i = 0; i < seed.Length; i++) { var key = GetKey(path, seed[i]); //var address = segwit.GetP2SHAddress(key); keys.Add(key); //Console.WriteLine(address.ToString()); } NBitcoin.Network _Network = NBitcoin.Network.TestNet; MultiSig multi = new MultiSig(NBitcoin.Network.TestNet); List <PubKey> pubKeys = new List <PubKey>(); for (int i = 0; i < keys.Count; i++) { pubKeys.Add(keys[i].PrivateKey.PubKey); } Script pubKeyScript = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, pubKeys.ToArray()); BitcoinAddress address = pubKeyScript.WitHash.GetAddress(_Network); BitcoinScriptAddress p2sh = address.GetScriptAddress(); Console.WriteLine("Send money here: " + p2sh.ToString()); REST.BlockExplorer explorer = new REST.BlockExplorer("https://testnet.blockexplorer.com/"); var response = explorer.GetUnspent(p2sh.ToString()); List <ExplorerUnspent> unspent = response.Convert <List <ExplorerUnspent> >(); List <Transaction> transactions = new List <Transaction>(); foreach (var item in unspent) { ExplorerResponse txResponse = explorer.GetTransaction(item.txid); RawFormat format = RawFormat.Satoshi; var tx = Transaction.Parse(txResponse.data, format, Network.TestNet); transactions.Add(tx); } //Create send transaction. //get redeem script //var redeemScript = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, pubKeys.ToArray());// multi.GetRedeemScript(2, keys.ToArray()); Transaction received = transactions[0]; ScriptCoin coin = received.Outputs.AsCoins().First().ToScriptCoin(pubKeyScript.WitHash.ScriptPubKey.Hash.ScriptPubKey); //create transaction: BitcoinAddress destination = BitcoinAddress.Create("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF"); //the faucet return address TransactionBuilder builder = new TransactionBuilder(); builder.AddCoins(coin); builder.Send(destination, Money.Coins(1.299m)); builder.SendFees(Money.Coins(0.001m)); builder.SetChange(destination); //builder. var unsigned = builder.BuildTransaction(sign: false); var signedA = builder.AddCoins(coin).AddKeys(keys[0].PrivateKey).SignTransaction(unsigned); Transaction signedB = builder.AddCoins(coin).AddKeys(keys[1].PrivateKey).SignTransaction(signedA); Transaction fullySigned = builder.AddCoins(coin).CombineSignatures(signedA, signedB); Console.WriteLine(fullySigned.ToHex()); Console.ReadLine(); }
// After sufficient votes are on the emulated stateHash, the block is approved and // executed to add to the chain public void ProduceBlock(IEnumerable <TransactionReceipt> receipts, BlockHeader header, MultiSig multiSig) { Logger.LogDebug($"Producing block {header.Index}"); if (_blockManager.GetHeight() >= header.Index) { Logger.LogWarning("Block already produced"); return; } var blockWithTransactions = new BlockBuilder(_blockManager.LatestBlock().Header, header.StateHash) .WithTransactions(receipts) .WithMultisig(multiSig) .Build(header.Nonce); Logger.LogDebug($"Block approved by consensus: {blockWithTransactions.Block.Hash.ToHex()}"); if (_blockManager.GetHeight() + 1 != header.Index) { throw new InvalidOperationException( $"Current height is {_blockManager.GetHeight()}, but we are trying to produce block {header.Index}" ); } var result = _blockManager.Execute( blockWithTransactions.Block, blockWithTransactions.Transactions, commit: true, checkStateHash: true); if (result != OperatingError.Ok) { Logger.LogError( $"Block {blockWithTransactions.Block.Header.Index} ({blockWithTransactions.Block.Hash.ToHex()}) was not persisted: {result}" ); Logger.LogTrace($"Block raw data: {blockWithTransactions.Block.ToByteArray().ToHex()}"); Logger.LogTrace($"Block transactions data: {string.Join(", ", blockWithTransactions.Transactions.Select(tx => tx.ToByteArray().ToHex()))}"); } }