Beispiel #1
0
    def run_test(self):
        self.log.info(
            'prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info(
            'Test getrawtransaction on genesis block coinbase returns an error'
        )
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(
            -5,
            "The genesis block coinbase is not considered an ordinary transaction",
            self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info(
            'Check parameter types and required parameters of createrawtransaction'
        )
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                False, 'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array",
                                self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected",
                                self.nodes[0].createrawtransaction, ['foo'],
                                {})
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(
            -8, "txid must be of length 64 (not 3, for 'foo')",
            self.nodes[0].createrawtransaction, [{
                'txid': 'foo'
            }], {})
        assert_raises_rpc_error(
            -8,
            "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')",
            self.nodes[0].createrawtransaction, [{
                'txid':
                'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'
            }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid,
                                    'vout': 'foo'
                                }], {})
        assert_raises_rpc_error(-8,
                                "Invalid parameter, vout cannot be negative",
                                self.nodes[0].createrawtransaction, [{
                                    'txid': txid,
                                    'vout': -1
                                }], {})
        assert_raises_rpc_error(
            -8, "Invalid parameter, sequence number is out of range",
            self.nodes[0].createrawtransaction, [{
                'txid': txid,
                'vout': 0,
                'sequence': -1
            }], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected",
                                self.nodes[0].createrawtransaction, [], 'foo')
        self.nodes[0].createrawtransaction(
            inputs=[],
            outputs={})  # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [],
                                {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid Bitcoin address",
                                self.nodes[0].createrawtransaction, [],
                                {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount",
                                self.nodes[0].createrawtransaction, [],
                                {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range",
                                self.nodes[0].createrawtransaction, [],
                                {address: -1})
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [],
            multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [], [{
                address: 1
            }, {
                address: 1
            }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                [{
                                    "data": 'aa'
                                }, {
                                    "data": "bb"
                                }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                multidict([("data", 'aa'), ("data", "bb")]))
        assert_raises_rpc_error(
            -8,
            "Invalid parameter, key-value pair must contain exactly one key",
            self.nodes[0].createrawtransaction, [], [{
                'a': 1,
                'b': 2
            }])
        assert_raises_rpc_error(
            -8, "Invalid parameter, key-value pair not an object as expected",
            self.nodes[0].createrawtransaction, [],
            [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number",
                                self.nodes[0].createrawtransaction, [], {},
                                'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {},
                                4294967296)

        # Test `createrawtransaction` invalid `replaceable`
        assert_raises_rpc_error(-3, "Expected type bool",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                'foo')

        self.log.info(
            'Check that createrawtransaction accepts an array and object as outputs'
        )
        tx = CTransaction()
        # One output
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }]),
        )
        # Two outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }]),
        )
        # Multiple mixed outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=multidict([(address, 99), (address2, 99),
                                       ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }, {
                                                   'data': '99'
                                               }]),
        )

        for type in ["bech32", "p2sh-segwit", "legacy"]:
            addr = self.nodes[0].getnewaddress("", type)
            addrinfo = self.nodes[0].getaddressinfo(addr)
            pubkey = addrinfo["scriptPubKey"]

            self.log.info('sendrawtransaction with missing prevtx info (%s)' %
                          (type))

            # Test `signrawtransactionwithwallet` invalid `prevtxs`
            inputs = [{'txid': txid, 'vout': 3, 'sequence': 1000}]
            outputs = {self.nodes[0].getnewaddress(): 1}
            rawtx = self.nodes[0].createrawtransaction(inputs, outputs)

            prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)
            succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
            assert succ["complete"]
            if type == "legacy":
                del prevtx["amount"]
                succ = self.nodes[0].signrawtransactionwithwallet(
                    rawtx, [prevtx])
                assert succ["complete"]

            if type != "legacy":
                assert_raises_rpc_error(
                    -3, "Missing amount",
                    self.nodes[0].signrawtransactionwithwallet, rawtx,
                    [{
                        "txid": txid,
                        "scriptPubKey": pubkey,
                        "vout": 3,
                    }])

            assert_raises_rpc_error(-3, "Missing vout",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "scriptPubKey": pubkey,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing txid",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "scriptPubKey": pubkey,
                                        "vout": 3,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing scriptPubKey",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "vout": 3,
                                        "amount": 1
                                    }])

        #########################################
        # sendrawtransaction with missing input #
        #########################################

        self.log.info('sendrawtransaction with missing input')
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]  #won't exists
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent",
                                self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found",
                                self.nodes[0].getrawtransaction, tx, True,
                                block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].getrawtransaction, tx, True,
                                True)
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 6, for 'foobar')",
            self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')",
            self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(
            -8,
            "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[0].getrawtransaction, tx, True,
            "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        assert_raises_rpc_error(
            -5, "Block hash not found", self.nodes[0].getrawtransaction, tx,
            True,
            "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx,
                                                verbose=True,
                                                blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        if not self.options.descriptors:
            # The traditional multisig workflow does not work with descriptor wallets so these are legacy only.
            # The multisig workflow with descriptor wallets uses PSBTs and is tested elsewhere, no need to do them here.
            #########################
            # RAW TX MULTISIG TESTS #
            #########################
            # 2of2 test
            addr1 = self.nodes[2].getnewaddress()
            addr2 = self.nodes[2].getnewaddress()

            addr1Obj = self.nodes[2].getaddressinfo(addr1)
            addr2Obj = self.nodes[2].getaddressinfo(addr2)

            # Tests for createmultisig and addmultisigaddress
            assert_raises_rpc_error(-5, "Invalid public key",
                                    self.nodes[0].createmultisig, 1,
                                    ["01020304"])
            self.nodes[0].createmultisig(
                2, [addr1Obj['pubkey'], addr2Obj['pubkey']
                    ])  # createmultisig can only take public keys
            assert_raises_rpc_error(
                -5, "Invalid public key", self.nodes[0].createmultisig, 2,
                [addr1Obj['pubkey'], addr1]
            )  # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.

            mSigObj = self.nodes[2].addmultisigaddress(
                2, [addr1Obj['pubkey'], addr1])['address']

            #use balance deltas instead of absolute values
            bal = self.nodes[2].getbalance()

            # send 1.2 BTC to msig adr
            txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()
            assert_equal(
                self.nodes[2].getbalance(), bal + Decimal('1.20000000')
            )  #node2 has both keys of the 2of2 ms addr., tx should affect the balance

            # 2of3 test from different nodes
            bal = self.nodes[2].getbalance()
            addr1 = self.nodes[1].getnewaddress()
            addr2 = self.nodes[2].getnewaddress()
            addr3 = self.nodes[2].getnewaddress()

            addr1Obj = self.nodes[1].getaddressinfo(addr1)
            addr2Obj = self.nodes[2].getaddressinfo(addr2)
            addr3Obj = self.nodes[2].getaddressinfo(addr3)

            mSigObj = self.nodes[2].addmultisigaddress(
                2,
                [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']
                 ])['address']

            txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
            decTx = self.nodes[0].gettransaction(txId)
            rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()

            #THIS IS AN INCOMPLETE FEATURE
            #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
            assert_equal(
                self.nodes[2].getbalance(), bal
            )  #for now, assume the funds of a 2of3 multisig tx are not marked as spendable

            txDetails = self.nodes[0].gettransaction(txId, True)
            rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
            vout = next(o for o in rawTx['vout']
                        if o['value'] == Decimal('2.20000000'))

            bal = self.nodes[0].getbalance()
            inputs = [{
                "txid": txId,
                "vout": vout['n'],
                "scriptPubKey": vout['scriptPubKey']['hex'],
                "amount": vout['value']
            }]
            outputs = {self.nodes[0].getnewaddress(): 2.19}
            rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
            rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(
                rawTx, inputs)
            assert_equal(
                rawTxPartialSigned['complete'],
                False)  #node1 only has one key, can't comp. sign the tx

            rawTxSigned = self.nodes[2].signrawtransactionwithwallet(
                rawTx, inputs)
            assert_equal(
                rawTxSigned['complete'],
                True)  #node2 can sign the tx compl., own two of three keys
            self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
            rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()
            assert_equal(self.nodes[0].getbalance(),
                         bal + Decimal('50.00000000') +
                         Decimal('2.19000000'))  #block reward + tx

            # 2of2 test for combining transactions
            bal = self.nodes[2].getbalance()
            addr1 = self.nodes[1].getnewaddress()
            addr2 = self.nodes[2].getnewaddress()

            addr1Obj = self.nodes[1].getaddressinfo(addr1)
            addr2Obj = self.nodes[2].getaddressinfo(addr2)

            self.nodes[1].addmultisigaddress(
                2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
            mSigObj = self.nodes[2].addmultisigaddress(
                2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
            mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

            txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
            decTx = self.nodes[0].gettransaction(txId)
            rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()

            assert_equal(
                self.nodes[2].getbalance(), bal
            )  # the funds of a 2of2 multisig tx should not be marked as spendable

            txDetails = self.nodes[0].gettransaction(txId, True)
            rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
            vout = next(o for o in rawTx2['vout']
                        if o['value'] == Decimal('2.20000000'))

            bal = self.nodes[0].getbalance()
            inputs = [{
                "txid": txId,
                "vout": vout['n'],
                "scriptPubKey": vout['scriptPubKey']['hex'],
                "redeemScript": mSigObjValid['hex'],
                "amount": vout['value']
            }]
            outputs = {self.nodes[0].getnewaddress(): 2.19}
            rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
            rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(
                rawTx2, inputs)
            self.log.debug(rawTxPartialSigned1)
            assert_equal(
                rawTxPartialSigned1['complete'],
                False)  #node1 only has one key, can't comp. sign the tx

            rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(
                rawTx2, inputs)
            self.log.debug(rawTxPartialSigned2)
            assert_equal(
                rawTxPartialSigned2['complete'],
                False)  #node2 only has one key, can't comp. sign the tx
            rawTxComb = self.nodes[2].combinerawtransaction(
                [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
            self.log.debug(rawTxComb)
            self.nodes[2].sendrawtransaction(rawTxComb)
            rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()
            assert_equal(self.nodes[0].getbalance(),
                         bal + Decimal('50.00000000') +
                         Decimal('2.19000000'))  #block reward + tx

        # decoderawtransaction tests
        # witness transaction
        encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, True)  # decode as witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        assert_raises_rpc_error(
            -22, 'TX decode failed', self.nodes[0].decoderawtransaction,
            encrawtx, False)  # force decode as non-witness transaction
        # non-witness transaction
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, False)  # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        # known ambiguous transaction in the chain (see https://github.com/bitcoin/bitcoin/issues/20579)
        encrawtx = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03c68708046ff8415c622f4254432e434f4d2ffabe6d6de1965d02c68f928e5b244ab1965115a36f56eb997633c7f690124bbf43644e23080000000ca3d3af6d005a65ff0200fd00000000ffffffff03f4c1fb4b0000000016001497cfc76442fe717f2a3f0cc9c175f7561b6619970000000000000000266a24aa21a9ed957d1036a80343e0d1b659497e1b48a38ebe876a056d45965fac4a85cda84e1900000000000000002952534b424c4f434b3a8e092581ab01986cbadc84f4b43f4fa4bb9e7a2e2a0caf9b7cf64d939028e22c0120000000000000000000000000000000000000000000000000000000000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(encrawtx)
        decrawtx_wit = self.nodes[0].decoderawtransaction(encrawtx, True)
        assert_raises_rpc_error(
            -22, 'TX decode failed', self.nodes[0].decoderawtransaction,
            encrawtx, False)  # fails to decode as non-witness transaction
        assert_equal(
            decrawtx,
            decrawtx_wit)  # the witness interpretation should be chosen
        assert_equal(
            decrawtx['vin'][0]['coinbase'],
            "03c68708046ff8415c622f4254432e434f4d2ffabe6d6de1965d02c68f928e5b244ab1965115a36f56eb997633c7f690124bbf43644e23080000000ca3d3af6d005a65ff0200fd00000000"
        )

        # Basic signrawtransaction test
        addr = self.nodes[1].getnewaddress()
        txid = self.nodes[0].sendtoaddress(addr, 10)
        self.nodes[0].generate(1)
        self.sync_all()
        vout = find_vout_for_address(self.nodes[1], txid, addr)
        rawTx = self.nodes[1].createrawtransaction(
            [{
                'txid': txid,
                'vout': vout
            }], {self.nodes[1].getnewaddress(): 9.999})
        rawTxSigned = self.nodes[1].signrawtransactionwithwallet(rawTx)
        txId = self.nodes[1].sendrawtransaction(rawTxSigned['hex'])
        self.nodes[0].generate(1)
        self.sync_all()

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        assert_equal(self.nodes[0].getrawtransaction(txId), rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, 0),
                     rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, False),
                     rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txId, 1)["hex"],
                     rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txId, True)["hex"],
                     rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txId, {})

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': -1
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967296
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967294
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed 32-bit integer.
        # As transaction version is unsigned, this should convert to its unsigned equivalent.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x80000000)

        # Test the maximum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)

        self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')

        # Test a transaction with a small fee.
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # Fee 10,000 satoshis, (1 - (10000 sat * 0.00000001 BTC/sat)) = 0.9999
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.99990000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # Fee 10,000 satoshis, ~100 b transaction, fee rate should land around 100 sat/byte = 0.00100000 BTC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']],
                                                  0.00001000)[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], 'max-fee-exceeded')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(
            -25,
            'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)',
            self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
        # and the following calls should both succeed
        testres = self.nodes[2].testmempoolaccept(
            rawtxs=[rawTxSigned['hex']])[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'])

        # Test a transaction with a large fee.
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # Fee 2,000,000 satoshis, (1 - (2000000 sat * 0.00000001 BTC/sat)) = 0.98
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.98000000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # Fee 2,000,000 satoshis, ~100 b transaction, fee rate should land around 20,000 sat/byte = 0.20000000 BTC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], 'max-fee-exceeded')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(
            -25,
            'Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)',
            self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
        # and the following calls should both succeed
        testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']],
                                                  maxfeerate='0.20000000')[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'],
                                         maxfeerate='0.20000000')
Beispiel #2
0
    def run_test(self):
        # Mine some coins
        self.nodes[0].generate(110)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for i in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for i in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]

        self.nodes[0].generate(1)
        self.sync_all()

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = [vout["value"] for vout in tx1["vout"]]
        v.sort()
        assert_approx(v[0], 0.2)
        assert_approx(v[1], 0.3, 0.0001)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = [vout["value"] for vout in tx2["vout"]]
        v.sort()
        assert_approx(v[0], 0.2)
        assert_approx(v[1], 1.3, 0.0001)

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=self.nodes[2].getbalance(), subtractfeefromamount=True)
        self.sync_all()
        self.nodes[0].generate(1)

        # Fill node2's wallet with 10000 outputs corresponding to the same
        # scriptPubKey
        for i in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}])
            tx = FromHex(CTransaction(), raw_tx)
            tx.vin = []
            tx.vout = [tx.vout[0]] * 2000
            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
            signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.nodes[0].generate(1)

        self.sync_all()

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
Beispiel #3
0
    def run_test(self):
        self.log.info(
            'prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info(
            'Test getrawtransaction on genesis block coinbase returns an error'
        )
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(
            -5,
            "The genesis block coinbase is not considered an ordinary transaction",
            self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info(
            'Check parameter types and required parameters of createrawtransaction'
        )
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                False, 'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array",
                                self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected",
                                self.nodes[0].createrawtransaction, ['foo'],
                                {})
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(
            -8, "txid must be of length 64 (not 3, for 'foo')",
            self.nodes[0].createrawtransaction, [{
                'txid': 'foo'
            }], {})
        assert_raises_rpc_error(
            -8,
            "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')",
            self.nodes[0].createrawtransaction, [{
                'txid':
                'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'
            }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid,
                                    'vout': 'foo'
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive",
                                self.nodes[0].createrawtransaction, [{
                                    'txid': txid,
                                    'vout': -1
                                }], {})
        assert_raises_rpc_error(
            -8, "Invalid parameter, sequence number is out of range",
            self.nodes[0].createrawtransaction, [{
                'txid': txid,
                'vout': 0,
                'sequence': -1
            }], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected",
                                self.nodes[0].createrawtransaction, [], 'foo')
        self.nodes[0].createrawtransaction(
            inputs=[],
            outputs={})  # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [],
                                {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid arcticoin address",
                                self.nodes[0].createrawtransaction, [],
                                {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount",
                                self.nodes[0].createrawtransaction, [],
                                {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range",
                                self.nodes[0].createrawtransaction, [],
                                {address: -1})
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [],
            multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: %s" % address,
            self.nodes[0].createrawtransaction, [], [{
                address: 1
            }, {
                address: 1
            }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                [{
                                    "data": 'aa'
                                }, {
                                    "data": "bb"
                                }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                multidict([("data", 'aa'), ("data", "bb")]))
        assert_raises_rpc_error(
            -8,
            "Invalid parameter, key-value pair must contain exactly one key",
            self.nodes[0].createrawtransaction, [], [{
                'a': 1,
                'b': 2
            }])
        assert_raises_rpc_error(
            -8, "Invalid parameter, key-value pair not an object as expected",
            self.nodes[0].createrawtransaction, [],
            [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number",
                                self.nodes[0].createrawtransaction, [], {},
                                'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {},
                                4294967296)

        # Test `createrawtransaction` invalid `replaceable`
        assert_raises_rpc_error(-3, "Expected type bool",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                'foo')

        self.log.info(
            'Check that createrawtransaction accepts an array and object as outputs'
        )
        tx = CTransaction()
        # One output
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }]),
        )
        # Two outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }]),
        )
        # Multiple mixed outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=multidict([(address, 99), (address2, 99),
                                       ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            bytes_to_hex_str(tx.serialize()),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }, {
                                                   'data': '99'
                                               }]),
        )

        for type in ["bech32", "p2sh-segwit", "legacy"]:
            addr = self.nodes[0].getnewaddress("", type)
            addrinfo = self.nodes[0].getaddressinfo(addr)
            pubkey = addrinfo["scriptPubKey"]

            self.log.info('sendrawtransaction with missing prevtx info (%s)' %
                          (type))

            # Test `signrawtransactionwithwallet` invalid `prevtxs`
            inputs = [{'txid': txid, 'vout': 3, 'sequence': 1000}]
            outputs = {self.nodes[0].getnewaddress(): 1}
            rawtx = self.nodes[0].createrawtransaction(inputs, outputs)

            prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)
            succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
            assert succ["complete"]
            if type == "legacy":
                del prevtx["amount"]
                succ = self.nodes[0].signrawtransactionwithwallet(
                    rawtx, [prevtx])
                assert succ["complete"]

            if type != "legacy":
                assert_raises_rpc_error(
                    -3, "Missing amount",
                    self.nodes[0].signrawtransactionwithwallet, rawtx,
                    [{
                        "txid": txid,
                        "scriptPubKey": pubkey,
                        "vout": 3,
                    }])

            assert_raises_rpc_error(-3, "Missing vout",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "scriptPubKey": pubkey,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing txid",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "scriptPubKey": pubkey,
                                        "vout": 3,
                                        "amount": 1,
                                    }])
            assert_raises_rpc_error(-3, "Missing scriptPubKey",
                                    self.nodes[0].signrawtransactionwithwallet,
                                    rawtx, [{
                                        "txid": txid,
                                        "vout": 3,
                                        "amount": 1
                                    }])

        #########################################
        # sendrawtransaction with missing input #
        #########################################

        self.log.info('sendrawtransaction with missing input')
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]  #won't exists
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "Missing inputs",
                                self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found",
                                self.nodes[0].getrawtransaction, tx, True,
                                block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].getrawtransaction, tx, True,
                                True)
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 6, for 'foobar')",
            self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')",
            self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(
            -8,
            "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[0].getrawtransaction, tx, True,
            "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        assert_raises_rpc_error(
            -5, "Block hash not found", self.nodes[0].getrawtransaction, tx,
            True,
            "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx,
                                                verbose=True,
                                                blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        #########################
        # RAW TX MULTISIG TESTS #
        #########################
        # 2of2 test
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-5, "Invalid public key",
                                self.nodes[0].createmultisig, 1, ["01020304"])
        self.nodes[0].createmultisig(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']
                ])  # createmultisig can only take public keys
        assert_raises_rpc_error(
            -5, "Invalid public key", self.nodes[0].createmultisig, 2,
            [addr1Obj['pubkey'], addr1]
        )  # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr1])['address']

        #use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 BTC to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(
            self.nodes[2].getbalance(), bal + Decimal('1.20000000')
        )  #node2 has both keys of the 2of2 ms addr., tx should affect the balance

        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)
        addr3Obj = self.nodes[2].getaddressinfo(addr3)

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']
                ])['address']

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #THIS IS AN INCOMPLETE FEATURE
        #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
        assert_equal(
            self.nodes[2].getbalance(), bal
        )  #for now, assume the funds of a 2of3 multisig tx are not marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(
            rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx, inputs)
        assert_equal(
            rawTxSigned['complete'],
            True)  #node2 can sign the tx compl., own two of three keys
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  #block reward + tx

        # 2of2 test for combining transactions
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        self.nodes[1].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(
            self.nodes[2].getbalance(), bal
        )  # the funds of a 2of2 multisig tx should not be marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx2['vout']:
            if outpoint['value'] == Decimal('2.20000000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "redeemScript": mSigObjValid['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        assert_equal(rawTxPartialSigned1['complete'],
                     False)  #node1 only has one key, can't comp. sign the tx

        rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned2)
        assert_equal(rawTxPartialSigned2['complete'],
                     False)  #node2 only has one key, can't comp. sign the tx
        rawTxComb = self.nodes[2].combinerawtransaction(
            [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
        self.log.debug(rawTxComb)
        self.nodes[2].sendrawtransaction(rawTxComb)
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  #block reward + tx

        # decoderawtransaction tests
        # witness transaction
        encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, True)  # decode as witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
        assert_raises_rpc_error(
            -22, 'TX decode failed', self.nodes[0].decoderawtransaction,
            encrawtx, False)  # force decode as non-witness transaction
        # non-witness transaction
        encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
        decrawtx = self.nodes[0].decoderawtransaction(
            encrawtx, False)  # decode as non-witness transaction
        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txHash = rawTx["hash"]
        assert_equal(self.nodes[0].getrawtransaction(txHash),
                     rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, 0),
                     rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, False),
                     rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"],
                     rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"],
                     rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash,
                                "Flase")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, {})

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': -1
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967296
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 4294967294
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], -0x80000000)

        # Test the maximum transaction version number that fits in a signed 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)
    def run_test(self):
        self.nodes[0].generate(161)  # block 161

        self.log.info(
            "Verify sigops are counted in GBT with pre-BIP141 rules before the fork"
        )
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert tmpl['sizelimit'] == 1000000
        assert 'weightlimit' not in tmpl
        assert tmpl['sigoplimit'] == 20000
        assert tmpl['transactions'][0]['hash'] == txid
        assert tmpl['transactions'][0]['sigops'] == 2
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert tmpl['sizelimit'] == 1000000
        assert 'weightlimit' not in tmpl
        assert tmpl['sigoplimit'] == 20000
        assert tmpl['transactions'][0]['hash'] == txid
        assert tmpl['transactions'][0]['sigops'] == 2
        self.nodes[0].generate(1)  # block 162

        balance_presetup = self.nodes[0].getbalance()
        self.pubkey = []
        p2sh_ids = [
        ]  # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh
        wit_ids = [
        ]  # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness
        for i in range(3):
            newaddress = self.nodes[i].getnewaddress()
            self.pubkey.append(
                self.nodes[i].getaddressinfo(newaddress)["pubkey"])
            multiscript = CScript([
                OP_1,
                hex_str_to_bytes(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG
            ])
            p2sh_ms_addr = self.nodes[i].addmultisigaddress(
                1, [self.pubkey[-1]], '', 'p2sh-segwit')['address']
            bip173_ms_addr = self.nodes[i].addmultisigaddress(
                1, [self.pubkey[-1]], '', 'bech32')['address']
            assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))
            assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))
            p2sh_ids.append([])
            wit_ids.append([])
            for v in range(2):
                p2sh_ids[i].append([])
                wit_ids[i].append([])

        for i in range(5):
            for n in range(3):
                for v in range(2):
                    wit_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], False,
                                        Decimal("49.999")))
                    p2sh_ids[n][v].append(
                        send_to_witness(v, self.nodes[0],
                                        find_spendable_utxo(self.nodes[0], 50),
                                        self.pubkey[n], True,
                                        Decimal("49.999")))

        self.nodes[0].generate(1)  # block 163
        self.sync_blocks()

        # Make sure all nodes recognize the transactions as theirs
        assert_equal(self.nodes[0].getbalance(),
                     balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50)
        assert_equal(self.nodes[1].getbalance(), 20 * Decimal("49.999"))
        assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999"))

        self.nodes[0].generate(260)  # block 423
        self.sync_blocks()

        self.log.info(
            "Verify witness txs are skipped for mining before the fork")
        self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0],
                       True)  # block 424
        self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0],
                       True)  # block 425
        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0],
                       True)  # block 426
        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0],
                       True)  # block 427

        self.log.info(
            "Verify unsigned p2sh witness txs without a redeem script are invalid"
        )
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_2][WIT_V0][1], False)
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_2][WIT_V1][1], False)

        self.nodes[2].generate(4)  # blocks 428-431

        self.log.info(
            "Verify previous witness txs skipped for mining can now be mined")
        assert_equal(len(self.nodes[2].getrawmempool()), 4)
        blockhash = self.nodes[2].generate(1)[
            0]  # block 432 (first block with new rules; 432 = 144 * 3)
        self.sync_blocks()
        assert_equal(len(self.nodes[2].getrawmempool()), 0)
        segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"]
        assert_equal(len(segwit_tx_list), 5)

        self.log.info(
            "Verify default node can't accept txs with missing witness")
        # unsigned, no scriptsig
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         wit_ids[NODE_0][WIT_V0][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         wit_ids[NODE_0][WIT_V1][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V0][0], False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V1][0], False)
        # unsigned with redeem script
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V0][0], False,
                         witness_script(False, self.pubkey[0]))
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag",
                         p2sh_ids[NODE_0][WIT_V1][0], False,
                         witness_script(True, self.pubkey[0]))

        self.log.info(
            "Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag"
        )
        assert self.nodes[2].getblock(
            blockhash, False) != self.nodes[0].getblock(blockhash, False)
        assert self.nodes[1].getblock(blockhash,
                                      False) == self.nodes[2].getblock(
                                          blockhash, False)

        for tx_id in segwit_tx_list:
            tx = FromHex(CTransaction(),
                         self.nodes[2].gettransaction(tx_id)["hex"])
            assert self.nodes[2].getrawtransaction(
                tx_id, False, blockhash) != self.nodes[0].getrawtransaction(
                    tx_id, False, blockhash)
            assert self.nodes[1].getrawtransaction(
                tx_id, False, blockhash) == self.nodes[2].getrawtransaction(
                    tx_id, False, blockhash)
            assert self.nodes[0].getrawtransaction(
                tx_id, False,
                blockhash) != self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[1].getrawtransaction(
                tx_id, False,
                blockhash) == self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[0].getrawtransaction(
                tx_id, False,
                blockhash) == tx.serialize_without_witness().hex()

        self.log.info(
            "Verify witness txs without witness data are invalid after the fork"
        )
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)',
            wit_ids[NODE_2][WIT_V0][2],
            sign=False)
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)',
            wit_ids[NODE_2][WIT_V1][2],
            sign=False)
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)',
            p2sh_ids[NODE_2][WIT_V0][2],
            sign=False,
            redeem_script=witness_script(False, self.pubkey[2]))
        self.fail_accept(
            self.nodes[2],
            'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)',
            p2sh_ids[NODE_2][WIT_V1][2],
            sign=False,
            redeem_script=witness_script(True, self.pubkey[2]))

        self.log.info("Verify default node can now use witness txs")
        self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0],
                          True)  # block 432
        self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0],
                          True)  # block 433
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0],
                          True)  # block 434
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0],
                          True)  # block 435

        self.log.info(
            "Verify sigops are counted in GBT with BIP141 rules after the fork"
        )
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert tmpl[
            'sizelimit'] >= 3999577  # actual maximum size is lower due to minimum mandatory non-witness data
        assert tmpl['weightlimit'] == 4000000
        assert tmpl['sigoplimit'] == 80000
        assert tmpl['transactions'][0]['txid'] == txid
        assert tmpl['transactions'][0]['sigops'] == 8

        self.nodes[0].generate(1)  # Mine a block to clear the gbt cache

        self.log.info(
            "Non-segwit miners are able to use GBT response after activation.")
        # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->
        #                      tx2 (segwit input, paying to a non-segwit output) ->
        #                      tx3 (non-segwit input, paying to a non-segwit output).
        # tx1 is allowed to appear in the block, but no others.
        txid1 = send_to_witness(1, self.nodes[0],
                                find_spendable_utxo(self.nodes[0], 50),
                                self.pubkey[0], False, Decimal("49.996"))
        hex_tx = self.nodes[0].gettransaction(txid)['hex']
        tx = FromHex(CTransaction(), hex_tx)
        assert tx.wit.is_null()  # This should not be a segwit input
        assert txid1 in self.nodes[0].getrawmempool()

        tx1_hex = self.nodes[0].gettransaction(txid1)['hex']
        tx1 = FromHex(CTransaction(), tx1_hex)

        # Check that wtxid is properly reported in mempool entry (txid1)
        assert_equal(int(self.nodes[0].getmempoolentry(txid1)["wtxid"], 16),
                     tx1.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid1)
        assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"],
                     (self.nodes[0].getmempoolentry(txid1)["weight"] + 3) // 4)
        assert_equal(
            self.nodes[0].getmempoolentry(txid1)["weight"],
            len(tx1.serialize_without_witness()) * 3 +
            len(tx1.serialize_with_witness()))

        # Now create tx2, which will spend from txid1.
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))
        tx.vout.append(
            CTxOut(int(49.99 * COIN),
                   CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
        tx2_hex = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))['hex']
        txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
        tx = FromHex(CTransaction(), tx2_hex)
        assert not tx.wit.is_null()

        # Check that wtxid is properly reported in mempool entry (txid2)
        assert_equal(int(self.nodes[0].getmempoolentry(txid2)["wtxid"], 16),
                     tx.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid2)
        assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"],
                     (self.nodes[0].getmempoolentry(txid2)["weight"] + 3) // 4)
        assert_equal(
            self.nodes[0].getmempoolentry(txid2)["weight"],
            len(tx.serialize_without_witness()) * 3 +
            len(tx.serialize_with_witness()))

        # Now create tx3, which will spend from txid2
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
        tx.vout.append(
            CTxOut(int(49.95 * COIN),
                   CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))  # Huge fee
        tx.calc_sha256()
        txid3 = self.nodes[0].sendrawtransaction(hexstring=ToHex(tx),
                                                 maxfeerate=0)
        assert tx.wit.is_null()
        assert txid3 in self.nodes[0].getrawmempool()

        # Check that getblocktemplate includes all transactions.
        template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
        template_txids = [t['txid'] for t in template['transactions']]
        assert txid1 in template_txids
        assert txid2 in template_txids
        assert txid3 in template_txids

        # Check that wtxid is properly reported in mempool entry (txid3)
        assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16),
                     tx.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid3)
        assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"],
                     (self.nodes[0].getmempoolentry(txid3)["weight"] + 3) // 4)
        assert_equal(
            self.nodes[0].getmempoolentry(txid3)["weight"],
            len(tx.serialize_without_witness()) * 3 +
            len(tx.serialize_with_witness()))

        # Mine a block to clear the gbt cache again.
        self.nodes[0].generate(1)

        self.log.info("Verify behaviour of importaddress and listunspent")

        # Some public keys to be used later
        pubkeys = [
            "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242",  # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
            "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF",  # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
            "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E",  # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
            "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538",  # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
            "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228",  # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
            "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC",  # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
            "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84",  # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
        ]

        # Import a compressed key and an uncompressed key, generate some multisig addresses
        self.nodes[0].importprivkey(
            "92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn")
        uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"]
        self.nodes[0].importprivkey(
            "cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
        compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"]
        assert not self.nodes[0].getaddressinfo(
            uncompressed_spendable_address[0])['iscompressed']
        assert self.nodes[0].getaddressinfo(
            compressed_spendable_address[0])['iscompressed']

        self.nodes[0].importpubkey(pubkeys[0])
        compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
        self.nodes[0].importpubkey(pubkeys[1])
        compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))
        self.nodes[0].importpubkey(pubkeys[2])
        uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]

        spendable_anytime = [
        ]  # These outputs should be seen anytime after importprivkey and addmultisigaddress
        spendable_after_importaddress = [
        ]  # These outputs should be seen after importaddress
        solvable_after_importaddress = [
        ]  # These outputs should be seen after importaddress but not spendable
        unsolvable_after_importaddress = [
        ]  # These outputs should be unsolvable after importaddress
        solvable_anytime = [
        ]  # These outputs should be solvable after importpubkey
        unseen_anytime = []  # These outputs should never be seen

        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                compressed_spendable_address[0]
            ])['address'])
        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                uncompressed_spendable_address[0]
            ])['address'])
        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_spendable_address[0]
             ])['address'])
        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                compressed_spendable_address[0],
                uncompressed_solvable_address[0]
            ])['address'])
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_solvable_address[0]
             ])['address'])
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_solvable_address[0], compressed_solvable_address[1]
             ])['address'])

        # Test multisig_without_privkey
        # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
        # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.

        multisig_without_privkey_address = self.nodes[0].addmultisigaddress(
            2, [pubkeys[3], pubkeys[4]])['address']
        script = CScript([
            OP_2,
            hex_str_to_bytes(pubkeys[3]),
            hex_str_to_bytes(pubkeys[4]), OP_2, OP_CHECKMULTISIG
        ])
        solvable_after_importaddress.append(
            CScript([OP_HASH160, hash160(script), OP_EQUAL]))

        for i in compressed_spendable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # p2sh multisig with compressed keys should always be spendable
                spendable_anytime.extend([p2sh])
                # bare multisig can be watched and signed, but is not treated as ours
                solvable_after_importaddress.extend([bare])
                # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
                spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH and P2PK with compressed keys should always be spendable
                spendable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress
                spendable_after_importaddress.extend([
                    p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])
                # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable
                spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

        for i in uncompressed_spendable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # p2sh multisig with uncompressed keys should always be spendable
                spendable_anytime.extend([p2sh])
                # bare multisig can be watched and signed, but is not treated as ours
                solvable_after_importaddress.extend([bare])
                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                unseen_anytime.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH and P2PK with uncompressed keys should always be spendable
                spendable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress
                spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
                # Witness output types with uncompressed keys are never seen
                unseen_anytime.extend([
                    p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        for i in compressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                # Multisig without private is not seen after addmultisigaddress, but seen after importaddress
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                solvable_after_importaddress.extend(
                    [bare, p2sh, p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH, P2PK, P2WPKH and P2SH_P2WPKH with compressed keys should always be seen
                solvable_anytime.extend([p2pkh, p2pk, p2wpkh, p2sh_p2wpkh])
                # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after direct importaddress
                solvable_after_importaddress.extend([
                    p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        for i in uncompressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
                solvable_after_importaddress.extend([bare, p2sh])
                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                unseen_anytime.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # normal P2PKH and P2PK with uncompressed keys should always be seen
                solvable_anytime.extend([p2pkh, p2pk])
                # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress
                solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
                # Witness output types with uncompressed keys are never seen
                unseen_anytime.extend([
                    p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh,
                    p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ])

        op1 = CScript([OP_1])
        op0 = CScript([OP_0])
        # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
        unsolvable_address_key = hex_str_to_bytes(
            "02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D"
        )
        unsolvablep2pkh = CScript([
            OP_DUP, OP_HASH160,
            hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG
        ])
        unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)])
        p2shop0 = CScript([OP_HASH160, hash160(op0), OP_EQUAL])
        p2wshop1 = CScript([OP_0, sha256(op1)])
        unsolvable_after_importaddress.append(unsolvablep2pkh)
        unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
        unsolvable_after_importaddress.append(
            op1)  # OP_1 will be imported as script
        unsolvable_after_importaddress.append(p2wshop1)
        unseen_anytime.append(
            op0
        )  # OP_0 will be imported as P2SH address with no script provided
        unsolvable_after_importaddress.append(p2shop0)

        spendable_txid = []
        solvable_txid = []
        spendable_txid.append(
            self.mine_and_test_listunspent(spendable_anytime, 2))
        solvable_txid.append(
            self.mine_and_test_listunspent(solvable_anytime, 1))
        self.mine_and_test_listunspent(
            spendable_after_importaddress + solvable_after_importaddress +
            unseen_anytime + unsolvable_after_importaddress, 0)

        importlist = []
        for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                bare = hex_str_to_bytes(v['hex'])
                importlist.append(bare.hex())
                importlist.append(CScript([OP_0, sha256(bare)]).hex())
            else:
                pubkey = hex_str_to_bytes(v['pubkey'])
                p2pk = CScript([pubkey, OP_CHECKSIG])
                p2pkh = CScript([
                    OP_DUP, OP_HASH160,
                    hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG
                ])
                importlist.append(p2pk.hex())
                importlist.append(p2pkh.hex())
                importlist.append(CScript([OP_0, hash160(pubkey)]).hex())
                importlist.append(CScript([OP_0, sha256(p2pk)]).hex())
                importlist.append(CScript([OP_0, sha256(p2pkh)]).hex())

        importlist.append(unsolvablep2pkh.hex())
        importlist.append(unsolvablep2wshp2pkh.hex())
        importlist.append(op1.hex())
        importlist.append(p2wshop1.hex())

        for i in importlist:
            # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
            # exceptions and continue.
            try_rpc(
                -4,
                "The wallet already contains the private key for this address or script",
                self.nodes[0].importaddress, i, "", False, True)

        self.nodes[0].importaddress(
            script_to_p2sh(op0))  # import OP_0 as address only
        self.nodes[0].importaddress(
            multisig_without_privkey_address)  # Test multisig_without_privkey

        spendable_txid.append(
            self.mine_and_test_listunspent(
                spendable_anytime + spendable_after_importaddress, 2))
        solvable_txid.append(
            self.mine_and_test_listunspent(
                solvable_anytime + solvable_after_importaddress, 1))
        self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
        self.mine_and_test_listunspent(unseen_anytime, 0)

        spendable_txid.append(
            self.mine_and_test_listunspent(
                spendable_anytime + spendable_after_importaddress, 2))
        solvable_txid.append(
            self.mine_and_test_listunspent(
                solvable_anytime + solvable_after_importaddress, 1))
        self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
        self.mine_and_test_listunspent(unseen_anytime, 0)

        # Repeat some tests. This time we don't add witness scripts with importaddress
        # Import a compressed key and an uncompressed key, generate some multisig addresses
        self.nodes[0].importprivkey(
            "927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH")
        uncompressed_spendable_address = ["mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"]
        self.nodes[0].importprivkey(
            "cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw")
        compressed_spendable_address = ["n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"]

        self.nodes[0].importpubkey(pubkeys[5])
        compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]
        self.nodes[0].importpubkey(pubkeys[6])
        uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]

        unseen_anytime = []  # These outputs should never be seen
        solvable_anytime = [
        ]  # These outputs should be solvable after importpubkey
        unseen_anytime = []  # These outputs should never be seen

        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                compressed_spendable_address[0]
            ])['address'])
        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2, [
                uncompressed_spendable_address[0],
                uncompressed_spendable_address[0]
            ])['address'])
        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_spendable_address[0]
             ])['address'])
        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_solvable_address[0], uncompressed_solvable_address[0]
             ])['address'])
        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(
            2,
            [compressed_spendable_address[0], compressed_solvable_address[0]
             ])['address'])

        premature_witaddress = []

        for i in compressed_spendable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                premature_witaddress.append(script_to_p2sh(p2wsh))
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # P2WPKH, P2SH_P2WPKH are always spendable
                spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

        for i in uncompressed_spendable_address + uncompressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                unseen_anytime.extend([p2wsh, p2sh_p2wsh])
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen
                unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])

        for i in compressed_solvable_address:
            v = self.nodes[0].getaddressinfo(i)
            if (v['isscript']):
                [bare, p2sh, p2wsh,
                 p2sh_p2wsh] = self.p2sh_address_to_script(v)
                premature_witaddress.append(script_to_p2sh(p2wsh))
            else:
                [
                    p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh,
                    p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh
                ] = self.p2pkh_address_to_script(v)
                # P2SH_P2PK, P2SH_P2PKH with compressed keys are always solvable
                solvable_anytime.extend([p2wpkh, p2sh_p2wpkh])

        self.mine_and_test_listunspent(spendable_anytime, 2)
        self.mine_and_test_listunspent(solvable_anytime, 1)
        self.mine_and_test_listunspent(unseen_anytime, 0)

        # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works
        v1_addr = program_to_witness(1, [3, 5])
        v1_tx = self.nodes[0].createrawtransaction(
            [getutxo(spendable_txid[0])], {v1_addr: 1})
        v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
        assert_equal(v1_decoded['vout'][0]['scriptPubKey']['addresses'][0],
                     v1_addr)
        assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305")

        # Check that spendable outputs are really spendable
        self.create_and_mine_tx_from_txids(spendable_txid)

        # import all the private keys so solvable addresses become spendable
        self.nodes[0].importprivkey(
            "cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb")
        self.nodes[0].importprivkey(
            "cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97")
        self.nodes[0].importprivkey(
            "91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV")
        self.nodes[0].importprivkey(
            "cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd")
        self.nodes[0].importprivkey(
            "cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66")
        self.nodes[0].importprivkey(
            "cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K")
        self.create_and_mine_tx_from_txids(solvable_txid)

        # Test that importing native P2WPKH/P2WSH scripts works
        for use_p2wsh in [False, True]:
            if use_p2wsh:
                scriptPubKey = "00203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a"
                transaction = "01000000000100e1f505000000002200203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a00000000"
            else:
                scriptPubKey = "a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d87"
                transaction = "01000000000100e1f5050000000017a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d8700000000"

            self.nodes[1].importaddress(scriptPubKey, "", False)
            rawtxfund = self.nodes[1].fundrawtransaction(transaction)['hex']
            rawtxfund = self.nodes[1].signrawtransactionwithwallet(
                rawtxfund)["hex"]
            txid = self.nodes[1].sendrawtransaction(rawtxfund)

            assert_equal(self.nodes[1].gettransaction(txid, True)["txid"],
                         txid)
            assert_equal(
                self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"],
                txid)

            # Assert it is properly saved
            self.stop_node(1)
            self.start_node(1)
            assert_equal(self.nodes[1].gettransaction(txid, True)["txid"],
                         txid)
            assert_equal(
                self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"],
                txid)
        def fund_and_test_wallet(scriptPubKey,
                                 shouldBeStandard,
                                 shouldBeInWallet,
                                 amount=10000,
                                 spendfee=500,
                                 nonstd_error="scriptpubkey (code 64)",
                                 sign_error=None):
            """ Get the nonstandard node to fund a transaction, test its
            standardness by trying to broadcast on the standard node, then
            mine it and see if it ended up in the standard node's wallet.
            Finally, it attempts to spend the coin.
            """

            self.log.info("Trying script {}".format(scriptPubKey.hex(), ))

            # get nonstandard node to fund the script
            tx = CTransaction()
            tx.vout.append(CTxOut(max(amount, 10000), scriptPubKey))
            rawtx = nonstd_node.fundrawtransaction(ToHex(tx), {
                'lockUnspents': True,
                'changePosition': 1
            })['hex']
            # fundrawtransaction doesn't like to fund dust outputs, so we
            # have to manually override the amount.
            FromHex(tx, rawtx)
            tx.vout[0].nValue = min(amount, 10000)
            rawtx = nonstd_node.signrawtransactionwithwallet(ToHex(tx))['hex']

            # ensure signing process did not disturb scriptPubKey
            signedtx = FromHex(CTransaction(), rawtx)
            assert_equal(scriptPubKey, signedtx.vout[0].scriptPubKey)
            txid = signedtx.rehash()

            balance_initial = std_node.getbalance()

            # try broadcasting it on the standard node
            if shouldBeStandard:
                std_node.sendrawtransaction(rawtx)
                assert txid in std_node.getrawmempool()
            else:
                assert_raises_rpc_error(-26, nonstd_error,
                                        std_node.sendrawtransaction, rawtx)
                assert txid not in std_node.getrawmempool()

            # make sure it's in nonstandard node's mempool, then mine it
            nonstd_node.sendrawtransaction(rawtx)
            assert txid in nonstd_node.getrawmempool()
            [blockhash] = nonstd_node.generate(1)
            # make sure it was mined
            assert txid in nonstd_node.getblock(blockhash)["tx"]

            sync_blocks(self.nodes)

            wallet_outpoints = {(entry['txid'], entry['vout'])
                                for entry in std_node.listunspent()}

            # calculate wallet balance change just as a double check
            balance_change = std_node.getbalance() - balance_initial
            if shouldBeInWallet:
                assert (txid, 0) in wallet_outpoints
                assert balance_change == amount * FIXOSHI
            else:
                assert (txid, 0) not in wallet_outpoints
                assert balance_change == 0

            # try spending the funds using the wallet.
            outamount = (amount - spendfee) * FIXOSHI
            if outamount < 546 * FIXOSHI:
                # If the final amount would be too small, then just donate
                # to miner fees.
                outputs = [{"data": b"to miner, with love".hex()}]
            else:
                outputs = [{address_nonstd: outamount}]
            spendtx = std_node.createrawtransaction([{
                'txid': txid,
                'vout': 0
            }], outputs)
            signresult = std_node.signrawtransactionwithwallet(spendtx)

            if sign_error is None:
                assert_equal(signresult['complete'], True)
                txid = std_node.sendrawtransaction(signresult['hex'])
                [blockhash] = std_node.generate(1)
                # make sure it was mined
                assert txid in std_node.getblock(blockhash)["tx"]
                sync_blocks(self.nodes)
            else:
                assert_equal(signresult['complete'], False)
                assert_equal(signresult['errors'][0]['error'], sign_error)
Beispiel #6
0
    def run_test(self):
        node = self.nodes[0]
        node.add_p2p_connection(P2PDataStore())
        node.setmocktime(ACTIVATION_TIME)

        self.genesis_hash = int(node.getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        spendable_outputs = []

        # save the current tip so it can be spent by a later block
        def save_spendable_output():
            spendable_outputs.append(self.tip)

        # get an output that we previously marked as spendable
        def get_spendable_output():
            return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0)

        # move the tip back to a previous block
        def tip(number):
            self.tip = self.blocks[number]

        # adds transactions to the block and updates state
        def update_block(block_number, new_transactions):
            block = self.blocks[block_number]
            block.vtx.extend(new_transactions)
            old_sha256 = block.sha256
            make_conform_to_ctor(block)
            block.hashMerkleRoot = block.calc_merkle_root()
            block.solve()
            # Update the internal state just like in next_block
            self.tip = block
            if block.sha256 != old_sha256:
                self.block_heights[
                    block.sha256] = self.block_heights[old_sha256]
                del self.block_heights[old_sha256]
            self.blocks[block_number] = block
            return block

        # send a txn to the mempool and check it was accepted
        def send_transaction_to_mempool(tx):
            tx_id = node.sendrawtransaction(ToHex(tx))
            assert (tx_id in node.getrawmempool())

        # checks the mempool has exactly the same txns as in the provided list
        def check_mempool_equal(txns):
            assert set(node.getrawmempool()) == set(tx.hash for tx in txns)

        # Create an always-valid chained transaction. It spends a
        # scriptPub=OP_TRUE coin into another. Returns the transaction and its
        # spendable output for further chaining.
        def create_always_valid_chained_tx(spend):
            tx = create_transaction(spend.tx, spend.n, b'',
                                    spend.tx.vout[0].nValue - 1000,
                                    CScript([OP_TRUE]))
            tx.rehash()
            return tx, PreviousSpendableOutput(tx, 0)

        # shorthand
        block = self.next_block

        # Create a new block
        block(0)
        save_spendable_output()
        node.p2p.send_blocks_and_test([self.tip], node)

        # Now we need that block to mature so we can spend the coinbase.
        maturity_blocks = []
        for i in range(110):
            block(5000 + i)
            maturity_blocks.append(self.tip)
            save_spendable_output()
        node.p2p.send_blocks_and_test(maturity_blocks, node)

        # collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(100):
            out.append(get_spendable_output())

        # Create 2 pre-fork-only txns (tx_pre0, tx_pre1). Fund txns are valid
        # pre-fork, so we can mine them right away.
        txfund0, tx_pre0 = create_fund_and_pre_fork_only_tx(out[0])
        txfund1, tx_pre1 = create_fund_and_pre_fork_only_tx(out[1])

        # Create 2 post-fork-only txns (tx_post0, tx_post1). Fund txns are
        # valid pre-fork, so we can mine them right away.
        txfund2, tx_post0 = create_fund_and_post_fork_only_tx(out[2])
        txfund3, tx_post1 = create_fund_and_post_fork_only_tx(out[3])

        # Create blocks to activate the fork. Mine all funding transactions.
        bfork = block(5555)
        bfork.nTime = ACTIVATION_TIME - 1
        update_block(5555, [txfund0, txfund1, txfund2, txfund3])
        node.p2p.send_blocks_and_test([self.tip], node)

        for i in range(5):
            node.p2p.send_blocks_and_test([block(5200 + i)], node)

        # Check we are just before the activation time
        assert_equal(
            node.getblockheader(node.getbestblockhash())['mediantime'],
            ACTIVATION_TIME - 1)

        # We are just before the fork. Pre-fork-only and always-valid chained
        # txns (tx_chain0, tx_chain1) are valid, post-fork-only txns are
        # rejected.
        send_transaction_to_mempool(tx_pre0)
        send_transaction_to_mempool(tx_pre1)
        tx_chain0, last_chained_output = create_always_valid_chained_tx(out[4])
        tx_chain1, last_chained_output = create_always_valid_chained_tx(
            last_chained_output)
        send_transaction_to_mempool(tx_chain0)
        send_transaction_to_mempool(tx_chain1)
        assert_raises_rpc_error(-26, RPC_EXPECTED_ERROR,
                                node.sendrawtransaction, ToHex(tx_post0))
        assert_raises_rpc_error(-26, RPC_EXPECTED_ERROR,
                                node.sendrawtransaction, ToHex(tx_post1))
        check_mempool_equal([tx_chain0, tx_chain1, tx_pre0, tx_pre1])

        # Activate the fork. Mine the 1st always-valid chained txn and a
        # pre-fork-only txn.
        block(5556)
        update_block(5556, [tx_chain0, tx_pre0])
        node.p2p.send_blocks_and_test([self.tip], node)
        forkblockid = node.getbestblockhash()

        # Check we just activated the fork
        assert_equal(
            node.getblockheader(forkblockid)['mediantime'], ACTIVATION_TIME)

        # Check mempool coherence when activating the fork. Pre-fork-only txns
        # were evicted from the mempool, while always-valid txns remain.
        # Evicted: tx_pre1
        check_mempool_equal([tx_chain1])

        # Post-fork-only and always-valid txns are accepted, pre-fork-only txn
        # are rejected.
        send_transaction_to_mempool(tx_post0)
        send_transaction_to_mempool(tx_post1)
        tx_chain2, _ = create_always_valid_chained_tx(last_chained_output)
        send_transaction_to_mempool(tx_chain2)
        assert_raises_rpc_error(-26, RPC_EXPECTED_ERROR,
                                node.sendrawtransaction, ToHex(tx_pre1))
        check_mempool_equal([tx_chain1, tx_chain2, tx_post0, tx_post1])

        # Mine the 2nd always-valid chained txn and a post-fork-only txn.
        block(5557)
        update_block(5557, [tx_chain1, tx_post0])
        node.p2p.send_blocks_and_test([self.tip], node)
        postforkblockid = node.getbestblockhash()
        # The mempool contains the 3rd chained txn and a post-fork-only txn.
        check_mempool_equal([tx_chain2, tx_post1])

        # In the following we will testing block disconnections and reorgs.
        # - tx_chain2 will always be retained in the mempool since it is always
        #   valid. Its continued presence shows that we are never simply
        #   clearing the entire mempool.
        # - tx_post1 may be evicted from mempool if we land before the fork.
        # - tx_post0 is in a block and if 'de-mined', it will either be evicted
        #   or end up in mempool depending if we land before/after the fork.
        # - tx_pre0 is in a block and if 'de-mined', it will either be evicted
        #   or end up in mempool depending if we land after/before the fork.

        # First we do a disconnection of the post-fork block, which is a
        # normal disconnection that merely returns the block contents into
        # the mempool -- nothing is lost.
        node.invalidateblock(postforkblockid)
        # In old mempool: tx_chain2, tx_post1
        # Recovered from blocks: tx_chain1 and tx_post0.
        # Lost from blocks: NONE
        # Retained from old mempool: tx_chain2, tx_post1
        # Evicted from old mempool: NONE
        check_mempool_equal([tx_chain1, tx_chain2, tx_post0, tx_post1])

        # Now, disconnect the fork block. This is a special disconnection
        # that requires reprocessing the mempool due to change in rules.
        node.invalidateblock(forkblockid)
        # In old mempool: tx_chain1, tx_chain2, tx_post0, tx_post1
        # Recovered from blocks: tx_chain0, tx_pre0
        # Lost from blocks: NONE
        # Retained from old mempool: tx_chain1, tx_chain2
        # Evicted from old mempool: tx_post0, tx_post1
        check_mempool_equal([tx_chain0, tx_chain1, tx_chain2, tx_pre0])

        # Restore state
        node.reconsiderblock(postforkblockid)
        node.reconsiderblock(forkblockid)
        send_transaction_to_mempool(tx_post1)
        check_mempool_equal([tx_chain2, tx_post1])

        # Test a reorg that crosses the fork.

        # If such a reorg happens, most likely it will both start *and end*
        # after the fork. We will test such a case here and make sure that
        # post-fork-only transactions are not unnecessarily discarded from
        # the mempool in such a reorg. Pre-fork-only transactions however can
        # get lost.

        # Set up a longer competing chain that doesn't confirm any of our txns.
        # This starts after 5204, so it contains neither the forkblockid nor
        # the postforkblockid from above.
        tip(5204)
        reorg_blocks = []
        for i in range(3):
            reorg_blocks.append(block(5900 + i))

        # Perform the reorg
        node.p2p.send_blocks_and_test(reorg_blocks, node)
        # reorg finishes after the fork
        assert_equal(
            node.getblockheader(node.getbestblockhash())['mediantime'],
            ACTIVATION_TIME + 2)
        # In old mempool: tx_chain2, tx_post1
        # Recovered from blocks: tx_chain0, tx_chain1, tx_post0
        # Lost from blocks: tx_pre0
        # Retained from old mempool: tx_chain2, tx_post1
        # Evicted from old mempool: NONE
        check_mempool_equal(
            [tx_chain0, tx_chain1, tx_chain2, tx_post0, tx_post1])
Beispiel #7
0
    def run_test(self):
        self.log.info(
            'prepare some coins for multiple *rawtransaction commands')
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
        self.sync_all()
        self.nodes[0].generate(5)
        self.sync_all()

        self.log.info(
            'Test getrawtransaction on genesis block coinbase returns an error'
        )
        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
        assert_raises_rpc_error(
            -5,
            "The genesis block coinbase is not considered an ordinary transaction",
            self.nodes[0].getrawtransaction, block['merkleroot'])

        self.log.info(
            'Check parameter types and required parameters of createrawtransaction'
        )
        # Test `createrawtransaction` required parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction)
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [])

        # Test `createrawtransaction` invalid extra parameters
        assert_raises_rpc_error(-1, "createrawtransaction",
                                self.nodes[0].createrawtransaction, [], {}, 0,
                                'foo')

        # Test `createrawtransaction` invalid `inputs`
        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
        assert_raises_rpc_error(-3, "Expected type array",
                                self.nodes[0].createrawtransaction, 'foo', {})
        assert_raises_rpc_error(-1, "JSON value is not an object as expected",
                                self.nodes[0].createrawtransaction, ['foo'],
                                {})
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].createrawtransaction, [{}], {})
        assert_raises_rpc_error(
            -8, "txid must be of length 64 (not 3, for 'foo')",
            self.nodes[0].createrawtransaction, [{
                'txid': 'foo'
            }], {})
        assert_raises_rpc_error(
            -8,
            "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')",
            self.nodes[0].createrawtransaction, [{
                'txid':
                'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'
            }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, missing vout key",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be a number",
                                self.nodes[0].createrawtransaction,
                                [{
                                    'txid': txid,
                                    'vout': 'foo'
                                }], {})
        assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive",
                                self.nodes[0].createrawtransaction, [{
                                    'txid': txid,
                                    'vout': -1
                                }], {})
        assert_raises_rpc_error(
            -8, "Invalid parameter, sequence number is out of range",
            self.nodes[0].createrawtransaction, [{
                'txid': txid,
                'vout': 0,
                'sequence': -1
            }], {})

        # Test `createrawtransaction` invalid `outputs`
        address = self.nodes[0].getnewaddress()
        address2 = self.nodes[0].getnewaddress()
        assert_raises_rpc_error(-1, "JSON value is not an array as expected",
                                self.nodes[0].createrawtransaction, [], 'foo')
        # Should not throw for backwards compatibility
        self.nodes[0].createrawtransaction(inputs=[], outputs={})
        self.nodes[0].createrawtransaction(inputs=[], outputs=[])
        assert_raises_rpc_error(-8, "Data must be hexadecimal string",
                                self.nodes[0].createrawtransaction, [],
                                {'data': 'foo'})
        assert_raises_rpc_error(-5, "Invalid Bitcoin address",
                                self.nodes[0].createrawtransaction, [],
                                {'foo': 0})
        assert_raises_rpc_error(-3, "Invalid amount",
                                self.nodes[0].createrawtransaction, [],
                                {address: 'foo'})
        assert_raises_rpc_error(-3, "Amount out of range",
                                self.nodes[0].createrawtransaction, [],
                                {address: -1})
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: {}".format(address),
            self.nodes[0].createrawtransaction, [],
            multidict([(address, 1), (address, 1)]))
        assert_raises_rpc_error(
            -8, "Invalid parameter, duplicated address: {}".format(address),
            self.nodes[0].createrawtransaction, [], [{
                address: 1
            }, {
                address: 1
            }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                [{
                                    "data": 'aa'
                                }, {
                                    "data": "bb"
                                }])
        assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
                                self.nodes[0].createrawtransaction, [],
                                multidict([("data", 'aa'), ("data", "bb")]))
        assert_raises_rpc_error(
            -8,
            "Invalid parameter, key-value pair must contain exactly one key",
            self.nodes[0].createrawtransaction, [], [{
                'a': 1,
                'b': 2
            }])
        assert_raises_rpc_error(
            -8, "Invalid parameter, key-value pair not an object as expected",
            self.nodes[0].createrawtransaction, [],
            [['key-value pair1'], ['2']])

        # Test `createrawtransaction` invalid `locktime`
        assert_raises_rpc_error(-3, "Expected type number",
                                self.nodes[0].createrawtransaction, [], {},
                                'foo')
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {}, -1)
        assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range",
                                self.nodes[0].createrawtransaction, [], {},
                                4294967296)

        self.log.info(
            'Check that createrawtransaction accepts an array and object as outputs'
        )
        tx = CTransaction()
        # One output
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }], outputs={address: 99}))))
        assert_equal(len(tx.vout), 1)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }]),
        )
        # Two outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=OrderedDict([(address, 99), (address2, 99)])))))
        assert_equal(len(tx.vout), 2)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }]),
        )
        # Multiple mixed outputs
        tx.deserialize(
            BytesIO(
                hex_str_to_bytes(self.nodes[2].createrawtransaction(
                    inputs=[{
                        'txid': txid,
                        'vout': 9
                    }],
                    outputs=multidict([(address, 99), (address2, 99),
                                       ('data', '99')])))))
        assert_equal(len(tx.vout), 3)
        assert_equal(
            tx.serialize().hex(),
            self.nodes[2].createrawtransaction(inputs=[{
                'txid': txid,
                'vout': 9
            }],
                                               outputs=[{
                                                   address: 99
                                               }, {
                                                   address2: 99
                                               }, {
                                                   'data': '99'
                                               }]),
        )

        self.log.info('sendrawtransaction with missing input')
        # won't exists
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = pad_raw_tx(rawtx)
        rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)

        # This will raise an exception since there are missing inputs
        assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent",
                                self.nodes[2].sendrawtransaction, rawtx['hex'])

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct
        # block
        gottx = self.nodes[0].getrawtransaction(tx, True, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a
        # block
        gottx = self.nodes[0].getrawtransaction(tx, True)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should not get the tx if we provide an unrelated block
        assert_raises_rpc_error(-5, "No such transaction found",
                                self.nodes[0].getrawtransaction, tx, True,
                                block2)
        # An invalid block hash should raise the correct errors
        assert_raises_rpc_error(-1, "JSON value is not a string as expected",
                                self.nodes[0].getrawtransaction, tx, True,
                                True)
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 6, for 'foobar')",
            self.nodes[0].getrawtransaction, tx, True, "foobar")
        assert_raises_rpc_error(
            -8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')",
            self.nodes[0].getrawtransaction, tx, True, "abcd1234")
        assert_raises_rpc_error(
            -8,
            "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[0].getrawtransaction, tx, True,
            "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        assert_raises_rpc_error(
            -5, "Block hash not found", self.nodes[0].getrawtransaction, tx,
            True,
            "0000000000000000000000000000000000000000000000000000000000000000")
        # Undo the blocks and check in_active_chain
        self.nodes[0].invalidateblock(block1)
        gottx = self.nodes[0].getrawtransaction(txid=tx,
                                                verbose=True,
                                                blockhash=block1)
        assert_equal(gottx['in_active_chain'], False)
        self.nodes[0].reconsiderblock(block1)
        assert_equal(self.nodes[0].getbestblockhash(), block2)

        #
        # RAW TX MULTISIG TESTS #
        #
        # 2of2 test
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        # Tests for createmultisig and addmultisigaddress
        assert_raises_rpc_error(-5, "Invalid public key",
                                self.nodes[0].createmultisig, 1, ["01020304"])
        # createmultisig can only take public keys
        self.nodes[0].createmultisig(2,
                                     [addr1Obj['pubkey'], addr2Obj['pubkey']])
        # addmultisigaddress can take both pubkeys and addresses so long as
        # they are in the wallet, which is tested here.
        assert_raises_rpc_error(-5, "Invalid public key",
                                self.nodes[0].createmultisig, 2,
                                [addr1Obj['pubkey'], addr1])

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr1])['address']

        # use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 BCH to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        # node2 has both keys of the 2of2 ms addr., tx should affect the
        # balance
        assert_equal(self.nodes[2].getbalance(), bal + Decimal('1.20000000'))

        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)
        addr3Obj = self.nodes[2].getaddressinfo(addr3)

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']
                ])['address']

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # THIS IS AN INCOMPLETE FEATURE
        # NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND
        # COUNT AT BALANCE CALCULATION
        # for now, assume the funds of a 2of3 multisig tx are not marked as
        # spendable
        assert_equal(self.nodes[2].getbalance(), bal)

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('2.20000000'))

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "amount": vout['value'],
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(
            rawTx, inputs)
        # node1 only has one key, can't comp. sign the tx
        assert_equal(rawTxPartialSigned['complete'], False)

        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx, inputs)
        # node2 can sign the tx compl., own two of three keys
        assert_equal(rawTxSigned['complete'], True)
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  # block reward + tx

        rawTxBlock = self.nodes[0].getblock(self.nodes[0].getbestblockhash())

        # 2of2 test for combining transactions
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[1].getaddressinfo(addr1)
        addr2Obj = self.nodes[2].getaddressinfo(addr2)

        self.nodes[1].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']
        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # the funds of a 2of2 multisig tx should not be marked as spendable
        assert_equal(self.nodes[2].getbalance(), bal)

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = next(o for o in rawTx2['vout']
                    if o['value'] == Decimal('2.20000000'))

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "redeemScript": mSigObjValid['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.19}
        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned1)
        # node1 only has one key, can't comp. sign the tx
        assert_equal(rawTxPartialSigned1['complete'], False)

        rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(
            rawTx2, inputs)
        self.log.debug(rawTxPartialSigned2)
        # node2 only has one key, can't comp. sign the tx
        assert_equal(rawTxPartialSigned2['complete'], False)
        rawTxComb = self.nodes[2].combinerawtransaction(
            [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
        self.log.debug(rawTxComb)
        self.nodes[2].sendrawtransaction(rawTxComb)
        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') +
                     Decimal('2.19000000'))  # block reward + tx

        # getrawtransaction tests
        # 1. valid parameters - only supply txid
        txHash = rawTx["hash"]
        assert_equal(self.nodes[0].getrawtransaction(txHash),
                     rawTxSigned['hex'])

        # 2. valid parameters - supply txid and 0 for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, 0),
                     rawTxSigned['hex'])

        # 3. valid parameters - supply txid and False for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, False),
                     rawTxSigned['hex'])

        # 4. valid parameters - supply txid and 1 for verbose.
        # We only check the "hex" field of the output so we don't need to
        # update this test every time the output format changes.
        assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"],
                     rawTxSigned['hex'])

        # 5. valid parameters - supply txid and True for non-verbose
        assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"],
                     rawTxSigned['hex'])

        # 6. invalid parameters - supply txid and string "Flase"
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash,
                                "False")

        # 7. invalid parameters - supply txid and empty array
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, [])

        # 8. invalid parameters - supply txid and empty dict
        assert_raises_rpc_error(-1, "not a boolean",
                                self.nodes[0].getrawtransaction, txHash, {})

        # Sanity checks on verbose getrawtransaction output
        rawTxOutput = self.nodes[0].getrawtransaction(txHash, True)
        assert_equal(rawTxOutput["hex"], rawTxSigned["hex"])
        assert_equal(rawTxOutput["txid"], txHash)
        assert_equal(rawTxOutput["hash"], txHash)
        assert_greater_than(rawTxOutput["size"], 300)
        assert_equal(rawTxOutput["version"], 0x02)
        assert_equal(rawTxOutput["locktime"], 0)
        assert_equal(len(rawTxOutput["vin"]), 1)
        assert_equal(len(rawTxOutput["vout"]), 1)
        assert_equal(rawTxOutput["blockhash"], rawTxBlock["hash"])
        assert_equal(rawTxOutput["confirmations"], 3)
        assert_equal(rawTxOutput["time"], rawTxBlock["time"])
        assert_equal(rawTxOutput["blocktime"], rawTxBlock["time"])

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        assert_raises_rpc_error(-8, 'Invalid parameter, missing vout key',
                                self.nodes[0].createrawtransaction, inputs,
                                outputs)

        inputs[0]['vout'] = "1"
        assert_raises_rpc_error(-8, 'Invalid parameter, vout must be a number',
                                self.nodes[0].createrawtransaction, inputs,
                                outputs)

        inputs[0]['vout'] = -1
        assert_raises_rpc_error(-8, 'Invalid parameter, vout must be positive',
                                self.nodes[0].createrawtransaction, inputs,
                                outputs)

        inputs[0]['vout'] = 1
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)

        # 9. invalid parameters - sequence number out of range
        inputs[0]['sequence'] = -1
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        # 10. invalid parameters - sequence number out of range
        inputs[0]['sequence'] = 4294967296
        assert_raises_rpc_error(
            -8, 'Invalid parameter, sequence number is out of range',
            self.nodes[0].createrawtransaction, inputs, outputs)

        inputs[0]['sequence'] = 4294967294
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)

        ####################################
        # TRANSACTION VERSION NUMBER TESTS #
        ####################################

        # Test the minimum transaction version number that fits in a signed
        # 32-bit integer.
        tx = CTransaction()
        tx.nVersion = -0x80000000
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], -0x80000000)

        # Test the maximum transaction version number that fits in a signed
        # 32-bit integer.
        tx = CTransaction()
        tx.nVersion = 0x7fffffff
        rawtx = ToHex(tx)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['version'], 0x7fffffff)

        self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')

        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        rawTx = self.nodes[0].getrawtransaction(txId, True)
        vout = next(o for o in rawTx['vout']
                    if o['value'] == Decimal('1.00000000'))

        self.sync_all()
        inputs = [{"txid": txId, "vout": vout['n']}]
        # 1000 sat fee
        outputs = {self.nodes[0].getnewaddress(): Decimal("0.99999000")}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
        assert_equal(rawTxSigned['complete'], True)
        # 1000 sat fee, ~200 b transaction, fee rate should land around 5 sat/b = 0.00005000 BTC/kB
        # Thus, testmempoolaccept should reject
        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']],
                                                  0.00001000)[0]
        assert_equal(testres['allowed'], False)
        assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
        # and sendrawtransaction should throw
        assert_raises_rpc_error(-26, "absurdly-high-fee",
                                self.nodes[2].sendrawtransaction,
                                rawTxSigned['hex'], 0.00001000)
        # And below calls should both succeed
        testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']],
                                                  maxfeerate='0.00007000')[0]
        assert_equal(testres['allowed'], True)
        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'],
                                         maxfeerate='0.00007000')

        ##########################################
        # Decoding weird scripts in transactions #
        ##########################################

        self.log.info('Decode correctly-formatted but weird transactions')
        tx = CTransaction()
        # empty
        self.nodes[0].decoderawtransaction(ToHex(tx))
        # truncated push
        tx.vin.append(CTxIn(COutPoint(42, 0), b'\x4e\x00\x00'))
        tx.vin.append(CTxIn(COutPoint(42, 0), b'\x4c\x10TRUNC'))
        tx.vout.append(CTxOut(0, b'\x4e\x00\x00'))
        tx.vout.append(CTxOut(0, b'\x4c\x10TRUNC'))
        self.nodes[0].decoderawtransaction(ToHex(tx))
        # giant pushes and long scripts
        tx.vin.append(CTxIn(COutPoint(42, 0),
                            CScript([b'giant push' * 10000])))
        tx.vout.append(CTxOut(0, CScript([b'giant push' * 10000])))
        self.nodes[0].decoderawtransaction(ToHex(tx))

        self.log.info('Refuse garbage after transaction')
        assert_raises_rpc_error(-22, 'TX decode failed',
                                self.nodes[0].decoderawtransaction,
                                ToHex(tx) + '00')
Beispiel #8
0
    def run_test(self):
        self.test_node = self.nodes[0].add_p2p_connection(P2PDataStore())

        self.log.info("Running signed block tests")
        assert_equal(self.nodes[0].getblockcount(), 0)
        genesisblock_hash = int(self.nodes[0].getbestblockhash(), 16)

        # create 1 spendable coinbase
        height = 1
        block_time = int(time())
        block1 = create_block(genesisblock_hash, create_coinbase(height),
                              block_time)
        block1.rehash()
        block1.solve(self.secret)
        self.nodes[0].p2p.send_blocks_and_test([block1],
                                               self.nodes[0],
                                               success=True)
        self.nodes[0].generate(100, self.secret)
        previousblock_hash = int(self.nodes[0].getbestblockhash(), 16)

        # create a test block
        height = 102
        block_time = int(time())
        block = create_block(previousblock_hash, create_coinbase(height),
                             block_time + 100)
        block.rehash()

        block_hex = ToHex(block)
        block_hash = block.getsighash()
        previousblock_hash = int(self.nodes[0].getbestblockhash(), 16)

        self.log.info("Test block : %s" % bytes_to_hex_str(block_hash))

        self.log.info("Testing RPC testproposedblock with valid block")

        assert_equal(self.nodes[0].testproposedblock(block_hex), True)

        self.log.info("Testing RPC combineblocksigs with 3 valid signatures")
        sig0 = self.cKey[0].sign(block_hash)
        sig1 = self.cKey[1].sign(block_hash)
        sig2 = self.cKey[2].sign(block_hash)

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        if (len(signedBlock["warning"])):
            self.log.warning(
                "%s : signatures:%s [%d, %d, %d]" %
                (signedBlock["warning"], [sig0, sig1, sig2],
                 self.cKey[0].verify(block_hash, sig0), self.cKey[1].verify(
                     block_hash, sig1), self.cKey[2].verify(block_hash, sig2)))

        block.solve(self.secret)
        self.nodes[0].p2p.send_blocks_and_test([block],
                                               self.nodes[0],
                                               success=True)
        # combineblocksigs only returns true when signatures are appended and enough
        # are included to pass validation
        assert_equal(signedBlock["complete"], True)
        assert_equal(signedBlock["warning"], "")
        assert_equal(
            len(signedBlock["hex"]),
            len(block_hex) + len(bytes_to_hex_str(sig0)) +
            len(bytes_to_hex_str(sig1)) + len(bytes_to_hex_str(sig2)) + 6)
        #6 is 2 bytes for 3 length of signatures

        self.log.info("Testing RPC combineblocksigs with 1 invalid signature")
        sig0 = bytearray(sig0)
        sig0[2] = 30

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        assert_equal(signedBlock["complete"], True)  #True as threshold is 1
        assert_equal(
            signedBlock["warning"],
            "invalid encoding in signature: Non-canonical DER signature %s One or more signatures were not added to block"
            % (bytes_to_hex_str(sig0)))
        assert_equal(
            len(signedBlock["hex"]),
            len(block_hex) + len(bytes_to_hex_str(sig1)) +
            len(bytes_to_hex_str(sig2)) + 4)

        self.log.info("Testing RPC combineblocksigs with 2 invalid signatures")
        sig1 = bytearray(sig1)
        sig1[2] = 30

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        assert_equal(signedBlock["complete"], True)  #True as threshold is 1
        assert_equal(len(signedBlock["hex"]),
                     len(block_hex) + len(bytes_to_hex_str(sig2)) + 2)

        self.log.info("Testing RPC combineblocksigs with 3 invalid signatures")
        sig2 = bytearray(sig2)
        sig2[2] = 30

        signedBlock = self.nodes[0].combineblocksigs(block_hex, [
            bytes_to_hex_str(sig0),
            bytes_to_hex_str(sig1),
            bytes_to_hex_str(sig2)
        ])

        assert_equal(signedBlock["complete"], False)
        assert_equal(len(signedBlock["hex"]), len(block_hex))

        self.log.info("Testing RPC combineblocksigs  with invalid blocks")
        #invalid block hex
        assert_raises_rpc_error(-22, "Block decode failed",
                                self.nodes[0].combineblocksigs, "0000", [])
        #no signature
        assert_raises_rpc_error(-32602, "Signature list was empty",
                                self.nodes[0].combineblocksigs, block_hex, [])
        #too many signature
        assert_raises_rpc_error(
            -32602, "Too many signatures", self.nodes[0].combineblocksigs,
            block_hex,
            ["00", "00", "00", "00", "00", "00", "00", "00", "00", "00"])

        self.log.info("Testing RPC testproposedblock with old block")
        #invalid block hex
        assert_raises_rpc_error(-22, "Block decode failed",
                                self.nodes[0].testproposedblock, "0000")
        # create invalid block
        height = 103
        invalid_block = create_block(previousblock_hash,
                                     create_coinbase(height), block_time + 110)
        invalid_block.solve(self.secret)
        assert_raises_rpc_error(-25,
                                "proposal was not based on our best chain",
                                self.nodes[0].testproposedblock,
                                ToHex(invalid_block))

        self.log.info("Testing RPC testproposedblock with non standard block")
        # create block with non-standard transaction
        previousblock_hash = int(self.nodes[0].getbestblockhash(), 16)
        height = 103
        nonstd_block = create_block(previousblock_hash,
                                    create_coinbase(height), block_time + 120)
        # 3 of 2 multisig is non standard
        nonstd_script = CScript([
            b'53' + self.pubkeys[0] + self.pubkeys[1] + self.pubkeys[2] +
            b'52ea'
        ])
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(block1.vtx[0].malfixsha256, 0), b""))
        tx.vout.append(CTxOut(50, b'0x51'))
        (sig_hash, err) = SignatureHash(nonstd_script, tx, 0, SIGHASH_ALL)
        signature = self.cKey[0].sign(sig_hash) + b'\x01'  # 0x1 is SIGHASH_ALL
        tx.vin[0].scriptSig = CScript([signature, self.pubkeys[0]])
        tx.rehash()
        #add non-standard tx to block
        nonstd_block.vtx.append(tx)
        nonstd_block.solve(self.secret)
        nonstd_block.hashMerkleRoot = nonstd_block.calc_merkle_root()
        nonstd_block.hashImMerkleRoot = nonstd_block.calc_immutable_merkle_root(
        )
        assert (nonstd_block.is_valid())

        #block is accepted when acceptnonstd flag is set
        assert_equal(
            self.nodes[0].testproposedblock(ToHex(nonstd_block), True), True)

        #block is rejected when acceptnonstd flag is not set
        assert_raises_rpc_error(
            -25, "Block proposal included a non-standard transaction",
            self.nodes[0].testproposedblock, ToHex(nonstd_block), False)
    def run_test(self):
        node, = self.nodes

        self.bootstrap_p2p()

        tip = self.get_best_block(node)

        self.log.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(10):
            tip = self.build_block(tip)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node, success=True)
        spendable_outputs = [block.vtx[0] for block in blocks]

        self.log.info("Mature the blocks and get out of IBD.")
        node.generatetoaddress(100, node.get_deterministic_priv_key().address)

        tip = self.get_best_block(node)
        self.log.info("Start pre-upgrade tests")

        # Test pre-upgrade max ancestor limit.
        # We create the full post-fork length chain for use later (+1 to test
        # too long chain)
        ancestors = self.build_ancestor_chain(
            spendable_outputs.pop(0), POSTFORK_MAX_ANCESTORS + 1)
        [node.sendrawtransaction(ToHex(tx))
         for tx in ancestors[:PREFORK_MAX_ANCESTORS]]

        self.log.info(
            "Sending rejected transaction (too many ancestors) via RPC")
        assert_raises_rpc_error(-26,
                                LONG_MEMPOOL_ERROR,
                                node.sendrawtransaction,
                                ToHex(ancestors[PREFORK_MAX_ANCESTORS]))

        self.log.info(
            "Sending rejected transaction (too many ancestors) via net")
        self.check_for_no_ban_on_rejected_tx(
            ancestors[PREFORK_MAX_ANCESTORS], LONG_MEMPOOL_ERROR)

        # Test pre-upgrade max descendants limit
        # We create the full post-fork length chain for use later (+1 to test
        # too long chain)
        descendants = self.build_descendants_chain(
            spendable_outputs.pop(0), POSTFORK_MAX_DESCENDANTS + 1)
        [node.sendrawtransaction(ToHex(tx))
         for tx in descendants[:PREFORK_MAX_DESCENDANTS]]

        self.log.info(
            "Sending rejected transaction (too many descendants) via RPC")
        assert_raises_rpc_error(-26,
                                LONG_MEMPOOL_ERROR,
                                node.sendrawtransaction,
                                ToHex(descendants[PREFORK_MAX_DESCENDANTS]))

        self.log.info(
            "Sending rejected transaction (too many descendants) via net")
        self.check_for_no_ban_on_rejected_tx(
            descendants[PREFORK_MAX_DESCENDANTS], LONG_MEMPOOL_ERROR)

        self.log.info("Start activation tests")

        self.log.info("Approach to just before upgrade activation")
        # Move our clock to the upgrade time so we will accept such
        # future-timestamped blocks.
        node.setmocktime(PHONON_START_TIME)

        # Mine six blocks with timestamp starting at PHONON_START_TIME-1
        blocks = []
        for i in range(-1, 5):
            tip = self.build_block(tip, n_time=PHONON_START_TIME + i)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node)

        # Ensure our MTP is PHONON_START_TIME-1, just before activation
        assert_equal(node.getblockchaininfo()['mediantime'],
                     PHONON_START_TIME - 1)

        self.log.info(
            "The next block will activate, but at the activation block itself must follow old rules")

        self.check_for_no_ban_on_rejected_tx(
            ancestors[PREFORK_MAX_ANCESTORS], LONG_MEMPOOL_ERROR)
        self.check_for_no_ban_on_rejected_tx(
            descendants[PREFORK_MAX_DESCENDANTS], LONG_MEMPOOL_ERROR)

        # Save pre-upgrade block, we will reorg based on this block later
        pre_upgrade_block = tip

        self.log.info("Mine the activation block itself")
        tip = self.build_block(tip, [])
        node.p2p.send_blocks_and_test([tip], node)

        self.log.info("We have activated!")
        # Ensure our MTP is PHONON_START_TIME, exactly at activation
        assert_equal(node.getblockchaininfo()['mediantime'], PHONON_START_TIME)

        # Test post-upgrade max ancestor limit
        [node.sendrawtransaction(
            ToHex(tx)) for tx in ancestors[PREFORK_MAX_ANCESTORS:POSTFORK_MAX_ANCESTORS]]

        self.log.info(
            "Sending rejected transaction (too many ancestors) via RPC")
        assert_raises_rpc_error(-26,
                                LONG_MEMPOOL_ERROR,
                                node.sendrawtransaction,
                                ToHex(ancestors[-1]))

        self.log.info(
            "Sending rejected transaction (too many ancestors) via net")
        self.check_for_no_ban_on_rejected_tx(ancestors[-1], LONG_MEMPOOL_ERROR)

        # Test post-upgrade max descendants limit
        [node.sendrawtransaction(ToHex(
            tx)) for tx in descendants[PREFORK_MAX_DESCENDANTS:POSTFORK_MAX_DESCENDANTS]]

        self.log.info(
            "Sending rejected transaction (too many descendants) via RPC")
        assert_raises_rpc_error(-26,
                                LONG_MEMPOOL_ERROR,
                                node.sendrawtransaction,
                                ToHex(descendants[-1]))

        self.log.info(
            "Sending rejected transaction (too many descendants) via net")
        self.check_for_no_ban_on_rejected_tx(
            descendants[-1], LONG_MEMPOOL_ERROR)

        self.log.info("Start deactivation tests")

        self.log.info(
            "Invalidating the pre-upgrade blocks trims the mempool back to old policies")
        node.invalidateblock(pre_upgrade_block.hash)

        assert_equal(PREFORK_MAX_ANCESTORS +
                     PREFORK_MAX_DESCENDANTS, len(node.getrawmempool()))
        expected = set([tx.hash for tx in ancestors[:PREFORK_MAX_ANCESTORS] +
                        descendants[:PREFORK_MAX_ANCESTORS]])
        assert_equal(set(node.getrawmempool()), expected)
Beispiel #10
0
    def _test_coin_stats_index(self):
        node = self.nodes[0]
        index_node = self.nodes[1]
        # Both none and muhash options allow the usage of the index
        index_hash_options = ['none', 'muhash']

        # Generate a normal transaction and mine it
        node.generate(COINBASE_MATURITY + 1)
        address = self.nodes[0].get_deterministic_priv_key().address
        node.sendtoaddress(address=address,
                           amount=10,
                           subtractfeefromamount=True)
        node.generate(1)

        self.sync_blocks(timeout=120)

        self.log.info(
            "Test that gettxoutsetinfo() output is consistent with or without coinstatsindex option"
        )
        self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set",
                                            node.gettxoutsetinfo))
        res0 = node.gettxoutsetinfo('none')

        # The fields 'disk_size' and 'transactions' do not exist on the index
        del res0['disk_size'], res0['transactions']

        self.wait_until(
            lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.
                                gettxoutsetinfo, 'muhash'))
        for hash_option in index_hash_options:
            res1 = index_node.gettxoutsetinfo(hash_option)
            # The fields 'block_info' and 'total_unspendable_amount' only exist on the index
            del res1['block_info'], res1['total_unspendable_amount']
            res1.pop('muhash', None)

            # Everything left should be the same
            assert_equal(res1, res0)

        self.log.info(
            "Test that gettxoutsetinfo() can get fetch data on specific heights with index"
        )

        # Generate a new tip
        node.generate(5)

        self.wait_until(
            lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.
                                gettxoutsetinfo, 'muhash'))
        for hash_option in index_hash_options:
            # Fetch old stats by height
            res2 = index_node.gettxoutsetinfo(hash_option, 102)
            del res2['block_info'], res2['total_unspendable_amount']
            res2.pop('muhash', None)
            assert_equal(res0, res2)

            # Fetch old stats by hash
            res3 = index_node.gettxoutsetinfo(hash_option, res0['bestblock'])
            del res3['block_info'], res3['total_unspendable_amount']
            res3.pop('muhash', None)
            assert_equal(res0, res3)

            # It does not work without coinstatsindex
            assert_raises_rpc_error(
                -8, "Querying specific block heights requires coinstatsindex",
                node.gettxoutsetinfo, hash_option, 102)

        self.log.info("Test gettxoutsetinfo() with index and verbose flag")

        for hash_option in index_hash_options:
            # Genesis block is unspendable
            res4 = index_node.gettxoutsetinfo(hash_option, 0)
            assert_equal(res4['total_unspendable_amount'], 50)
            assert_equal(
                res4['block_info'], {
                    'unspendable': 50,
                    'prevout_spent': 0,
                    'new_outputs_ex_coinbase': 0,
                    'coinbase': 0,
                    'unspendables': {
                        'genesis_block': 50,
                        'bip30': 0,
                        'scripts': 0,
                        'unclaimed_rewards': 0
                    }
                })
            self.block_sanity_check(res4['block_info'])

            # Test an older block height that included a normal tx
            res5 = index_node.gettxoutsetinfo(hash_option, 102)
            assert_equal(res5['total_unspendable_amount'], 50)
            assert_equal(
                res5['block_info'], {
                    'unspendable': 0,
                    'prevout_spent': 50,
                    'new_outputs_ex_coinbase': Decimal('49.99995560'),
                    'coinbase': Decimal('50.00004440'),
                    'unspendables': {
                        'genesis_block': 0,
                        'bip30': 0,
                        'scripts': 0,
                        'unclaimed_rewards': 0
                    }
                })
            self.block_sanity_check(res5['block_info'])

        # Generate and send a normal tx with two outputs
        tx1_inputs = []
        tx1_outputs = {
            self.nodes[0].getnewaddress(): 21,
            self.nodes[0].getnewaddress(): 42
        }
        raw_tx1 = self.nodes[0].createrawtransaction(tx1_inputs, tx1_outputs)
        funded_tx1 = self.nodes[0].fundrawtransaction(raw_tx1)
        signed_tx1 = self.nodes[0].signrawtransactionwithwallet(
            funded_tx1['hex'])
        tx1_txid = self.nodes[0].sendrawtransaction(signed_tx1['hex'])

        # Find the right position of the 21 BTC output
        tx1_final = self.nodes[0].gettransaction(tx1_txid)
        for output in tx1_final['details']:
            if output['amount'] == Decimal(
                    '21.00000000') and output['category'] == 'receive':
                n = output['vout']

        # Generate and send another tx with an OP_RETURN output (which is unspendable)
        tx2 = CTransaction()
        tx2.vin.append(CTxIn(COutPoint(int(tx1_txid, 16), n), b''))
        tx2.vout.append(
            CTxOut(int(20.99 * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30)))
        tx2_hex = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))['hex']
        self.nodes[0].sendrawtransaction(tx2_hex)

        # Include both txs in a block
        self.nodes[0].generate(1)
        self.sync_all()

        self.wait_until(
            lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.
                                gettxoutsetinfo, 'muhash'))
        for hash_option in index_hash_options:
            # Check all amounts were registered correctly
            res6 = index_node.gettxoutsetinfo(hash_option, 108)
            assert_equal(res6['total_unspendable_amount'],
                         Decimal('70.98999999'))
            assert_equal(
                res6['block_info'], {
                    'unspendable': Decimal('20.98999999'),
                    'prevout_spent': 111,
                    'new_outputs_ex_coinbase': Decimal('89.99993620'),
                    'coinbase': Decimal('50.01006381'),
                    'unspendables': {
                        'genesis_block': 0,
                        'bip30': 0,
                        'scripts': Decimal('20.98999999'),
                        'unclaimed_rewards': 0
                    }
                })
            self.block_sanity_check(res6['block_info'])

        # Create a coinbase that does not claim full subsidy and also
        # has two outputs
        cb = create_coinbase(109, nValue=35)
        cb.vout.append(CTxOut(5 * COIN, CScript([OP_FALSE])))
        cb.rehash()

        # Generate a block that includes previous coinbase
        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblock(tip)['time'] + 1
        block = create_block(int(tip, 16), cb, block_time)
        block.solve()
        self.nodes[0].submitblock(ToHex(block))
        self.sync_all()

        self.wait_until(
            lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.
                                gettxoutsetinfo, 'muhash'))
        for hash_option in index_hash_options:
            res7 = index_node.gettxoutsetinfo(hash_option, 109)
            assert_equal(res7['total_unspendable_amount'],
                         Decimal('80.98999999'))
            assert_equal(
                res7['block_info'], {
                    'unspendable': 10,
                    'prevout_spent': 0,
                    'new_outputs_ex_coinbase': 0,
                    'coinbase': 40,
                    'unspendables': {
                        'genesis_block': 0,
                        'bip30': 0,
                        'scripts': 0,
                        'unclaimed_rewards': 10
                    }
                })
            self.block_sanity_check(res7['block_info'])

        self.log.info("Test that the index is robust across restarts")

        res8 = index_node.gettxoutsetinfo('muhash')
        self.restart_node(1, extra_args=self.extra_args[1])
        res9 = index_node.gettxoutsetinfo('muhash')
        assert_equal(res8, res9)

        index_node.generate(1)
        self.wait_until(
            lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.
                                gettxoutsetinfo, 'muhash'))
        res10 = index_node.gettxoutsetinfo('muhash')
        assert (res8['txouts'] < res10['txouts'])
    def run_test(self):
        node, = self.nodes

        self.nodes[0].add_p2p_connection(P2PDataStore())

        tip = self.getbestblock(node)

        self.log.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(10):
            tip = self.build_block(tip)
            blocks.append(tip)
        node.p2ps[0].send_blocks_and_test(blocks, node, success=True)
        spendable_outputs = [block.vtx[0] for block in blocks]

        self.log.info("Mature the blocks and get out of IBD.")
        node.generatetoaddress(100, node.get_deterministic_priv_key().address)

        tip = self.getbestblock(node)

        self.log.info("Setting up spends to test and mining the fundings.")
        fundings = []

        # Generate a key pair
        private_key = ECKey()
        private_key.set(b"Schnorr!" * 4, True)
        # get uncompressed public key serialization
        public_key = private_key.get_pubkey().get_bytes()

        def create_fund_and_spend_tx(multi=False, sig='schnorr'):
            spendfrom = spendable_outputs.pop()

            if multi:
                script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])
            else:
                script = CScript([public_key, OP_CHECKSIG])

            value = spendfrom.vout[0].nValue

            # Fund transaction
            txfund = create_tx_with_script(spendfrom,
                                           0,
                                           b'',
                                           amount=value,
                                           script_pub_key=script)
            txfund.rehash()
            fundings.append(txfund)

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = SIGHASH_ALL | SIGHASH_FORKID
            hashbyte = bytes([sighashtype & 0xff])
            sighash = SignatureHashForkId(script, txspend, 0, sighashtype,
                                          value)
            if sig == 'schnorr':
                txsig = private_key.sign_schnorr(sighash) + hashbyte
            elif sig == 'ecdsa':
                txsig = private_key.sign_ecdsa(sighash) + hashbyte
            elif isinstance(sig, bytes):
                txsig = sig + hashbyte
            if multi:
                txspend.vin[0].scriptSig = CScript([b'', txsig])
            else:
                txspend.vin[0].scriptSig = CScript([txsig])
            txspend.rehash()

            return txspend

        schnorrchecksigtx = create_fund_and_spend_tx()
        schnorrmultisigtx = create_fund_and_spend_tx(multi=True)
        ecdsachecksigtx = create_fund_and_spend_tx(sig='ecdsa')
        sig64checksigtx = create_fund_and_spend_tx(sig=sig64)
        sig64multisigtx = create_fund_and_spend_tx(multi=True, sig=sig64)

        tip = self.build_block(tip, fundings)
        node.p2ps[0].send_blocks_and_test([tip], node)

        self.log.info("Typical ECDSA and Schnorr CHECKSIG are valid.")
        node.p2ps[0].send_txs_and_test([schnorrchecksigtx, ecdsachecksigtx],
                                       node)
        # They get mined as usual.
        node.generatetoaddress(1, node.get_deterministic_priv_key().address)
        tip = self.getbestblock(node)
        # Make sure they are in the block, and mempool is now empty.
        txhashes = set([schnorrchecksigtx.hash, ecdsachecksigtx.hash])
        assert txhashes.issubset(tx.rehash() for tx in tip.vtx)
        assert not node.getrawmempool()

        self.log.info("Schnorr in multisig is rejected with mandatory error.")
        assert_raises_rpc_error(-26, SCHNORR_MULTISIG_ERROR,
                                node.sendrawtransaction,
                                ToHex(schnorrmultisigtx))
        # And it is banworthy.
        self.check_for_ban_on_rejected_tx(schnorrmultisigtx,
                                          SCHNORR_MULTISIG_ERROR)
        # And it can't be mined
        self.check_for_ban_on_rejected_block(
            self.build_block(tip, [schnorrmultisigtx]), BADINPUTS_ERROR)

        self.log.info("Bad 64-byte sig is rejected with mandatory error.")
        # In CHECKSIG it's invalid Schnorr and hence NULLFAIL.
        assert_raises_rpc_error(-26, NULLFAIL_ERROR, node.sendrawtransaction,
                                ToHex(sig64checksigtx))
        # In CHECKMULTISIG it's invalid length and hence BAD_LENGTH.
        assert_raises_rpc_error(-26, SCHNORR_MULTISIG_ERROR,
                                node.sendrawtransaction,
                                ToHex(sig64multisigtx))
        # Sending these transactions is banworthy.
        self.check_for_ban_on_rejected_tx(sig64checksigtx, NULLFAIL_ERROR)
        self.check_for_ban_on_rejected_tx(sig64multisigtx,
                                          SCHNORR_MULTISIG_ERROR)
        # And they can't be mined either...
        self.check_for_ban_on_rejected_block(
            self.build_block(tip, [sig64checksigtx]), BADINPUTS_ERROR)
        self.check_for_ban_on_rejected_block(
            self.build_block(tip, [sig64multisigtx]), BADINPUTS_ERROR)
    def run_test(self):
        (node, std_node) = self.nodes
        node.add_p2p_connection(P2PDataStore())
        std_node.add_p2p_connection(P2PDataStore())
        # Get out of IBD
        node.generatetoaddress(1, node.get_deterministic_priv_key().address)

        tip = self.getbestblock(node)

        self.log.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(20):
            tip = self.build_block(tip)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node, success=True)
        self.spendable_outputs = deque(block.vtx[0] for block in blocks)

        self.log.info("Mature the blocks.")
        node.generatetoaddress(100, node.get_deterministic_priv_key().address)

        tip = self.getbestblock(node)

        self.log.info("Generating some high-sigop transactions.")

        # Tx with 4001 sigops (valid but non standard)
        tx_4001 = create_transaction(self.spendable_outputs.popleft(), [
                                     OP_CHECKMULTISIG] * 200 + [OP_CHECKDATASIG])

        # Tx with 20001 sigops (consensus-invalid)
        tx_20001 = create_transaction(self.spendable_outputs.popleft(), [
                                      OP_CHECKMULTISIG] * 1000 + [OP_CHECKDATASIG])

        # P2SH tx with too many sigops (valid but nonstandard for std_node)
        redeem_script = bytes(
            [OP_IF, OP_CHECKMULTISIG, OP_ENDIF, OP_TRUE])
        p2sh_script = CScript([OP_HASH160, hash160(redeem_script), OP_EQUAL])
        tx_fundp2sh = create_transaction(
            self.spendable_outputs.popleft(), p2sh_script)
        tx_spendp2sh = CTransaction()
        tx_spendp2sh.vin.append(
            CTxIn(COutPoint(tx_fundp2sh.sha256, 1), CScript([OP_FALSE, redeem_script])))
        tx_spendp2sh.vout.append(
            CTxOut(0, CScript([OP_RETURN, b'pad' * 20])))
        tx_spendp2sh.rehash()

        # Chain of 10 txes with 2000 sigops each.
        txes_10x2000_sigops = []
        tx = self.spendable_outputs.popleft()
        for _ in range(10):
            tx = create_transaction(tx, [OP_CHECKMULTISIG] * 100)
            txes_10x2000_sigops.append(tx)

        def make_hightotalsigop_block():
            # 20001 total sigops
            return self.build_block(
                tip, txes_10x2000_sigops, cbextrascript=bytes([OP_CHECKDATASIG]))

        def make_highsigop_coinbase_block():
            # 60000 sigops in the coinbase
            return self.build_block(
                tip, cbextrascript=bytes([OP_CHECKMULTISIG] * 3000))

        self.log.info(
            "Try various high-sigop transactions in blocks / mempool before upgrade")

        # mempool refuses over 4001.
        check_for_no_ban_on_rejected_tx(node, tx_4001, MEMPOOL_TXSIGOPS_ERROR)
        # it used to be that exceeding 20000 would cause a ban, but it's
        # important that this causes no ban: we want that upgraded nodes
        # can't get themselves banned by relaying huge-sigops transactions.
        check_for_no_ban_on_rejected_tx(node, tx_20001, MEMPOOL_TXSIGOPS_ERROR)

        # the 20001 tx can't be mined
        check_for_ban_on_rejected_block(node, self.build_block(
            tip, [tx_20001]), BLOCK_TXSIGOPS_ERROR)

        self.log.info(
            "The P2SH script has too many sigops (20 > 15) for a standard node.")
        # Mine the P2SH funding first because it's nonstandard.
        tip = self.build_block(tip, [tx_fundp2sh])
        std_node.p2p.send_blocks_and_test([tip], node)
        assert_raises_rpc_error(-26, MEMPOOL_P2SH_SIGOPS_ERROR,
                                std_node.sendrawtransaction, ToHex(tx_spendp2sh))

        self.log.info(
            "A bunch of 2000-sigops txes can be put in mempool but not mined all at once.")
        # Send the 2000-sigop transactions, which are acceptable.
        for tx in txes_10x2000_sigops:
            node.sendrawtransaction(ToHex(tx))

        # They can't be mined all at once if the coinbase has a single sigop
        # (total 20001)
        check_for_ban_on_rejected_block(
            node, make_hightotalsigop_block(), BLOCK_TOTALSIGOPS_ERROR)

        # Activation tests

        self.log.info("Approach to just before upgrade activation")
        # Move our clock to the uprade time so we will accept such
        # future-timestamped blocks.
        node.setmocktime(SIGOPS_DEACTIVATION_TIME)
        std_node.setmocktime(SIGOPS_DEACTIVATION_TIME)
        # Mine six blocks with timestamp starting at SIGOPS_DEACTIVATION_TIME-1
        blocks = []
        for i in range(-1, 5):
            tip = self.build_block(tip, nTime=SIGOPS_DEACTIVATION_TIME + i)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node)
        assert_equal(node.getblockchaininfo()[
                     'mediantime'], SIGOPS_DEACTIVATION_TIME - 1)

        self.log.info(
            "The next block will activate, but the activation block itself must follow old rules")

        check_for_ban_on_rejected_block(node, self.build_block(
            tip, [tx_20001]), BLOCK_TXSIGOPS_ERROR)
        check_for_ban_on_rejected_block(
            node, make_hightotalsigop_block(), BLOCK_TOTALSIGOPS_ERROR)
        check_for_ban_on_rejected_block(
            node, make_highsigop_coinbase_block(), BLOCK_TXSIGOPS_ERROR)

        self.log.info("Mine the activation block itself")
        tip = self.build_block(tip)
        node.p2p.send_blocks_and_test([tip], node)
        sync_blocks(self.nodes)

        self.log.info("We have activated!")
        assert_equal(node.getblockchaininfo()[
                     'mediantime'], SIGOPS_DEACTIVATION_TIME)
        assert_equal(std_node.getblockchaininfo()[
                     'mediantime'], SIGOPS_DEACTIVATION_TIME)

        # save this tip for later
        upgrade_block = tip

        self.log.info(
            "The mempool is now a free-for-all, and we can get all the high-sigops transactions in")
        std_node.sendrawtransaction(ToHex(tx_spendp2sh))
        node.sendrawtransaction(ToHex(tx_spendp2sh))
        node.sendrawtransaction(ToHex(tx_4001))
        node.sendrawtransaction(ToHex(tx_20001))
        # resend the 2000-sigop transactions, which will have expired due to
        # setmocktime.
        for tx in txes_10x2000_sigops:
            node.sendrawtransaction(ToHex(tx))

        alltxes = set(tx.hash for tx in [
                      tx_spendp2sh, tx_4001, tx_20001] + txes_10x2000_sigops)
        assert_equal(set(node.getrawmempool()), alltxes)

        self.log.info(
            "The miner will include all the high-sigops transactions at once, without issue.")
        node.generatetoaddress(1, node.get_deterministic_priv_key().address)
        tip = self.getbestblock(node)
        assert_equal(set(tx.rehash() for tx in tip.vtx[1:]), alltxes)
        # even though it is far smaller than one megabyte, we got in something
        # like 44000 sigops
        assert len(tip.serialize()) < ONE_MEGABYTE

        # save this tip for later
        postupgrade_block = tip

        # Deactivation tests

        self.log.info(
            "Invalidating the post-upgrade block returns the transactions to mempool")
        node.invalidateblock(postupgrade_block.hash)
        assert_equal(set(node.getrawmempool()), alltxes)

        self.log.info("Test some weird alternative blocks")
        tip = upgrade_block
        self.log.info("A 40000-sigop coinbase is acceptable now")
        tip = make_highsigop_coinbase_block()
        node.p2p.send_blocks_and_test([tip], node)
        self.log.info("We can get in our 20001 sigop total block")
        tip = make_hightotalsigop_block()
        node.p2p.send_blocks_and_test([tip], node)

        self.log.info(
            "Invalidating the upgrade block evicts the bad txes")
        goodtxes = alltxes - {tx_4001.hash, tx_20001.hash}
        # loose-rules node just evicts the too-many-sigops transactions
        node.invalidateblock(upgrade_block.hash)
        assert_equal(set(node.getrawmempool()), goodtxes)
        # std_node evicts everything as either nonstandard scriptpubkey or p2sh
        # too-many-sigops.
        std_node.invalidateblock(upgrade_block.hash)
        assert_equal(std_node.getrawmempool(), [])
    def run_test(self):
        (node, ) = self.nodes
        node.add_p2p_connection(P2PDataStore())
        # Get out of IBD
        node.generatetoaddress(1, node.get_deterministic_priv_key().address)

        tip = self.getbestblock(node)

        self.log.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(20):
            tip = self.build_block(tip)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node)
        self.spendable_outputs = deque(block.vtx[0] for block in blocks)

        self.log.info("Mature the blocks.")
        node.generatetoaddress(100, node.get_deterministic_priv_key().address)

        tip = self.getbestblock(node)

        # To make compact and fast-to-verify transactions, we'll use
        # CHECKDATASIG over and over with the same data.
        # (Using the same stuff over and over again means we get to hit the
        # node's signature cache and don't need to make new signatures every
        # time.)
        cds_message = b''
        # r=1 and s=1 ecdsa, the minimum values.
        cds_signature = bytes.fromhex('3006020101020101')
        # Recovered pubkey
        cds_pubkey = bytes.fromhex(
            '03089b476b570d66fad5a20ae6188ebbaf793a4c2a228c65f3d79ee8111d56c932'
        )

        fundings = []

        def make_spend(scriptpubkey, scriptsig):
            # Add a funding tx to fundings, and return a tx spending that using
            # scriptsig.
            self.log.debug(
                "Gen tx with locking script {} unlocking script {} .".format(
                    scriptpubkey.hex(), scriptsig.hex()))

            # get funds locked with OP_1
            sourcetx = self.spendable_outputs.popleft()
            # make funding that forwards to scriptpubkey
            fundtx = create_transaction(sourcetx, scriptpubkey)
            fundings.append(fundtx)

            # make the spending
            tx = CTransaction()
            tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig))
            tx.vout.append(CTxOut(0, CScript([OP_RETURN])))
            pad_tx(tx)
            tx.rehash()
            return tx

        self.log.info("Generating txes used in this test")

        # "Good" txns that pass our rule:

        goodtxes = [
            # most dense allowed input -- 2 sigchecks with a 26-byte scriptsig.
            make_spend(
                CScript([
                    cds_message, cds_pubkey, OP_3DUP, OP_CHECKDATASIGVERIFY,
                    OP_CHECKDATASIGVERIFY
                ]), CScript([b'x' * 16, cds_signature])),

            # 4 sigchecks with a 112-byte scriptsig, just at the limit for this
            # sigchecks count.
            make_spend(
                CScript([
                    cds_message, cds_pubkey, OP_3DUP, OP_CHECKDATASIGVERIFY,
                    OP_3DUP, OP_CHECKDATASIGVERIFY, OP_3DUP,
                    OP_CHECKDATASIGVERIFY, OP_CHECKDATASIGVERIFY
                ]), CScript([b'x' * 101, cds_signature])),

            # "nice" transaction - 1 sigcheck with 9-byte scriptsig.
            make_spend(CScript([cds_message, cds_pubkey, OP_CHECKDATASIG]),
                       CScript([cds_signature])),

            # 1 sigcheck with 0-byte scriptsig.
            make_spend(
                CScript(
                    [cds_signature, cds_message, cds_pubkey, OP_CHECKDATASIG]),
                CScript([])),
        ]

        badtxes = [
            # "Bad" txns:
            # 2 sigchecks with a 25-byte scriptsig, just 1 byte too short.
            make_spend(
                CScript([
                    cds_message, cds_pubkey, OP_3DUP, OP_CHECKDATASIGVERIFY,
                    OP_CHECKDATASIGVERIFY
                ]), CScript([b'x' * 15, cds_signature])),

            # 4 sigchecks with a 111-byte scriptsig, just 1 byte too short.
            make_spend(
                CScript([
                    cds_message, cds_pubkey, OP_3DUP, OP_CHECKDATASIGVERIFY,
                    OP_3DUP, OP_CHECKDATASIGVERIFY, OP_3DUP,
                    OP_CHECKDATASIGVERIFY, OP_CHECKDATASIGVERIFY
                ]), CScript([b'x' * 100, cds_signature])),
        ]

        goodtxids = set(t.hash for t in goodtxes)
        badtxids = set(t.hash for t in badtxes)

        self.log.info("Funding the txes")
        tip = self.build_block(tip, fundings)
        node.p2p.send_blocks_and_test([tip], node)

        # Activation tests

        self.log.info("Approach to just before upgrade activation")
        # Move our clock to the uprade time so we will accept such
        # future-timestamped blocks.
        node.setmocktime(SIGCHECKS_ACTIVATION_TIME + 10)
        # Mine six blocks with timestamp starting at
        # SIGCHECKS_ACTIVATION_TIME-1
        blocks = []
        for i in range(-1, 5):
            tip = self.build_block(tip, nTime=SIGCHECKS_ACTIVATION_TIME + i)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node)
        assert_equal(node.getblockchaininfo()['mediantime'],
                     SIGCHECKS_ACTIVATION_TIME - 1)

        self.log.info(
            "The next block will activate, but the activation block itself must follow old rules"
        )

        self.log.info("Send all the transactions just before upgrade")

        node.p2p.send_txs_and_test(goodtxes, node)
        node.p2p.send_txs_and_test(badtxes, node)

        assert_equal(set(node.getrawmempool()), goodtxids | badtxids)

        # ask the node to mine a block, it should include the bad txes.
        [blockhash
         ] = node.generatetoaddress(1,
                                    node.get_deterministic_priv_key().address)
        assert_equal(set(node.getblock(blockhash, 1)['tx'][1:]),
                     goodtxids | badtxids)
        assert_equal(node.getrawmempool(), [])

        # discard that block
        node.invalidateblock(blockhash)
        assert_equal(set(node.getrawmempool()), goodtxids | badtxids)

        self.log.info("Mine the activation block itself")
        tip = self.build_block(tip)
        node.p2p.send_blocks_and_test([tip], node)

        self.log.info("We have activated!")
        assert_equal(node.getblockchaininfo()['mediantime'],
                     SIGCHECKS_ACTIVATION_TIME)

        self.log.info(
            "The high-sigchecks transactions got evicted but the good ones are still around"
        )
        assert_equal(set(node.getrawmempool()), goodtxids)

        self.log.info(
            "Now the high-sigchecks transactions are rejected from mempool.")
        # try sending some of the bad txes again after the upgrade
        for tx in badtxes:
            check_for_no_ban_on_rejected_tx(node, tx, TX_INPUT_SIGCHECKS_ERROR)
            assert_raises_rpc_error(-26, TX_INPUT_SIGCHECKS_ERROR,
                                    node.sendrawtransaction, ToHex(tx))

        self.log.info("But they can still be mined!")

        # now make a block with all the txes, they still are accepted in
        # blocks!
        tip = self.build_block(tip, goodtxes + badtxes)
        node.p2p.send_blocks_and_test([tip], node)

        assert_equal(node.getbestblockhash(), tip.hash)
    def get_tests(self):
        self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        spendable_outputs = []

        # save the current tip so it can be spent by a later block
        def save_spendable_output():
            spendable_outputs.append(self.tip)

        # get an output that we previously marked as spendable
        def get_spendable_output():
            return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0)

        # returns a test case that asserts that the current tip was accepted
        def accepted():
            return TestInstance([[self.tip, True]])

        # returns a test case that asserts that the current tip was rejected
        def rejected(reject=None):
            if reject is None:
                return TestInstance([[self.tip, False]])
            else:
                return TestInstance([[self.tip, reject]])

        # move the tip back to a previous block
        def tip(number):
            self.tip = self.blocks[number]

        # adds transactions to the block and updates state
        def update_block(block_number, new_transactions):
            block = self.blocks[block_number]
            self.add_transactions_to_block(block, new_transactions)
            old_sha256 = block.sha256
            block.hashMerkleRoot = block.calc_merkle_root()
            block.solve()
            # Update the internal state just like in next_block
            self.tip = block
            if block.sha256 != old_sha256:
                self.block_heights[
                    block.sha256] = self.block_heights[old_sha256]
                del self.block_heights[old_sha256]
            self.blocks[block_number] = block
            return block

        # shorthand for functions
        block = self.next_block
        create_tx = self.create_tx

        # shorthand for variables
        node = self.nodes[0]

        # Create a new block
        block(0)
        save_spendable_output()
        yield accepted()

        # Now we need that block to mature so we can spend the coinbase.
        test = TestInstance(sync_every_block=False)
        for i in range(99):
            block(5000 + i)
            test.blocks_and_transactions.append([self.tip, True])
            save_spendable_output()
        yield test

        # Collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(33):
            out.append(get_spendable_output())

        # P2SH
        # Build the redeem script, hash it, use hash to create the p2sh script
        redeem_script = CScript([self.coinbase_pubkey] +
                                [OP_2DUP, OP_CHECKSIGVERIFY] * 5 +
                                [OP_CHECKSIG])
        redeem_script_hash = hash160(redeem_script)
        p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL])

        # Creates a new transaction using a p2sh transaction as input
        def spend_p2sh_tx(p2sh_tx_to_spend, output_script=CScript([OP_TRUE])):
            # Create the transaction
            spent_p2sh_tx = CTransaction()
            spent_p2sh_tx.vin.append(
                CTxIn(COutPoint(p2sh_tx_to_spend.sha256, 0), b''))
            spent_p2sh_tx.vout.append(CTxOut(1, output_script))
            # Sign the transaction using the redeem script
            sighash = SignatureHashForkId(redeem_script, spent_p2sh_tx, 0,
                                          SIGHASH_ALL | SIGHASH_FORKID,
                                          p2sh_tx_to_spend.vout[0].nValue)
            sig = self.coinbase_key.sign(sighash) + bytes(
                bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
            spent_p2sh_tx.vin[0].scriptSig = CScript([sig, redeem_script])
            spent_p2sh_tx.rehash()
            return spent_p2sh_tx

        # P2SH tests
        # Create a p2sh transaction
        p2sh_tx = self.create_and_sign_transaction(out[0].tx, out[0].n, 1,
                                                   p2sh_script)

        # Add the transaction to the block
        block(1)
        update_block(1, [p2sh_tx])
        yield accepted()

        # Sigops p2sh limit for the mempool test
        p2sh_sigops_limit_mempool = MAX_STANDARD_TX_SIGOPS - \
            redeem_script.GetSigOpCount(True)
        # Too many sigops in one p2sh script
        too_many_p2sh_sigops_mempool = CScript([OP_CHECKSIG] *
                                               (p2sh_sigops_limit_mempool + 1))

        # A transaction with this output script can't get into the mempool
        assert_raises_rpc_error(
            -26, RPC_TXNS_TOO_MANY_SIGOPS_ERROR, node.sendrawtransaction,
            ToHex(spend_p2sh_tx(p2sh_tx, too_many_p2sh_sigops_mempool)))

        # The transaction is rejected, so the mempool should still be empty
        assert_equal(set(node.getrawmempool()), set())

        # Max sigops in one p2sh txn
        max_p2sh_sigops_mempool = CScript([OP_CHECKSIG] *
                                          (p2sh_sigops_limit_mempool))

        # A transaction with this output script can get into the mempool
        max_p2sh_sigops_txn = spend_p2sh_tx(p2sh_tx, max_p2sh_sigops_mempool)
        max_p2sh_sigops_txn_id = node.sendrawtransaction(
            ToHex(max_p2sh_sigops_txn))
        assert_equal(set(node.getrawmempool()), {max_p2sh_sigops_txn_id})

        # Mine the transaction
        block(2, spend=out[1])
        update_block(2, [max_p2sh_sigops_txn])
        yield accepted()

        # The transaction has been mined, it's not in the mempool anymore
        assert_equal(set(node.getrawmempool()), set())
Beispiel #15
0
    def test_sequence_lock_unconfirmed_inputs(self):
        # Store height so we can easily reset the chain at the end of the test
        cur_height = self.nodes[0].getblockcount()

        # Create a mempool tx.
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
        tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
        tx1.rehash()

        # Anyone-can-spend mempool tx.
        # Sequence lock of 0 should pass.
        tx2 = CTransaction()
        tx2.nVersion = 2
        tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
        tx2.vout = [
            CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN),
                   DUMMY_P2WPKH_SCRIPT)
        ]
        tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
        tx2 = FromHex(tx2, tx2_raw)
        tx2.rehash()

        self.nodes[0].sendrawtransaction(tx2_raw)

        # Create a spend of the 0th output of orig_tx with a sequence lock
        # of 1, and test what happens when submitting.
        # orig_tx.vout[0] must be an anyone-can-spend output
        def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
            sequence_value = 1
            if not use_height_lock:
                sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG

            tx = CTransaction()
            tx.nVersion = 2
            tx.vin = [
                CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)
            ]
            tx.vout = [
                CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN),
                       DUMMY_P2WPKH_SCRIPT)
            ]
            tx.rehash()

            if (orig_tx.hash in node.getrawmempool()):
                # sendrawtransaction should fail if the tx is in the mempool
                assert_raises_rpc_error(-26, NOT_FINAL_ERROR,
                                        node.sendrawtransaction, ToHex(tx))
            else:
                # sendrawtransaction should succeed if the tx is not in the mempool
                node.sendrawtransaction(ToHex(tx))

            return tx

        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=True)
        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=False)

        # Now mine some blocks, but make sure tx2 doesn't get mined.
        # Use prioritisetransaction to lower the effective feerate to 0
        self.nodes[0].prioritisetransaction(txid=tx2.hash,
                                            fee_delta=int(-self.relayfee *
                                                          COIN))
        cur_time = int(time.time())
        for i in range(10):
            self.nodes[0].setmocktime(cur_time + 600)
            self.nodes[0].generate(1)
            cur_time += 600

        assert tx2.hash in self.nodes[0].getrawmempool()

        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=True)
        test_nonzero_locks(tx2,
                           self.nodes[0],
                           self.relayfee,
                           use_height_lock=False)

        # Mine tx2, and then try again
        self.nodes[0].prioritisetransaction(txid=tx2.hash,
                                            fee_delta=int(self.relayfee *
                                                          COIN))

        # Advance the time on the node so that we can test timelocks
        self.nodes[0].setmocktime(cur_time + 600)
        self.nodes[0].generate(1)
        assert tx2.hash not in self.nodes[0].getrawmempool()

        # Now that tx2 is not in the mempool, a sequence locked spend should
        # succeed
        tx3 = test_nonzero_locks(tx2,
                                 self.nodes[0],
                                 self.relayfee,
                                 use_height_lock=False)
        assert tx3.hash in self.nodes[0].getrawmempool()

        self.nodes[0].generate(1)
        assert tx3.hash not in self.nodes[0].getrawmempool()

        # One more test, this time using height locks
        tx4 = test_nonzero_locks(tx3,
                                 self.nodes[0],
                                 self.relayfee,
                                 use_height_lock=True)
        assert tx4.hash in self.nodes[0].getrawmempool()

        # Now try combining confirmed and unconfirmed inputs
        tx5 = test_nonzero_locks(tx4,
                                 self.nodes[0],
                                 self.relayfee,
                                 use_height_lock=True)
        assert tx5.hash not in self.nodes[0].getrawmempool()

        utxos = self.nodes[0].listunspent()
        tx5.vin.append(
            CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]),
                  nSequence=1))
        tx5.vout[0].nValue += int(utxos[0]["amount"] * COIN)
        raw_tx5 = self.nodes[0].signrawtransactionwithwallet(ToHex(tx5))["hex"]

        assert_raises_rpc_error(-26, NOT_FINAL_ERROR,
                                self.nodes[0].sendrawtransaction, raw_tx5)

        # Test mempool-BIP68 consistency after reorg
        #
        # State of the transactions in the last blocks:
        # ... -> [ tx2 ] ->  [ tx3 ]
        #         tip-1        tip
        # And currently tx4 is in the mempool.
        #
        # If we invalidate the tip, tx3 should get added to the mempool, causing
        # tx4 to be removed (fails sequence-lock).
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        assert tx4.hash not in self.nodes[0].getrawmempool()
        assert tx3.hash in self.nodes[0].getrawmempool()

        # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in
        # diagram above).
        # This would cause tx2 to be added back to the mempool, which in turn causes
        # tx3 to be removed.
        tip = int(
            self.nodes[0].getblockhash(self.nodes[0].getblockcount() - 1), 16)
        height = self.nodes[0].getblockcount()
        for i in range(2):
            block = create_block(tip, create_coinbase(height), cur_time)
            block.nVersion = 3
            block.rehash()
            block.solve()
            tip = block.sha256
            height += 1
            self.nodes[0].submitblock(ToHex(block))
            cur_time += 1

        mempool = self.nodes[0].getrawmempool()
        assert tx3.hash not in mempool
        assert tx2.hash in mempool

        # Reset the chain and get rid of the mocktimed-blocks
        self.nodes[0].setmocktime(0)
        self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height +
                                                                 1))
        self.nodes[0].generate(10)
Beispiel #16
0
    def run_test(self):
        node, = self.nodes

        self.bootstrap_p2p()

        tip = self.getbestblock(node)

        self.log.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(10):
            tip = self.build_block(tip)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node, success=True)
        spendable_outputs = [block.vtx[0] for block in blocks]

        self.log.info("Mature the blocks and get out of IBD.")
        node.generate(100)

        tip = self.getbestblock(node)

        self.log.info("Setting up spends to test and mining the fundings.")
        fundings = []

        def create_fund_and_spend_tx():
            spendfrom = spendable_outputs.pop()

            script = CScript([OP_ADD])

            value = spendfrom.vout[0].nValue

            # Fund transaction
            txfund = create_transaction(spendfrom, 0, b'', value, script)
            txfund.rehash()
            fundings.append(txfund)

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            txspend.vin[0].scriptSig = CScript(
                b'\x01\x01\x51')  # PUSH1(0x01) OP_1
            pad_tx(txspend)
            txspend.rehash()

            return txspend

        # make a few of these, which are nonstandard before upgrade and invalid after.
        nonminimaltx = create_fund_and_spend_tx()
        nonminimaltx_2 = create_fund_and_spend_tx()
        nonminimaltx_3 = create_fund_and_spend_tx()

        tip = self.build_block(tip, fundings)
        node.p2p.send_blocks_and_test([tip], node)

        self.log.info("Start preupgrade tests")

        self.log.info("Sending rejected transactions via RPC")
        assert_raises_rpc_error(-26, MINIMALPUSH_ERROR,
                                node.sendrawtransaction, ToHex(nonminimaltx))
        assert_raises_rpc_error(-26, MINIMALPUSH_ERROR,
                                node.sendrawtransaction, ToHex(nonminimaltx_2))
        assert_raises_rpc_error(-26, MINIMALPUSH_ERROR,
                                node.sendrawtransaction, ToHex(nonminimaltx_3))

        self.log.info("Sending rejected transactions via net (banning)")
        self.check_for_ban_on_rejected_tx(nonminimaltx, MINIMALPUSH_ERROR)
        self.check_for_ban_on_rejected_tx(nonminimaltx_2, MINIMALPUSH_ERROR)
        self.check_for_ban_on_rejected_tx(nonminimaltx_3, MINIMALPUSH_ERROR)

        assert_equal(node.getrawmempool(), [])

        self.log.info("Successfully mine nonstandard transaction")
        tip = self.build_block(tip, [nonminimaltx])
        node.p2p.send_blocks_and_test([tip], node)

        # Activation tests

        self.log.info("Approach to just before upgrade activation")
        # Move our clock to the uprade time so we will accept such future-timestamped blocks.
        node.setmocktime(GRAVITON_START_TIME)
        # Mine six blocks with timestamp starting at GRAVITON_START_TIME-1
        blocks = []
        for i in range(-1, 5):
            tip = self.build_block(tip, nTime=GRAVITON_START_TIME + i)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node)
        assert_equal(node.getblockchaininfo()['mediantime'],
                     GRAVITON_START_TIME - 1)

        self.log.info(
            "Mine the activation block itself, including a minimaldata violation at the last possible moment"
        )
        tip = self.build_block(tip, [nonminimaltx_2])
        node.p2p.send_blocks_and_test([tip], node)

        self.log.info("We have activated!")
        assert_equal(node.getblockchaininfo()['mediantime'],
                     GRAVITON_START_TIME)

        self.log.info(
            "Trying to mine a minimaldata violation, but we are just barely too late"
        )
        self.check_for_ban_on_rejected_block(
            self.build_block(tip, [nonminimaltx_3]), BADINPUTS_ERROR)
        self.log.info(
            "If we try to submit it by mempool or RPC we still aren't banned")
        assert_raises_rpc_error(-26, MINIMALPUSH_ERROR,
                                node.sendrawtransaction, ToHex(nonminimaltx_3))
        self.check_for_ban_on_rejected_tx(nonminimaltx_3, MINIMALPUSH_ERROR)

        self.log.info("Mine a normal block")
        tip = self.build_block(tip)
        node.p2p.send_blocks_and_test([tip], node)
Beispiel #17
0
def sign_transaction(node, unsignedtx):
    rawtx = ToHex(unsignedtx)
    signresult = node.signrawtransactionwithwallet(rawtx)
    tx = FromHex(CTransaction(), signresult['hex'])
    return tx
    def run_test(self):
        node = self.nodes[0]
        node.add_p2p_connection(P2PDataStore())

        self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        spendable_outputs = []

        # save the current tip so it can be spent by a later block
        def save_spendable_output():
            spendable_outputs.append(self.tip)

        # get an output that we previously marked as spendable
        def get_spendable_output():
            return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0)

        # move the tip back to a previous block
        def tip(number):
            self.tip = self.blocks[number]

        # adds transactions to the block and updates state
        def update_block(block_number, new_transactions):
            block = self.blocks[block_number]
            self.add_transactions_to_block(block, new_transactions)
            old_sha256 = block.sha256
            block.hashMerkleRoot = block.calc_merkle_root()
            block.solve()
            # Update the internal state just like in next_block
            self.tip = block
            if block.sha256 != old_sha256:
                self.block_heights[
                    block.sha256] = self.block_heights[old_sha256]
                del self.block_heights[old_sha256]
            self.blocks[block_number] = block
            return block

        # shorthand for functions
        block = self.next_block

        # Create a new block
        block(0)
        save_spendable_output()
        node.p2p.send_blocks_and_test([self.tip], node)

        # Now we need that block to mature so we can spend the coinbase.
        maturity_blocks = []
        for i in range(99):
            block(5000 + i)
            maturity_blocks.append(self.tip)
            save_spendable_output()
        node.p2p.send_blocks_and_test(maturity_blocks, node)

        # Collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(33):
            out.append(get_spendable_output())

        # P2SH
        # Build the redeem script, hash it, use hash to create the p2sh script
        # Pad with extra bytes to make sure that the scriptsig length will be
        # >= 198 after signature is added, even if it's a schnorr sig; this
        # ensures a not-too-high density of sigchecks.
        redeem_script = CScript([b'X' * 51, OP_DROP, self.coinbase_pubkey] +
                                [OP_2DUP, OP_CHECKSIGVERIFY] * 5 +
                                [OP_CHECKSIG])
        # should be this length since coinbase_pubkey is uncompressed.
        assert_equal(len(redeem_script), 130)
        redeem_script_hash = hash160(redeem_script)
        p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL])

        # Creates a new transaction using a p2sh transaction as input
        def spend_p2sh_tx(p2sh_tx_to_spend, output_script=CScript([OP_TRUE])):
            # Create the transaction
            spent_p2sh_tx = CTransaction()
            spent_p2sh_tx.vin.append(
                CTxIn(COutPoint(p2sh_tx_to_spend.sha256, 0), b''))
            spent_p2sh_tx.vout.append(CTxOut(1000, output_script))
            # Sign the transaction using the redeem script
            sighash = SignatureHashForkId(redeem_script, spent_p2sh_tx, 0,
                                          SIGHASH_ALL | SIGHASH_FORKID,
                                          p2sh_tx_to_spend.vout[0].nValue)
            sig = self.coinbase_key.sign_ecdsa(sighash) + bytes(
                bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
            spent_p2sh_tx.vin[0].scriptSig = CScript([sig, redeem_script])
            assert len(spent_p2sh_tx.vin[0].scriptSig
                       ) >= 198, "needs to pass input sigchecks limit"
            spent_p2sh_tx.rehash()
            return spent_p2sh_tx

        # P2SH tests
        # Create a p2sh transaction
        p2sh_tx = self.create_and_sign_transaction(out[0].tx, out[0].n, 10000,
                                                   p2sh_script)

        # Add the transaction to the block
        block(1)
        update_block(1, [p2sh_tx])
        node.p2p.send_blocks_and_test([self.tip], node)

        # Sigops p2sh limit for the mempool test
        p2sh_sigops_limit_mempool = MAX_STANDARD_TX_SIGOPS - \
            redeem_script.GetSigOpCount(True)
        # Too many sigops in one p2sh script
        too_many_p2sh_sigops_mempool = CScript([OP_CHECKSIG] *
                                               (p2sh_sigops_limit_mempool + 1))

        # A transaction with this output script can't get into the mempool
        assert_raises_rpc_error(
            -26, RPC_TXNS_TOO_MANY_SIGOPS_ERROR, node.sendrawtransaction,
            ToHex(spend_p2sh_tx(p2sh_tx, too_many_p2sh_sigops_mempool)))

        # The transaction is rejected, so the mempool should still be empty
        assert_equal(set(node.getrawmempool()), set())

        # Max sigops in one p2sh txn
        max_p2sh_sigops_mempool = CScript([OP_CHECKSIG] *
                                          (p2sh_sigops_limit_mempool))

        # A transaction with this output script can get into the mempool
        max_p2sh_sigops_txn = spend_p2sh_tx(p2sh_tx, max_p2sh_sigops_mempool)
        max_p2sh_sigops_txn_id = node.sendrawtransaction(
            ToHex(max_p2sh_sigops_txn))
        assert_equal(set(node.getrawmempool()), {max_p2sh_sigops_txn_id})

        # Mine the transaction
        block(2, spend=out[1])
        update_block(2, [max_p2sh_sigops_txn])
        node.p2p.send_blocks_and_test([self.tip], node)

        # The transaction has been mined, it's not in the mempool anymore
        assert_equal(set(node.getrawmempool()), set())
Beispiel #19
0
 def send_transaction_to_mempool(tx):
     tx_id = node.sendrawtransaction(ToHex(tx))
     assert (tx_id in node.getrawmempool())
Beispiel #20
0
    def get_tests(self):
        self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        spendable_outputs = []

        # shorthand
        block = self.next_block
        node_nonstd = self.nodes[0]
        node_std = self.nodes[1]

        # save the current tip so it can be spent by a later block
        def save_spendable_output():
            spendable_outputs.append(self.tip)

        # get an output that we previously marked as spendable
        def get_spendable_output():
            return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0)

        # returns a test case that asserts that the current tip was accepted
        def accepted():
            return TestInstance([[self.tip, True]])

        # returns a test case that asserts that the current tip was rejected
        def rejected(reject=None):
            if reject is None:
                return TestInstance([[self.tip, False]])
            else:
                return TestInstance([[self.tip, reject]])

        # move the tip back to a previous block
        def tip(number):
            self.tip = self.blocks[number]

        # adds transactions to the block and updates state
        def update_block(block_number, new_transactions):
            block = self.blocks[block_number]
            block.vtx.extend(new_transactions)
            old_sha256 = block.sha256
            make_conform_to_ctor(block)
            block.hashMerkleRoot = block.calc_merkle_root()
            block.solve()
            # Update the internal state just like in next_block
            self.tip = block
            if block.sha256 != old_sha256:
                self.block_heights[
                    block.sha256] = self.block_heights[old_sha256]
                del self.block_heights[old_sha256]
            self.blocks[block_number] = block
            return block

        # checks the mempool has exactly the same txns as in the provided list
        def check_mempool_equal(node, txns):
            assert set(node.getrawmempool()) == set(tx.hash for tx in txns)

        # Returns 2 transactions:
        # 1) txfund: create outputs in segwit addresses
        # 2) txspend: spends outputs from segwit addresses
        def create_segwit_fund_and_spend_tx(spend, case0=False):
            if not case0:
                # Spending from a P2SH-P2WPKH coin,
                #   txhash:a45698363249312f8d3d93676aa714be59b0bd758e62fa054fb1ea6218480691
                redeem_script0 = bytearray.fromhex(
                    '0014fcf9969ce1c98a135ed293719721fb69f0b686cb')
                # Spending from a P2SH-P2WSH coin,
                #   txhash:6b536caf727ccd02c395a1d00b752098ec96e8ec46c96bee8582be6b5060fa2f
                redeem_script1 = bytearray.fromhex(
                    '0020fc8b08ed636cb23afcb425ff260b3abd03380a2333b54cfa5d51ac52d803baf4'
                )
            else:
                redeem_script0 = bytearray.fromhex('51020000')
                redeem_script1 = bytearray.fromhex('53020080')
            redeem_scripts = [redeem_script0, redeem_script1]

            # Fund transaction to segwit addresses
            txfund = CTransaction()
            txfund.vin = [CTxIn(COutPoint(spend.tx.sha256, spend.n))]
            amount = (50 * COIN - 1000) // len(redeem_scripts)
            for redeem_script in redeem_scripts:
                txfund.vout.append(
                    CTxOut(
                        amount,
                        CScript([OP_HASH160,
                                 hash160(redeem_script), OP_EQUAL])))
            txfund.rehash()

            # Segwit spending transaction
            # We'll test if a node that checks for standardness accepts this
            # txn. It should fail exclusively because of the restriction in
            # the scriptSig (non clean stack..), so all other characteristcs
            # must pass standardness checks. For this reason, we create
            # standard P2SH outputs.
            txspend = CTransaction()
            for i in range(len(redeem_scripts)):
                txspend.vin.append(
                    CTxIn(COutPoint(txfund.sha256, i),
                          CScript([redeem_scripts[i]])))
            txspend.vout = [
                CTxOut(
                    50 * COIN - 2000,
                    CScript(
                        [OP_HASH160,
                         hash160(CScript([OP_TRUE])), OP_EQUAL]))
            ]
            txspend.rehash()

            return txfund, txspend

        # Check we are not banned when sending a txn that node_nonstd rejects.
        def check_for_no_ban_on_rejected_tx(tx, reject_code, reject_reason):
            # Check that our connection to node_std is open
            assert (node_std.p2p.state == 'connected')

            # The P2PConnection stores a public counter for each message type
            # and the last receive message of each type. We use this counter to
            # identify that we received a new reject message.
            with mininode_lock:
                rejects_count = node_std.p2p.message_count['reject']

            # Send the transaction directly. We use a ping for synchronization:
            # if we have been banned, the pong message won't be received, a
            # timeout occurs and the test fails.
            node_std.p2p.send_message(msg_tx(tx))
            node_std.p2p.sync_with_ping()

            # Check we haven't been disconnected
            assert (node_std.p2p.state == 'connected')

            # Check the reject message matches what we expected
            with mininode_lock:
                assert (node_std.p2p.message_count['reject'] == rejects_count +
                        1)
                reject_msg = node_std.p2p.last_message['reject']
                assert (reject_msg.code == reject_code
                        and reject_msg.reason == reject_reason
                        and reject_msg.data == tx.sha256)

        # Create a new block
        block(0)
        save_spendable_output()
        yield accepted()

        # Now we need that block to mature so we can spend the coinbase.
        test = TestInstance(sync_every_block=False)
        for i in range(100):
            block(5000 + i)
            test.blocks_and_transactions.append([self.tip, True])
            save_spendable_output()
        yield test

        # collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(100):
            out.append(get_spendable_output())

        # Create segwit funding and spending transactions
        txfund, txspend = create_segwit_fund_and_spend_tx(out[0])
        txfund_case0, txspend_case0 = create_segwit_fund_and_spend_tx(
            out[1], True)

        # Mine txfund, as it can't go into node_std mempool because it's
        # nonstandard.
        b = block(5555)
        update_block(5555, [txfund, txfund_case0])
        yield accepted()

        # Since the TestManager is not connected to node_std, we must check
        # both nodes are synchronized before continuing.
        sync_blocks(self.nodes)

        # Check that upgraded nodes checking for standardness are not banning
        # nodes sending segwit spending txns.
        check_for_no_ban_on_rejected_tx(txspend, 64, CLEANSTACK_ERROR)
        check_for_no_ban_on_rejected_tx(txspend_case0, 64, EVAL_FALSE_ERROR)

        # Segwit recovery txns are never accepted into the mempool,
        # as they are included in standard flags.
        assert_raises_rpc_error(-26, RPC_CLEANSTACK_ERROR,
                                node_nonstd.sendrawtransaction, ToHex(txspend))
        assert_raises_rpc_error(-26, RPC_EVAL_FALSE_ERROR,
                                node_nonstd.sendrawtransaction,
                                ToHex(txspend_case0))
        assert_raises_rpc_error(-26, RPC_CLEANSTACK_ERROR,
                                node_std.sendrawtransaction, ToHex(txspend))
        assert_raises_rpc_error(-26, RPC_EVAL_FALSE_ERROR,
                                node_std.sendrawtransaction,
                                ToHex(txspend_case0))

        # Blocks containing segwit spending txns are accepted in both nodes.
        block(5)
        postforkblock = update_block(5, [txspend, txspend_case0])
        yield accepted()
        sync_blocks(self.nodes)
Beispiel #21
0
    def run_miner_fund_test(self, bit, name, fund_address):
        self.log.info("Testing miner fund {} on bit {}.".format(name, bit))

        version = VERSION_BASE | (1 << bit)

        self.stop_node(0)
        self.start_node(0, [
            "-blockversion={}".format(version),
            "-axionactivationtime={}".format(AXION_ACTIVATION_TIME)
        ])

        node = self.nodes[0]
        node.setmocktime(1580000000)
        address = node.get_deterministic_priv_key().address

        def get_best_vote():
            return node.getblockheader(
                node.getbestblockhash())['version'] & 0xF

        for i in range(144):
            node.generatetoaddress(1, address)
            assert_equal(get_best_vote(), 1 << bit)
            self.check_bip9_state(
                name, {
                    'status': 'started',
                    'bit': bit,
                    'start_time': 1573819200,
                    'timeout': 1589544000,
                    'since': 288,
                    'statistics': {
                        'period': 144,
                        'threshold': 96,
                        'elapsed': i,
                        'count': i,
                        'possible': True,
                    },
                })

        for i in range(144):
            node.generatetoaddress(1, address)
            assert_equal(get_best_vote(), 1 << bit)
            self.check_bip9_state(
                name, {
                    'status': 'locked_in',
                    'start_time': 1573819200,
                    'timeout': 1589544000,
                    'since': 432,
                })

        # Now this should be active.
        node.generatetoaddress(1, address)
        assert_equal(get_best_vote(), 1 << bit)
        self.check_bip9_state(
            name, {
                'status': 'active',
                'start_time': 1573819200,
                'timeout': 1589544000,
                'since': 576,
            })

        # Move MTP forward to axion activation.
        node.setmocktime(AXION_ACTIVATION_TIME)
        for i in range(6):
            node.generatetoaddress(1, address)
            assert_equal(get_best_vote(), 1 << bit)
        assert_equal(node.getblockchaininfo()['mediantime'],
                     AXION_ACTIVATION_TIME)

        self.check_bip9_state(
            name, {
                'status': 'active',
                'start_time': 1573819200,
                'timeout': 1589544000,
                'since': 576,
            })

        # Let's remember the hash of this block for later use.
        fork_block_hash = int(node.getbestblockhash(), 16)

        def get_best_coinbase():
            return node.getblock(node.getbestblockhash(), 2)['tx'][0]

        # Check that we do not send anything to the fund yet.
        assert_equal(len(get_best_coinbase()['vout']), 1)

        # Now the miner fund is STILL NOT enforced
        node.generatetoaddress(1, address)

        # Now we STILL DO NOT send part of the coinbase to the fund.
        coinbase = get_best_coinbase()
        assert_equal(len(coinbase['vout']), 1)
        assert_equal(
            False, coinbase['vout'][0]['scriptPubKey']['addresses'][0] ==
            fund_address)

        # Invalidate top block, submit a custom block that do not send anything
        # to the fund and check it is NOT rejected.
        node.invalidateblock(node.getbestblockhash())

        block_height = node.getblockcount()
        block = create_block(fork_block_hash, create_coinbase(block_height),
                             AXION_ACTIVATION_TIME + 99)
        block.solve()

        assert_equal(node.submitblock(ToHex(block)), None)
Beispiel #22
0
    def run_test(self):
        self.nodes[0].add_p2p_connection(P2PInterface())

        network_thread_start()

        # wait_for_verack ensures that the P2P connection is fully up.
        self.nodes[0].p2p.wait_for_verack()

        self.log.info("Mining {} blocks".format(CLTV_HEIGHT - 2))
        self.coinbase_blocks = self.nodes[0].generate(CLTV_HEIGHT - 2)
        self.nodeaddress = self.nodes[0].getnewaddress()

        self.log.info(
            "Test that an invalid-according-to-CLTV transaction can still appear in a block")

        fundtx = spend_from_coinbase(self.nodes[0], self.coinbase_blocks[0],
                                     self.nodeaddress, 49.99)
        fundtx, spendtx = cltv_lock_to_height(
            self.nodes[0], fundtx, self.nodeaddress, 49.98)

        tip = self.nodes[0].getbestblockhash()
        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
        block = create_block(int(tip, 16), create_coinbase(
            CLTV_HEIGHT - 1), block_time)
        block.nVersion = 3
        block.vtx.append(fundtx)
        # include the -1 CLTV in block
        block.vtx.append(spendtx)
        make_conform_to_ctor(block)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        # This block is valid
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        self.log.info("Test that blocks must now be at least version 4")
        tip = block.sha256
        block_time += 1
        block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
        block.nVersion = 3
        block.solve()
        self.nodes[0].p2p.send_and_ping(msg_block(block))
        assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)

        wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(),
                   lock=mininode_lock)
        with mininode_lock:
            assert_equal(
                self.nodes[0].p2p.last_message["reject"].code, REJECT_OBSOLETE)
            assert_equal(
                self.nodes[0].p2p.last_message["reject"].reason, b'bad-version(0x00000003)')
            assert_equal(
                self.nodes[0].p2p.last_message["reject"].data, block.sha256)
            del self.nodes[0].p2p.last_message["reject"]

        self.log.info(
            "Test that invalid-according-to-cltv transactions cannot appear in a block")
        block.nVersion = 4

        fundtx = spend_from_coinbase(self.nodes[0], self.coinbase_blocks[1],
                                     self.nodeaddress, 49.99)
        fundtx, spendtx = cltv_lock_to_height(
            self.nodes[0], fundtx, self.nodeaddress, 49.98)

        # The funding tx only has unexecuted bad CLTV, in scriptpubkey; this is valid.
        self.nodes[0].p2p.send_and_ping(msg_tx(fundtx))
        assert fundtx.hash in self.nodes[0].getrawmempool()

        # Mine a block containing the funding transaction
        block.vtx.append(fundtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        # This block is valid
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)

        # We show that this tx is invalid due to CLTV by getting it
        # rejected from the mempool for exactly that reason.
        assert_equal(
            [{'txid': spendtx.hash, 'allowed': False,
                'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],
            self.nodes[0].testmempoolaccept(
                rawtxs=[spendtx.serialize().hex()], allowhighfees=True)
        )

        rejectedtx_signed = self.nodes[0].signrawtransactionwithwallet(
            ToHex(spendtx))

        # Couldn't complete signature due to CLTV
        assert(rejectedtx_signed['errors'][0]['error'] == 'Negative locktime')

        tip = block.hash
        block_time += 1
        block = create_block(
            block.sha256, create_coinbase(CLTV_HEIGHT+1), block_time)
        block.nVersion = 4
        block.vtx.append(spendtx)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        # This block is invalid
        assert_equal(self.nodes[0].getbestblockhash(), tip)

        wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(),
                   lock=mininode_lock)
        with mininode_lock:
            assert self.nodes[0].p2p.last_message["reject"].code in [
                REJECT_INVALID, REJECT_NONSTANDARD]
            assert_equal(
                self.nodes[0].p2p.last_message["reject"].data, block.sha256)
            if self.nodes[0].p2p.last_message["reject"].code == REJECT_INVALID:
                # Generic rejection when a block is invalid
                assert_equal(
                    self.nodes[0].p2p.last_message["reject"].reason, b'blk-bad-inputs')
            else:
                assert b'Negative locktime' in self.nodes[0].p2p.last_message["reject"].reason

        self.log.info(
            "Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
        fundtx = spend_from_coinbase(self.nodes[0], self.coinbase_blocks[2],
                                     self.nodeaddress, 49.99)
        fundtx, spendtx = cltv_lock_to_height(
            self.nodes[0], fundtx, self.nodeaddress, 49.98, CLTV_HEIGHT)

        # make sure sequence is nonfinal and locktime is good
        spendtx.vin[0].nSequence = 0xfffffffe
        spendtx.nLockTime = CLTV_HEIGHT

        # both transactions are fully valid
        self.nodes[0].sendrawtransaction(ToHex(fundtx))
        self.nodes[0].sendrawtransaction(ToHex(spendtx))

        # Modify the transactions in the block to be valid against CLTV
        block.vtx.pop(1)
        block.vtx.append(fundtx)
        block.vtx.append(spendtx)
        make_conform_to_ctor(block)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()

        self.nodes[0].p2p.send_and_ping(msg_block(block))
        # This block is now valid
        assert_equal(self.nodes[0].getbestblockhash(), block.hash)
Beispiel #23
0
    def run_test(self):
        node = self.nodes[0]

        self.log.info('Start with empty mempool, and 200 blocks')
        self.mempool_size = 0
        assert_equal(node.getblockcount(), 200)
        assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
        coins = node.listunspent()

        self.log.info('Should not accept garbage to testmempoolaccept')
        assert_raises_rpc_error(
            -3, 'Expected type array, got string',
            lambda: node.testmempoolaccept(rawtxs='ff00baar'))
        assert_raises_rpc_error(
            -8, 'Array must contain exactly one raw transaction for now',
            lambda: node.testmempoolaccept(rawtxs=['ff00baar', 'ff22']))
        assert_raises_rpc_error(
            -22, 'TX decode failed',
            lambda: node.testmempoolaccept(rawtxs=['ff00baar']))

        self.log.info('A transaction already in the blockchain')
        # Pick a random coin(base) to spend
        coin = coins.pop()
        raw_tx_in_block = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    'txid': coin['txid'],
                    'vout': coin['vout']
                }],
                outputs=[{
                    node.getnewaddress(): 0.3
                }, {
                    node.getnewaddress(): 49
                }],
            ))['hex']
        txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block,
                                                maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_in_block,
                'allowed': False,
                'reject-reason': 'txn-already-known'
            }],
            rawtxs=[raw_tx_in_block],
        )

        self.log.info('A transaction not in the mempool')
        fee = 0.00000700
        raw_tx_0 = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    "txid": txid_in_block,
                    "vout": 0,
                    "sequence": 0xfffffffd
                }],
                outputs=[{
                    node.getnewaddress(): 0.3 - fee
                }],
            ))['hex']
        tx = FromHex(CTransaction(), raw_tx_0)
        txid_0 = tx.rehash()
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_0,
                'allowed': True
            }],
            rawtxs=[raw_tx_0],
        )

        self.log.info('A final transaction not in the mempool')
        # Pick a random coin(base) to spend
        coin = coins.pop()
        raw_tx_final = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    'txid': coin['txid'],
                    'vout': coin['vout'],
                    "sequence": 0xffffffff
                }],  # SEQUENCE_FINAL
                outputs=[{
                    node.getnewaddress(): 0.025
                }],
                locktime=node.getblockcount() + 2000,  # Can be anything
            ))['hex']
        tx = FromHex(CTransaction(), raw_tx_final)
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': True
            }],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
        node.sendrawtransaction(hexstring=raw_tx_final, maxfeerate=0)
        self.mempool_size += 1

        self.log.info('A transaction in the mempool')
        node.sendrawtransaction(hexstring=raw_tx_0)
        self.mempool_size += 1
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_0,
                'allowed': False,
                'reject-reason': 'txn-already-in-mempool'
            }],
            rawtxs=[raw_tx_0],
        )

        # Removed RBF test
        # self.log.info('A transaction that replaces a mempool transaction')
        # ...

        self.log.info('A transaction that conflicts with an unconfirmed tx')
        # Send the transaction that conflicts with the mempool transaction
        node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
        # take original raw_tx_0
        tx = FromHex(CTransaction(), raw_tx_0)
        tx.vout[0].nValue -= int(4 * fee * COIN)  # Set more fee
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'txn-mempool-conflict'
            }],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )

        self.log.info('A transaction with missing inputs, that never existed')
        tx = FromHex(CTransaction(), raw_tx_0)
        tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14)
        # skip re-signing the tx
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'missing-inputs'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info(
            'A transaction with missing inputs, that existed once in the past')
        tx = FromHex(CTransaction(), raw_tx_0)
        # Set vout to 1, to spend the other outpoint (49 coins) of the
        # in-chain-tx we want to double spend
        tx.vin[0].prevout.n = 1
        raw_tx_1 = node.signrawtransactionwithwallet(ToHex(tx))['hex']
        txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
        # Now spend both to "clearly hide" the outputs, ie. remove the coins
        # from the utxo set by spending them
        raw_tx_spend_both = node.signrawtransactionwithwallet(
            node.createrawtransaction(inputs=[
                {
                    'txid': txid_0,
                    'vout': 0
                },
                {
                    'txid': txid_1,
                    'vout': 0
                },
            ],
                                      outputs=[{
                                          node.getnewaddress(): 0.1
                                      }]))['hex']
        txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both,
                                                  maxfeerate=0)
        node.generate(1)
        self.mempool_size = 0
        # Now see if we can add the coins back to the utxo set by sending the
        # exact txs again
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_0,
                'allowed': False,
                'reject-reason': 'missing-inputs'
            }],
            rawtxs=[raw_tx_0],
        )
        self.check_mempool_result(
            result_expected=[{
                'txid': txid_1,
                'allowed': False,
                'reject-reason': 'missing-inputs'
            }],
            rawtxs=[raw_tx_1],
        )

        self.log.info('Create a signed "reference" tx for later use')
        raw_tx_reference = node.signrawtransactionwithwallet(
            node.createrawtransaction(
                inputs=[{
                    'txid': txid_spend_both,
                    'vout': 0
                }],
                outputs=[{
                    node.getnewaddress(): 0.05
                }],
            ))['hex']
        tx = FromHex(CTransaction(), raw_tx_reference)
        # Reference tx should be valid on itself
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': True
            }],
            rawtxs=[ToHex(tx)],
            maxfeerate=0,
        )

        self.log.info('A transaction with no outputs')
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vout = []
        # Skip re-signing the transaction for context independent checks from now on
        # FromHex(tx, node.signrawtransactionwithwallet(ToHex(tx))['hex'])
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-vout-empty'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('A really large transaction')
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vin = [tx.vin[0]
                  ] * (1 + MAX_BLOCK_BASE_SIZE // len(tx.vin[0].serialize()))
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-oversize'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('A transaction with negative output value')
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vout[0].nValue *= -1
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-vout-negative'
            }],
            rawtxs=[ToHex(tx)],
        )

        # The following two validations prevent overflow of the output amounts
        # (see CVE-2010-5139).
        self.log.info('A transaction with too large output value')
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vout[0].nValue = 21000000 * COIN + 1
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-vout-toolarge'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('A transaction with too large sum of output values')
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vout = [tx.vout[0]] * 2
        tx.vout[0].nValue = 21000000 * COIN
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-txouttotal-toolarge'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('A transaction with duplicate inputs')
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vin = [tx.vin[0]] * 2
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-inputs-duplicate'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('A coinbase transaction')
        # Pick the input of the first tx we signed, so it has to be a coinbase
        # tx
        raw_tx_coinbase_spent = node.getrawtransaction(
            txid=node.decoderawtransaction(
                hexstring=raw_tx_in_block)['vin'][0]['txid'])
        tx = FromHex(CTransaction(), raw_tx_coinbase_spent)
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-tx-coinbase'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('Some nonstandard transactions')
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.nVersion = 3  # A version currently non-standard
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'version'
            }],
            rawtxs=[ToHex(tx)],
        )
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vout[0].scriptPubKey = CScript([OP_0])  # Some non-standard script
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'scriptpubkey'
            }],
            rawtxs=[ToHex(tx)],
        )
        tx = FromHex(CTransaction(), raw_tx_reference)
        key = ECKey()
        key.generate()
        pubkey = key.get_pubkey().get_bytes()
        # Some bare multisig script (2-of-3)
        tx.vout[0].scriptPubKey = CScript(
            [OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG])
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bare-multisig'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx = FromHex(CTransaction(), raw_tx_reference)
        # Some not-pushonly scriptSig
        tx.vin[0].scriptSig = CScript([OP_HASH160])
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'scriptsig-not-pushonly'
            }],
            rawtxs=[ToHex(tx)],
        )
        tx = FromHex(CTransaction(), raw_tx_reference)
        # Some too large scriptSig (>1650 bytes)
        tx.vin[0].scriptSig = CScript([b'a' * 1648])
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'scriptsig-size'
            }],
            rawtxs=[tx.serialize().hex()],
        )
        tx = FromHex(CTransaction(), raw_tx_reference)
        output_p2sh_burn = CTxOut(nValue=540,
                                  scriptPubKey=CScript(
                                      [OP_HASH160,
                                       hash160(b'burn'), OP_EQUAL]))
        # Use enough outputs to make the tx too large for our policy
        num_scripts = 100000 // len(output_p2sh_burn.serialize())
        tx.vout = [output_p2sh_burn] * num_scripts
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'tx-size'
            }],
            rawtxs=[ToHex(tx)],
        )
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vout[0] = output_p2sh_burn
        # Make output smaller, such that it is dust for our policy
        tx.vout[0].nValue -= 1
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'dust'
            }],
            rawtxs=[ToHex(tx)],
        )
        tx = FromHex(CTransaction(), raw_tx_reference)
        tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
        tx.vout = [tx.vout[0]] * 2
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'multi-op-return'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('A timelocked transaction')
        tx = FromHex(CTransaction(), raw_tx_reference)
        # Should be non-max, so locktime is not ignored
        tx.vin[0].nSequence -= 1
        tx.nLockTime = node.getblockcount() + 1
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'bad-txns-nonfinal'
            }],
            rawtxs=[ToHex(tx)],
        )

        self.log.info('A transaction that is locked by BIP68 sequence logic')
        tx = FromHex(CTransaction(), raw_tx_reference)
        # We could include it in the second block mined from now, but not the
        # very next one
        tx.vin[0].nSequence = 2
        # Can skip re-signing the tx because of early rejection
        self.check_mempool_result(
            result_expected=[{
                'txid': tx.rehash(),
                'allowed': False,
                'reject-reason': 'non-BIP68-final'
            }],
            rawtxs=[tx.serialize().hex()],
            maxfeerate=0,
        )
Beispiel #24
0
    def decoderawtransaction_asm_sighashtype(self):
        """Test decoding scripts via RPC command "decoderawtransaction".

        This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
        """

        # this test case uses a random plain vanilla mainnet transaction with a
        # single P2PKH input and output
        tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            '304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536',
            rpc_result['vin'][0]['scriptSig']['asm'])

        # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
        # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
        # verify that we have not altered scriptPubKey decoding.
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            '8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0',
            rpc_result['txid'])
        assert_equal(
            '0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae',
            rpc_result['vin'][0]['scriptSig']['asm'])
        assert_equal(
            'OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG',
            rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal(
            'OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL',
            rpc_result['vout'][1]['scriptPubKey']['asm'])
        txSave = FromHex(CTransaction(), tx)

        # make sure that a specifically crafted op_return value will not pass
        # all the IsDERSignature checks and then get decoded as a sighash type
        tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal('OP_RETURN 300602010002010001',
                     rpc_result['vout'][0]['scriptPubKey']['asm'])

        # verify that we have not altered scriptPubKey processing even of a
        # specially crafted P2PKH pubkeyhash and P2SH redeem script hash that
        # is made to pass the der signature checks
        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
        rpc_result = self.nodes[0].decoderawtransaction(tx)
        assert_equal(
            'OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG',
            rpc_result['vout'][0]['scriptPubKey']['asm'])
        assert_equal(
            'OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL',
            rpc_result['vout'][1]['scriptPubKey']['asm'])

        # some more full transaction tests of varying specific scriptSigs. used instead of
        # tests in decodescript_script_sig because the decodescript RPC is specifically
        # for working on scriptPubKeys (argh!).
        push_signature = txSave.vin[0].scriptSig.hex()[2:(0x48 * 2 + 4)]
        signature = push_signature[2:]
        der_signature = signature[:-2]
        signature_sighash_decoded = der_signature + '[ALL]'
        signature_2 = der_signature + '82'
        push_signature_2 = '48' + signature_2
        signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'

        # 1) P2PK scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)
        rpc_result = self.nodes[0].decoderawtransaction(ToHex(txSave))
        assert_equal(signature_sighash_decoded,
                     rpc_result['vin'][0]['scriptSig']['asm'])

        # make sure that the sighash decodes come out correctly for a more
        # complex / lesser used case.
        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(ToHex(txSave))
        assert_equal(signature_2_sighash_decoded,
                     rpc_result['vin'][0]['scriptSig']['asm'])

        # 2) multisig scriptSig
        txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature +
                                                   push_signature_2)
        rpc_result = self.nodes[0].decoderawtransaction(ToHex(txSave))
        assert_equal(
            '0 ' + signature_sighash_decoded + ' ' +
            signature_2_sighash_decoded,
            rpc_result['vin'][0]['scriptSig']['asm'])

        # 3) test a scriptSig that contains more than push operations.
        # in fact, it contains an OP_RETURN with data specially crafted to
        # cause improper decode if the code does not catch it.
        txSave.vin[0].scriptSig = hex_str_to_bytes(
            '6a143011020701010101010101020601010101010101')
        rpc_result = self.nodes[0].decoderawtransaction(ToHex(txSave))
        assert_equal('OP_RETURN 3011020701010101010101020601010101010101',
                     rpc_result['vin'][0]['scriptSig']['asm'])
Beispiel #25
0
def send_generic_input_tx(node, coinbases, address):
    return node.sendrawtransaction(ToHex(sign_transaction(node, create_transaction(node, node.getblock(coinbases.pop())['tx'][0], address, amount=Decimal("49.99")))))
    def run_test(self):
        node, = self.nodes

        self.bootstrap_p2p()

        tip = self.getbestblock(node)

        self.log.info("Create some blocks with OP_1 coinbase for spending.")
        blocks = []
        for _ in range(10):
            tip = self.build_block(tip)
            blocks.append(tip)
        node.p2p.send_blocks_and_test(blocks, node, success=True)
        spendable_outputs = [block.vtx[0] for block in blocks]

        self.log.info("Mature the blocks and get out of IBD.")
        node.generatetoaddress(100, node.get_deterministic_priv_key().address)

        tip = self.getbestblock(node)

        self.log.info("Setting up spends to test and mining the fundings.")
        fundings = []

        # Generate a key pair
        privkeybytes = b"Schnorr!" * 4
        private_key = CECKey()
        private_key.set_secretbytes(privkeybytes)
        # get uncompressed public key serialization
        public_key = private_key.get_pubkey()

        def create_fund_and_spend_tx(dummy=OP_0, sigtype='ecdsa'):
            spendfrom = spendable_outputs.pop()

            script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])

            value = spendfrom.vout[0].nValue

            # Fund transaction
            txfund = create_tx_with_script(spendfrom, 0, b'', value, script)
            txfund.rehash()
            fundings.append(txfund)

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(
                CTxOut(value - 1000, CScript([OP_TRUE])))
            txspend.vin.append(
                CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = SIGHASH_ALL | SIGHASH_FORKID
            hashbyte = bytes([sighashtype & 0xff])
            sighash = SignatureHashForkId(
                script, txspend, 0, sighashtype, value)
            if sigtype == 'schnorr':
                txsig = schnorr.sign(privkeybytes, sighash) + hashbyte
            elif sigtype == 'ecdsa':
                txsig = private_key.sign(sighash) + hashbyte
            txspend.vin[0].scriptSig = CScript([dummy, txsig])
            txspend.rehash()

            return txspend

        # This is valid.
        ecdsa0tx = create_fund_and_spend_tx(OP_0, 'ecdsa')

        # This is invalid.
        ecdsa1tx = create_fund_and_spend_tx(OP_1, 'ecdsa')

        # This is invalid.
        schnorr0tx = create_fund_and_spend_tx(OP_0, 'schnorr')

        # This is valid.
        schnorr1tx = create_fund_and_spend_tx(OP_1, 'schnorr')

        tip = self.build_block(tip, fundings)
        node.p2p.send_blocks_and_test([tip], node)

        self.log.info("Send a legacy ECDSA multisig into mempool.")
        node.p2p.send_txs_and_test([ecdsa0tx], node)
        assert_equal(node.getrawmempool(), [ecdsa0tx.hash])

        self.log.info("Trying to mine a non-null-dummy ECDSA.")
        self.check_for_ban_on_rejected_block(
            self.build_block(tip, [ecdsa1tx]), BADINPUTS_ERROR)
        self.log.info(
            "If we try to submit it by mempool or RPC, it is rejected and we are banned")
        assert_raises_rpc_error(-26, ECDSA_NULLDUMMY_ERROR,
                                node.sendrawtransaction, ToHex(ecdsa1tx))
        self.check_for_ban_on_rejected_tx(
            ecdsa1tx, ECDSA_NULLDUMMY_ERROR)

        self.log.info(
            "Submitting a Schnorr-multisig via net, and mining it in a block")
        node.p2p.send_txs_and_test([schnorr1tx], node)
        assert_equal(set(node.getrawmempool()), {
                     ecdsa0tx.hash, schnorr1tx.hash})
        tip = self.build_block(tip, [schnorr1tx])
        node.p2p.send_blocks_and_test([tip], node)

        self.log.info(
            "That legacy ECDSA multisig is still in mempool, let's mine it")
        assert_equal(node.getrawmempool(), [ecdsa0tx.hash])
        tip = self.build_block(tip, [ecdsa0tx])
        node.p2p.send_blocks_and_test([tip], node)
        assert_equal(node.getrawmempool(), [])

        self.log.info(
            "Trying Schnorr in legacy multisig is invalid and banworthy.")
        self.check_for_ban_on_rejected_tx(
            schnorr0tx, SCHNORR_LEGACY_MULTISIG_ERROR)
        self.check_for_ban_on_rejected_block(
            self.build_block(tip, [schnorr0tx]), BADINPUTS_ERROR)
Beispiel #27
0
    def run_test(self):
        self.log.info("Setting up")
        # Mine some coins
        self.nodes[0].generate(COINBASE_MATURITY + 1)

        # Get some addresses from the two nodes
        addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
        addr2 = [self.nodes[2].getnewaddress() for _ in range(3)]
        addrs = addr1 + addr2

        # Send 1 + 0.5 coin to each address
        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]

        self.nodes[0].generate(1)
        self.sync_all()

        # For each node, send 0.2 coins back to 0;
        # - node[1] should pick one 0.5 UTXO and leave the rest
        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
        #   given address, and leave the rest
        self.log.info(
            "Test sending transactions picks one UTXO group and leaves the rest"
        )
        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx1 = self.nodes[1].getrawtransaction(txid1, True)
        # txid1 should have 1 input and 2 outputs
        assert_equal(1, len(tx1["vin"]))
        assert_equal(2, len(tx1["vout"]))
        # one output should be 0.2, the other should be ~0.3
        v = [vout["value"] for vout in tx1["vout"]]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=0.3, vspan=0.0001)

        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        tx2 = self.nodes[2].getrawtransaction(txid2, True)
        # txid2 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx2["vin"]))
        assert_equal(2, len(tx2["vout"]))
        # one output should be 0.2, the other should be ~1.3
        v = [vout["value"] for vout in tx2["vout"]]
        v.sort()
        assert_approx(v[0], vexp=0.2, vspan=0.0001)
        assert_approx(v[1], vexp=1.3, vspan=0.0001)

        self.log.info(
            "Test avoiding partial spends if warranted, even if avoidpartialspends is disabled"
        )
        self.sync_all()
        self.nodes[0].generate(1)
        # Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
        # Node #1:      Node #2:
        # - A  1.0      - D0 1.0
        # - B0 1.0      - D1 0.5
        # - B1 0.5      - E0 1.0
        # - C0 1.0      - E1 0.5
        # - C1 0.5      - F  ~1.3
        # - D ~0.3
        assert_approx(self.nodes[1].getbalance(), vexp=4.3, vspan=0.0001)
        assert_approx(self.nodes[2].getbalance(), vexp=4.3, vspan=0.0001)
        # Sending 1.4 btc should pick one 1.0 + one more. For node #1,
        # this could be (A / B0 / C0) + (B1 / C1 / D). We ensure that it is
        # B0 + B1 or C0 + C1, because this avoids partial spends while not being
        # detrimental to transaction cost
        txid3 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.4)
        tx3 = self.nodes[1].getrawtransaction(txid3, True)
        # tx3 should have 2 inputs and 2 outputs
        assert_equal(2, len(tx3["vin"]))
        assert_equal(2, len(tx3["vout"]))
        # the accumulated value should be 1.5, so the outputs should be
        # ~0.1 and 1.4 and should come from the same destination
        values = [vout["value"] for vout in tx3["vout"]]
        values.sort()
        assert_approx(values[0], vexp=0.1, vspan=0.0001)
        assert_approx(values[1], vexp=1.4, vspan=0.0001)

        input_txids = [vin["txid"] for vin in tx3["vin"]]
        input_addrs = [
            self.nodes[1].gettransaction(txid)['details'][0]['address']
            for txid in input_txids
        ]
        assert_equal(input_addrs[0], input_addrs[1])
        # Node 2 enforces avoidpartialspends so needs no checking here

        self.log.info("Test wallet option maxapsfee")
        addr_aps = self.nodes[3].getnewaddress()
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.nodes[0].sendtoaddress(addr_aps, 1.0)
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[3].assert_debug_log(
            ['Fee non-grouped = 2820, grouped = 4160, using grouped']):
            txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                0.1)
        tx4 = self.nodes[3].getrawtransaction(txid4, True)
        # tx4 should have 2 inputs and 2 outputs although one output would
        # have been enough and the transaction caused higher fees
        assert_equal(2, len(tx4["vin"]))
        assert_equal(2, len(tx4["vout"]))

        addr_aps2 = self.nodes[3].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[3].assert_debug_log(
            ['Fee non-grouped = 5520, grouped = 8240, using non-grouped']):
            txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx5 = self.nodes[3].getrawtransaction(txid5, True)
        # tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs
        assert_equal(3, len(tx5["vin"]))
        assert_equal(2, len(tx5["vout"]))

        # Test wallet option maxapsfee with node 4, which sets maxapsfee
        # 1 sat higher, crossing the threshold from non-grouped to grouped.
        self.log.info(
            "Test wallet option maxapsfee threshold from non-grouped to grouped"
        )
        addr_aps3 = self.nodes[4].getnewaddress()
        [self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
        self.nodes[0].generate(1)
        self.sync_all()
        with self.nodes[4].assert_debug_log(
            ['Fee non-grouped = 5520, grouped = 8240, using grouped']):
            txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(),
                                                2.95)
        tx6 = self.nodes[4].getrawtransaction(txid6, True)
        # tx6 should have 5 inputs and 2 outputs
        assert_equal(5, len(tx6["vin"]))
        assert_equal(2, len(tx6["vout"]))

        # Empty out node2's wallet
        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(),
                                    amount=self.nodes[2].getbalance(),
                                    subtractfeefromamount=True)
        self.sync_all()
        self.nodes[0].generate(1)

        self.log.info(
            "Fill a wallet with 10,000 outputs corresponding to the same scriptPubKey"
        )
        for _ in range(5):
            raw_tx = self.nodes[0].createrawtransaction([{
                "txid": "0" * 64,
                "vout": 0
            }], [{
                addr2[0]: 0.05
            }])
            tx = FromHex(CTransaction(), raw_tx)
            tx.vin = []
            tx.vout = [tx.vout[0]] * 2000
            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
            signed_tx = self.nodes[0].signrawtransactionwithwallet(
                funded_tx['hex'])
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            self.nodes[0].generate(1)
            self.sync_all()

        # Check that we can create a transaction that only requires ~100 of our
        # utxos, without pulling in all outputs and creating a transaction that
        # is way too big.
        self.log.info(
            "Test creating txn that only requires ~100 of our UTXOs without pulling in all outputs"
        )
        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
Beispiel #28
0
    def test_sequence_lock_confirmed_inputs(self):
        # Create lots of confirmed utxos, and use them to generate lots of random
        # transactions.
        max_outputs = 10
        addresses = []
        while len(addresses) < max_outputs:
            addresses.append(self.nodes[0].getnewaddress())
        while len(self.nodes[0].listunspent()) < 200:
            import random
            random.shuffle(addresses)
            num_outputs = random.randint(1, max_outputs)
            outputs = {}
            for i in range(num_outputs):
                outputs[addresses[i]] = random.randint(1, 20) * 0.125
            self.nodes[0].sendmany("", outputs)
            self.nodes[0].generate(1)

        utxos = self.nodes[0].listunspent()

        # Try creating a lot of random transactions.
        # Each time, choose a random number of inputs, and randomly set
        # some of those inputs to be sequence locked (and randomly choose
        # between height/time locking). Small random chance of making the locks
        # all pass.
        for i in range(400):
            # Randomly choose up to 10 inputs
            num_inputs = random.randint(1, 10)
            random.shuffle(utxos)

            # Track whether any sequence locks used should fail
            should_pass = True

            # Track whether this transaction was built with sequence locks
            using_sequence_locks = False

            tx = CTransaction()
            tx.nVersion = 2
            value = 0
            for j in range(num_inputs):
                sequence_value = 0xfffffffe  # this disables sequence locks

                # 50% chance we enable sequence locks
                if random.randint(0, 1):
                    using_sequence_locks = True

                    # 10% of the time, make the input sequence value pass
                    input_will_pass = (random.randint(1, 10) == 1)
                    sequence_value = utxos[j]["confirmations"]
                    if not input_will_pass:
                        sequence_value += 1
                        should_pass = False

                    # Figure out what the median-time-past was for the confirmed input
                    # Note that if an input has N confirmations, we're going back N blocks
                    # from the tip so that we're looking up MTP of the block
                    # PRIOR to the one the input appears in, as per the BIP68 spec.
                    orig_time = self.get_median_time_past(
                        utxos[j]["confirmations"])
                    cur_time = self.get_median_time_past(0)  # MTP of the tip

                    # can only timelock this input if it's not too old -- otherwise use height
                    can_time_lock = True
                    if ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY
                        ) >= SEQUENCE_LOCKTIME_MASK:
                        can_time_lock = False

                    # if time-lockable, then 50% chance we make this a time lock
                    if random.randint(0, 1) and can_time_lock:
                        # Find first time-lock value that fails, or latest one that succeeds
                        time_delta = sequence_value << SEQUENCE_LOCKTIME_GRANULARITY
                        if input_will_pass and time_delta > cur_time - orig_time:
                            sequence_value = ((cur_time - orig_time) >>
                                              SEQUENCE_LOCKTIME_GRANULARITY)
                        elif (not input_will_pass
                              and time_delta <= cur_time - orig_time):
                            sequence_value = (
                                (cur_time - orig_time) >>
                                SEQUENCE_LOCKTIME_GRANULARITY) + 1
                        sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG
                tx.vin.append(
                    CTxIn(COutPoint(int(utxos[j]["txid"], 16),
                                    utxos[j]["vout"]),
                          nSequence=sequence_value))
                value += utxos[j]["amount"] * COIN
            # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
            tx_size = len(ToHex(tx)) // 2 + 120 * num_inputs + 50
            tx.vout.append(
                CTxOut(int(value - self.relayfee * tx_size * COIN / 1000),
                       DUMMY_P2WPKH_SCRIPT))
            rawtx = self.nodes[0].signrawtransactionwithwallet(
                ToHex(tx))["hex"]

            if (using_sequence_locks and not should_pass):
                # This transaction should be rejected
                assert_raises_rpc_error(-26, NOT_FINAL_ERROR,
                                        self.nodes[0].sendrawtransaction,
                                        rawtx)
            else:
                # This raw transaction should be accepted
                self.nodes[0].sendrawtransaction(rawtx)
                utxos = self.nodes[0].listunspent()
Beispiel #29
0
    def run_test(self):
        self.log.info("Mining blocks...")
        self.nodes[0].generate(COINBASE_MATURITY + 5)
        sync_blocks(self.nodes)

        chain_height = self.nodes[1].getblockcount()
        assert_equal(chain_height, COINBASE_MATURITY + 5)
        assert_equal(self.nodes[1].getbalance(), 0)
        assert_equal(self.nodes[2].getbalance(), 0)

        node0utxos = self.nodes[0].listunspent(1)
        tx1 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()],
            {self.nodes[1].getnewaddress(): INITIAL_BLOCK_REWARD - 0.01})
        txid1 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransactionwithwallet(tx1)["hex"])
        tx2 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()],
            {self.nodes[1].getnewaddress(): INITIAL_BLOCK_REWARD - 0.01})
        txid2 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransactionwithwallet(tx2)["hex"])
        # This will raise an exception because the transaction is not yet in a block
        assert_raises_rpc_error(-5, "Transaction not yet in block",
                                self.nodes[0].gettxoutproof, [txid1])

        self.nodes[0].generate(1)
        blockhash = self.nodes[0].getblockhash(chain_height + 1)
        self.sync_all()

        txlist = []
        blocktxn = self.nodes[0].getblock(blockhash, True)["tx"]
        txlist.append(blocktxn[1])
        txlist.append(blocktxn[2])

        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1
                                                                        ])),
            [txid1])
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2])), txlist)
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2], blockhash)), txlist)

        txin_spent = self.nodes[1].listunspent(1).pop()
        tx3 = self.nodes[1].createrawtransaction(
            [txin_spent],
            {self.nodes[0].getnewaddress(): INITIAL_BLOCK_REWARD - 0.02})
        txid3 = self.nodes[0].sendrawtransaction(
            self.nodes[1].signrawtransactionwithwallet(tx3)["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        txid_spent = txin_spent["txid"]
        txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2

        # Invalid txids
        assert_raises_rpc_error(
            -8,
            "txid must be of length 64 (not 32, for '00000000000000000000000000000000')",
            self.nodes[2].gettxoutproof, ["00000000000000000000000000000000"],
            blockhash)
        assert_raises_rpc_error(
            -8,
            "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[2].gettxoutproof, [
                "ZZZ0000000000000000000000000000000000000000000000000000000000000"
            ], blockhash)
        # Invalid blockhashes
        assert_raises_rpc_error(
            -8,
            "blockhash must be of length 64 (not 32, for '00000000000000000000000000000000')",
            self.nodes[2].gettxoutproof, [txid_spent],
            "00000000000000000000000000000000")
        assert_raises_rpc_error(
            -8,
            "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
            self.nodes[2].gettxoutproof, [txid_spent],
            "ZZZ0000000000000000000000000000000000000000000000000000000000000")
        # We can't find the block from a fully-spent tx
        assert_raises_rpc_error(-5, "Transaction not yet in block",
                                self.nodes[2].gettxoutproof, [txid_spent])
        # We can get the proof if we specify the block
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_spent], blockhash)), [txid_spent])
        # We can't get the proof if we specify a non-existent block
        assert_raises_rpc_error(
            -5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent],
            "0000000000000000000000000000000000000000000000000000000000000000")
        # We can get the proof if the transaction is unspent
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_unspent])), [txid_unspent])
        # We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter.
        assert_equal(
            sorted(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2]))), sorted(txlist))
        assert_equal(
            sorted(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid2, txid1]))), sorted(txlist))
        # We can always get a proof if we have a -txindex
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof(
                [txid_spent])), [txid_spent])
        # We can't get a proof if we specify transactions from different blocks
        assert_raises_rpc_error(
            -5, "Not all transactions found in specified or retrieved block",
            self.nodes[2].gettxoutproof, [txid1, txid3])

        # Now we'll try tweaking a proof.
        proof = self.nodes[3].gettxoutproof([txid1, txid2])
        assert txid1 in self.nodes[0].verifytxoutproof(proof)
        assert txid2 in self.nodes[1].verifytxoutproof(proof)

        tweaked_proof = FromHex(CMerkleBlock(), proof)

        # Make sure that our serialization/deserialization is working
        assert txid1 in self.nodes[2].verifytxoutproof(ToHex(tweaked_proof))

        # Check to see if we can go up the merkle tree and pass this off as a
        # single-transaction block
        tweaked_proof.txn.nTransactions = 1
        tweaked_proof.txn.vHash = [tweaked_proof.header.hashMerkleRoot]
        tweaked_proof.txn.vBits = [True] + [False] * 7

        for n in self.nodes:
            assert not n.verifytxoutproof(ToHex(tweaked_proof))
Beispiel #30
0
        txid1 = send_to_witness(1, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996"))
        hex_tx = self.nodes[0].gettransaction(txid)['hex']
        tx = FromHex(CTransaction(), hex_tx)
<<<<<<< HEAD
        assert(tx.wit.is_null()) # This should not be a segwit input
        assert(txid1 in self.nodes[0].getrawmempool())
=======
        assert tx.wit.is_null()  # This should not be a segwit input
        assert txid1 in self.nodes[0].getrawmempool()
>>>>>>> 3001cc61cf11e016c403ce83c9cbcfd3efcbcfd9

        # Now create tx2, which will spend from txid1.
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))
        tx.vout.append(CTxOut(int(49.99 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
        tx2_hex = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))['hex']
        txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
        tx = FromHex(CTransaction(), tx2_hex)
        assert not tx.wit.is_null()

        # Now create tx3, which will spend from txid2
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
        tx.vout.append(CTxOut(int(49.95 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))  # Huge fee
        tx.calc_sha256()
        txid3 = self.nodes[0].sendrawtransaction(ToHex(tx))
        assert tx.wit.is_null()
        assert txid3 in self.nodes[0].getrawmempool()

        # Now try calling getblocktemplate() without segwit support.
        template = self.nodes[0].getblocktemplate()