hacktober fest #214
76 changed files with 1617 additions and 1172 deletions
|
@ -38,7 +38,7 @@ AC_DEFUN([BITCOIN_FIND_BDB48],[
|
|||
done
|
||||
if test "x$bdbpath" = "xX"; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR(libdb_cxx headers missing)
|
||||
AC_MSG_ERROR([libdb_cxx headers missing, Bitcoin Core requires this library for wallet functionality (--disable-wallet to disable wallet functionality)])
|
||||
elif test "x$bdb48path" = "xX"; then
|
||||
BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx)
|
||||
AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[
|
||||
|
|
|
@ -7,7 +7,7 @@ There are several features that make it different from most similar systems:
|
|||
|
||||
In theory, binaries for any target OS/architecture can be created, from a
|
||||
builder running any OS/architecture. In practice, build-side tools must be
|
||||
specified when the defaults don't fit, and packages must be ammended to work
|
||||
specified when the defaults don't fit, and packages must be amended to work
|
||||
on new hosts. For now, a build architecture of x86_64 is assumed, either on
|
||||
Linux or OSX.
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ endef
|
|||
# These functions create the build targets for each package. They must be
|
||||
# broken down into small steps so that each part is done for all packages
|
||||
# before moving on to the next step. Otherwise, a package's info
|
||||
# (build-id for example) would only be avilable to another package if it
|
||||
# (build-id for example) would only be available to another package if it
|
||||
# happened to be computed already.
|
||||
|
||||
#set the type for host/build packages.
|
||||
|
|
|
@ -3,7 +3,7 @@ Bitcoin Core 0.10.99
|
|||
|
||||
Setup
|
||||
---------------------
|
||||
[Bitcoin Core](http://bitcoin.org/en/download) is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions (which is currently several GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. Thankfully you only have to do this once. If you would like the process to go faster you can [download the blockchain directly](bootstrap.md).
|
||||
[Bitcoin Core](http://bitcoin.org/en/download) is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions (which is currently several GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
|
||||
|
||||
Running
|
||||
---------------------
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
### Bootstrap the Blockchain Synchronization
|
||||
|
||||
Normally the Bitcoin client will download the transaction and network information, called the blockchain, from the network by syncing with the other clients. This process can take quite some time as the [Bitcoin blockchain](https://blockchain.info/charts/blocks-size) is growing bigger and bigger for each day. Luckily there is a safe and fast way to speed up this process. We'll show you how to bootstrap your blockchain to bring your client up to speed in just a few simple steps.
|
||||
|
||||
### Requirements
|
||||
|
||||
- A fresh install of the Bitcoin client software.
|
||||
|
||||
### Download the blockchain via BitTorrent
|
||||
|
||||
Jeff Garzik, Bitcoin Core developer, offers an [torrent file](https://bitcointalk.org/index.php?topic=145386.0) for bootstrapping purposes that is updated often. BitTorrent is a protocol that speeds up the downloading of large files by using the other clients in the network. Examples of free and safe open source clients are [Deluge](http://deluge-torrent.org/) or [qBittorrent](http://www.qbittorrent.org/). A guide to installing and configuring the torrent clients can be found [here](http://dev.deluge-torrent.org/wiki/UserGuide) for Deluge and [here](http://qbforums.shiki.hu/) for qBittorrent. A further in-depth tutorial on BitTorrent can be found [here](http://www.howtogeek.com/howto/31846/bittorrent-for-beginners-how-get-started-downloading-torrents/).
|
||||
|
||||
With the client installed we'll proceed to download the blockchain torrent file. Use the following magnet link:
|
||||
|
||||
magnet:?xt=urn:btih:2d4e6c1f96c5d5fb260dff92aea4e600227f1aea&dn=bootstrap.dat&tr=udp://tracker.openbittorrent.com:80&tr=udp://tracker.publicbt.com:80&tr=udp://tracker.ccc.de:80&tr=udp://tracker.istole.it:80
|
||||
|
||||
or go to [Jeff Garzik's topic](https://bitcointalk.org/index.php?topic=145386.0) for a signed magnet link. Alternatively you can use the [.torrent file](http://sourceforge.net/projects/bitcoin/files/Bitcoin/blockchain/bootstrap.dat.torrent/download) found on SourceForge.
|
||||
|
||||
![Fig1](img/bootstrap1.png)
|
||||
|
||||
The download page should look like this, with a countdown to the download. If it does not work click the direct download link.
|
||||
|
||||
The torrent client installed will recognize the download of the torrent file. Save the bootstrap.dat file to the folder you use for downloads. The image below shows the torrent download in qBittorrent, with current speed and ETA highlighted.
|
||||
|
||||
![Fig2](img/bootstrap2.png)
|
||||
|
||||
### Importing the blockchain
|
||||
Exit the Bitcoin client software if you have it running. Be sure not to have an actively used wallet in use. We are going to copy the download of the blockchain to the Bitcoin client data directory. You should run the client software at least once so it can generate the data directory. Copy the downloaded bootstrap.dat file into the Bitcoin data folder.
|
||||
|
||||
**For Windows users:**
|
||||
Open explorer, and type into the address bar:
|
||||
|
||||
%APPDATA%\Bitcoin
|
||||
|
||||
This will open up the data folder. It should look like the image below. Copy over the bootstrap.dat from your download folder to this directory.
|
||||
![Fig4](img/bootstrap4.png)
|
||||
|
||||
**For OSX users:**
|
||||
Open Finder by pressing Press [shift] + [cmd] + [g] and enter:
|
||||
|
||||
~/Library/Application Support/Bitcoin/
|
||||
|
||||
**For Linux users:**
|
||||
The directory is hidden in your User folder. Go to:
|
||||
|
||||
~/.bitcoin/
|
||||
|
||||
### Importing the blockchain
|
||||
Now start the Bitcoin client software. It should show "Importing blocks from disk" like the image below.
|
||||
![Fig5](img/bootstrap5.png)
|
||||
|
||||
Wait until the import finishes. The client will download the last days not covered by the import. Congratulations you have successfully imported the blockchain!
|
||||
|
||||
### Is this safe?
|
||||
|
||||
Yes, the above method is safe. The download contains only raw blockchain data and the client verifies this on import. Do not download the blockchain from unofficial sources, especially if they provide `*.rev` and `*.sst` files. These files are not verified and can contain malicious edits.
|
|
@ -159,7 +159,7 @@ tar -xzvf db-4.8.30.NC.tar.gz
|
|||
|
||||
# Build the library and install to our prefix
|
||||
cd db-4.8.30.NC/build_unix/
|
||||
# Note: Do a static build so that it can be embedded into the exectuable, instead of having to find a .so at runtime
|
||||
# Note: Do a static build so that it can be embedded into the executable, instead of having to find a .so at runtime
|
||||
../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX
|
||||
make install
|
||||
|
||||
|
@ -196,7 +196,7 @@ Hardening enables the following features:
|
|||
* Position Independent Executable
|
||||
Build position independent code to take advantage of Address Space Layout Randomization
|
||||
offered by some kernels. An attacker who is able to cause execution of code at an arbitrary
|
||||
memory location is thwarted if he doesn't know where anything useful is located.
|
||||
memory location is thwarted if he or she doesn't know where anything useful is located.
|
||||
The stack and heap are randomly located by default but this allows the code section to be
|
||||
randomly located as well.
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ Table of Contents
|
|||
- [Connecting to the VM](#connecting-to-the-vm)
|
||||
- [Setting up Debian for gitian building](#setting-up-debian-for-gitian-building)
|
||||
- [Installing gitian](#installing-gitian)
|
||||
- [Setting up gitian images](#setting-up-gitian-images)
|
||||
- [Setting up the gitian image](#setting-up-the-gitian-image)
|
||||
- [Getting and building the inputs](#getting-and-building-the-inputs)
|
||||
- [Building Bitcoin](#building-bitcoin)
|
||||
- [Building an alternative repository](#building-an-alternative-repository)
|
||||
|
@ -74,11 +74,11 @@ In the VirtualBox GUI click "Create" and choose the following parameters in the
|
|||
- Disk size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side
|
||||
- Push the `Create` button
|
||||
|
||||
Get the [Debian 7.4 net installer](http://ftp.at.debian.org/debian-jigdo/current/amd64/iso-cd/debian-7.4.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
|
||||
Get the [Debian 7.7 net installer](http://cdimage.debian.org/debian-cd/7.7.0/amd64/iso-cd/debian-7.7.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
|
||||
This DVD image can be validated using a SHA256 hashing tool, for example on
|
||||
Unixy OSes by entering the following in a terminal:
|
||||
|
||||
echo "b712a141bc60269db217d3b3e456179bd6b181645f90e4aac9c42ed63de492e9 debian-7.4.0-amd64-netinst.iso" | sha256sum -c
|
||||
echo "d440e85b4121f94608748139f25dbce1ad36771348b002fe07d4d44b9d9e623f debian-7.7.0-amd64-netinst.iso" | sha256sum -c
|
||||
# (must return OK)
|
||||
|
||||
After creating the VM, we need to configure it.
|
||||
|
@ -109,7 +109,7 @@ Then start the VM. On the first launch you will be asked for a CD or DVD image.
|
|||
Installing Debian
|
||||
------------------
|
||||
|
||||
In this section it will be explained how to install Debian on the newly created VM.
|
||||
This section will explain how to install Debian on the newly created VM.
|
||||
|
||||
- Choose the non-graphical installer. We do not need the graphical environment, it will only increase installation time and disk usage.
|
||||
|
||||
|
@ -277,24 +277,21 @@ cd ..
|
|||
|
||||
**Note**: When sudo asks for a password, enter the password for the user *debian* not for *root*.
|
||||
|
||||
Clone the git repositories for bitcoin and gitian and then checkout the bitcoin version that you want to build.
|
||||
Clone the git repositories for bitcoin and gitian.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/devrandom/gitian-builder.git
|
||||
git clone https://github.com/bitcoin/bitcoin
|
||||
cd bitcoin
|
||||
git checkout v${VERSION}
|
||||
cd ..
|
||||
```
|
||||
|
||||
Setting up gitian images
|
||||
Setting up the gitian image
|
||||
-------------------------
|
||||
|
||||
Gitian needs virtual images of the operating system to build in.
|
||||
Currently this is Ubuntu Precise for x86_64.
|
||||
These images will be copied and used every time that a build is started to
|
||||
Gitian needs a virtual image of the operating system to build in.
|
||||
Currently this is Ubuntu Precise x86_64.
|
||||
This image will be copied and used every time that a build is started to
|
||||
make sure that the build is deterministic.
|
||||
Creating the images will take a while, but only has to be done once.
|
||||
Creating the image will take a while, but only has to be done once.
|
||||
|
||||
Execute the following as user `debian`:
|
||||
|
||||
|
@ -303,7 +300,7 @@ cd gitian-builder
|
|||
bin/make-base-vm --lxc --arch amd64 --suite precise
|
||||
```
|
||||
|
||||
There will be a lot of warnings printed during build of the images. These can be ignored.
|
||||
There will be a lot of warnings printed during build of the image. These can be ignored.
|
||||
|
||||
**Note**: When sudo asks for a password, enter the password for the user *debian* not for *root*.
|
||||
|
||||
|
@ -322,13 +319,14 @@ To build Bitcoin (for Linux, OSX and Windows) just follow the steps under 'perfo
|
|||
gitian builds' in [doc/release-process.md](release-process.md) in the bitcoin repository.
|
||||
|
||||
This may take a long time as it also builds the dependencies needed for each descriptor.
|
||||
These dependencies will be cached after a successful build to avoid rebuilding them when possible.
|
||||
These dependencies will be cached after a successful build to avoid rebuilding them where possible.
|
||||
|
||||
At any time you can check the package installation and build progress with
|
||||
|
||||
```bash
|
||||
tail -f var/install.log
|
||||
tail -f var/build.log
|
||||
```
|
||||
|
||||
Output from `gbuild` will look something like
|
||||
|
||||
|
@ -382,9 +380,9 @@ When you execute `gsign` you will get an error from GPG, which can be ignored. C
|
|||
in `gitian.sigs` to your signing machine and do
|
||||
|
||||
```bash
|
||||
gpg --detach-sign ${VERSION}-linux/${SIGNER}/bitcoin-build.assert
|
||||
gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-build.assert
|
||||
gpg --detach-sign ${VERSION}-osx/${SIGNER}/bitcoin-build.assert
|
||||
gpg --detach-sign ${VERSION}-linux/${SIGNER}/bitcoin-linux-build.assert
|
||||
gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-win-build.assert
|
||||
gpg --detach-sign ${VERSION}-osx-unsigned/${SIGNER}/bitcoin-osx-build.assert
|
||||
```
|
||||
|
||||
This will create the `.sig` files that can be committed together with the `.assert` files to assert your
|
||||
|
|
|
@ -12,7 +12,7 @@ Base class for new regression tests.
|
|||
### [listtransactions.py](listtransactions.py)
|
||||
Tests for the listtransactions RPC call.
|
||||
|
||||
### [util.py](util.sh)
|
||||
### [util.py](util.py)
|
||||
Generally useful functions.
|
||||
|
||||
Bash-based tests, to be ported to Python:
|
||||
|
|
90
qa/rpc-tests/bipdersig.py
Executable file
90
qa/rpc-tests/bipdersig.py
Executable file
|
@ -0,0 +1,90 @@
|
|||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2014 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test the BIP66 changeover logic
|
||||
#
|
||||
|
||||
from test_framework import BitcoinTestFramework
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
from util import *
|
||||
import os
|
||||
import shutil
|
||||
|
||||
class BIP66Test(BitcoinTestFramework):
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, []))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=2"]))
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=3"]))
|
||||
connect_nodes(self.nodes[1], 0)
|
||||
connect_nodes(self.nodes[2], 0)
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
cnt = self.nodes[0].getblockcount()
|
||||
|
||||
# Mine some old-version blocks
|
||||
self.nodes[1].setgenerate(True, 100)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 100):
|
||||
raise AssertionError("Failed to mine 100 version=2 blocks")
|
||||
|
||||
# Mine 750 new-version blocks
|
||||
for i in xrange(15):
|
||||
self.nodes[2].setgenerate(True, 50)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 850):
|
||||
raise AssertionError("Failed to mine 750 version=3 blocks")
|
||||
|
||||
# TODO: check that new DERSIG rules are not enforced
|
||||
|
||||
# Mine 1 new-version block
|
||||
self.nodes[2].setgenerate(True, 1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 851):
|
||||
raise AssertionFailure("Failed to mine a version=3 blocks")
|
||||
|
||||
# TODO: check that new DERSIG rules are enforced
|
||||
|
||||
# Mine 198 new-version blocks
|
||||
for i in xrange(2):
|
||||
self.nodes[2].setgenerate(True, 99)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1049):
|
||||
raise AssertionError("Failed to mine 198 version=3 blocks")
|
||||
|
||||
# Mine 1 old-version block
|
||||
self.nodes[1].setgenerate(True, 1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1050):
|
||||
raise AssertionError("Failed to mine a version=2 block after 949 version=3 blocks")
|
||||
|
||||
# Mine 1 new-version blocks
|
||||
self.nodes[2].setgenerate(True, 1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1051):
|
||||
raise AssertionError("Failed to mine a version=3 block")
|
||||
|
||||
# Mine 1 old-version blocks
|
||||
try:
|
||||
self.nodes[1].setgenerate(True, 1)
|
||||
raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks")
|
||||
except JSONRPCException:
|
||||
pass
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1051):
|
||||
raise AssertionError("Accepted a version=2 block after 950 version=3 blocks")
|
||||
|
||||
# Mine 1 new-version blocks
|
||||
self.nodes[2].setgenerate(True, 1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1052):
|
||||
raise AssertionError("Failed to mine a version=3 block")
|
||||
|
||||
if __name__ == '__main__':
|
||||
BIP66Test().main()
|
|
@ -95,6 +95,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
|||
|
||||
def run_test(self):
|
||||
node = self.nodes[0]
|
||||
node.setgenerate(True, 1) # Mine a block to leave initial block download
|
||||
tmpl = node.getblocktemplate()
|
||||
if 'coinbasetxn' not in tmpl:
|
||||
rawcoinbase = encodeUNum(tmpl['height'])
|
||||
|
|
|
@ -61,7 +61,7 @@ class WalletTest (BitcoinTestFramework):
|
|||
walletinfo = self.nodes[0].getwalletinfo()
|
||||
assert_equal(walletinfo['immature_balance'], 0)
|
||||
|
||||
# Have node0 mine a block, thus he will collect his own fee.
|
||||
# Have node0 mine a block, thus they will collect their own fee.
|
||||
self.nodes[0].setgenerate(True, 1)
|
||||
self.sync_all()
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ EXTRA_DIST += \
|
|||
JSON_TEST_FILES = \
|
||||
test/data/script_valid.json \
|
||||
test/data/base58_keys_valid.json \
|
||||
test/data/sig_canonical.json \
|
||||
test/data/sig_noncanonical.json \
|
||||
test/data/base58_encode_decode.json \
|
||||
test/data/base58_keys_invalid.json \
|
||||
test/data/script_invalid.json \
|
||||
|
|
|
@ -436,7 +436,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
|
|||
BOOST_FOREACH(const CTransaction& txv, txVariants) {
|
||||
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
|
||||
}
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i)))
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
|
||||
fComplete = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -186,11 +186,11 @@ public:
|
|||
vSeeds.clear();
|
||||
//vFixedSeeds.clear();
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = boost::assign::list_of(0);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = boost::assign::list_of(5);
|
||||
base58Prefixes[SECRET_KEY] = boost::assign::list_of(128);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E);
|
||||
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4);
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
|
||||
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container<std::vector<unsigned char> >();
|
||||
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container<std::vector<unsigned char> >();
|
||||
|
||||
convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main));
|
||||
|
||||
|
@ -244,11 +244,11 @@ public:
|
|||
//vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
|
||||
//vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = boost::assign::list_of(111);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = boost::assign::list_of(196);
|
||||
base58Prefixes[SECRET_KEY] = boost::assign::list_of(239);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF);
|
||||
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94);
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
|
||||
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >();
|
||||
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
|
||||
|
||||
convertSeed6(vFixedSeeds, pnSeed6_test, ARRAYLEN(pnSeed6_test));
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ private:
|
|||
fAllOk &= fOk;
|
||||
nTodo -= nNow;
|
||||
if (nTodo == 0 && !fMaster)
|
||||
// We processed the last element; inform the master he can exit and return the result
|
||||
// We processed the last element; inform the master he or she can exit and return the result
|
||||
condMaster.notify_one();
|
||||
} else {
|
||||
// first iteration
|
||||
|
|
|
@ -102,7 +102,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
|
|||
}
|
||||
|
||||
|
||||
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
|
||||
static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
|
||||
{
|
||||
CCrypter cKeyCrypter;
|
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
|
||||
|
@ -112,7 +112,7 @@ bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vch
|
|||
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
|
||||
}
|
||||
|
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
|
||||
static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
|
||||
{
|
||||
CCrypter cKeyCrypter;
|
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
|
||||
|
@ -122,6 +122,19 @@ bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned
|
|||
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
|
||||
}
|
||||
|
||||
static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
|
||||
{
|
||||
CKeyingMaterial vchSecret;
|
||||
if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
||||
return false;
|
||||
|
||||
if (vchSecret.size() != 32)
|
||||
return false;
|
||||
|
||||
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
||||
return key.VerifyPubKey(vchPubKey);
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::SetCrypted()
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
|
@ -161,20 +174,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
|||
{
|
||||
const CPubKey &vchPubKey = (*mi).second.first;
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
|
||||
CKeyingMaterial vchSecret;
|
||||
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
||||
{
|
||||
keyFail = true;
|
||||
break;
|
||||
}
|
||||
if (vchSecret.size() != 32)
|
||||
{
|
||||
keyFail = true;
|
||||
break;
|
||||
}
|
||||
CKey key;
|
||||
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
||||
if (key.GetPubKey() != vchPubKey)
|
||||
if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
|
||||
{
|
||||
keyFail = true;
|
||||
break;
|
||||
|
@ -243,13 +244,7 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
|
|||
{
|
||||
const CPubKey &vchPubKey = (*mi).second.first;
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
|
||||
CKeyingMaterial vchSecret;
|
||||
if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
||||
return false;
|
||||
if (vchSecret.size() != 32)
|
||||
return false;
|
||||
keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
||||
return true;
|
||||
return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -107,9 +107,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
|
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
|
||||
|
||||
/** Keystore which keeps the private keys encrypted.
|
||||
* It derives from the basic key store, which is used if no encryption is active.
|
||||
*/
|
||||
|
|
22
src/init.cpp
22
src/init.cpp
|
@ -236,6 +236,26 @@ bool static Bind(const CService &addr, unsigned int flags) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void OnRPCStopped()
|
||||
{
|
||||
cvBlockChange.notify_all();
|
||||
LogPrint("rpc", "RPC stopped.\n");
|
||||
}
|
||||
|
||||
void OnRPCPreCommand(const CRPCCommand& cmd)
|
||||
{
|
||||
#ifdef ENABLE_WALLET
|
||||
if (cmd.reqWallet && !pwalletMain)
|
||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
|
||||
#endif
|
||||
|
||||
// Observe safe mode
|
||||
string strWarning = GetWarnings("rpc");
|
||||
if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
|
||||
!cmd.okSafeMode)
|
||||
throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
|
||||
}
|
||||
|
||||
std::string HelpMessage(HelpMessageMode mode)
|
||||
{
|
||||
// When adding new options to the categories, please keep and ensure alphabetical ordering.
|
||||
|
@ -804,6 +824,8 @@ bool AppInit2(boost::thread_group& threadGroup)
|
|||
if (fServer)
|
||||
{
|
||||
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
|
||||
RPCServer::OnStopped(&OnRPCStopped);
|
||||
RPCServer::OnPreCommand(&OnRPCPreCommand);
|
||||
StartRPCThreads();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
#include "crypter.h"
|
||||
#include "key.h"
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
|
||||
#include "key.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "sync.h"
|
||||
|
||||
#include <boost/signals2/signal.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
class CScript;
|
||||
class CScriptID;
|
||||
|
||||
/** A virtual base class for key stores */
|
||||
class CKeyStore
|
||||
{
|
||||
|
|
26
src/main.cpp
26
src/main.cpp
|
@ -747,7 +747,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|||
// non-standard. Note that this EvalScript() call will
|
||||
// be quick, because if there are any operations
|
||||
// beside "push data" in the scriptSig
|
||||
// IsStandard() will have already returned false
|
||||
// IsStandardTx() will have already returned false
|
||||
// and this method isn't called.
|
||||
vector<vector<unsigned char> > stack;
|
||||
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
|
||||
|
@ -908,7 +908,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
|
|||
|
||||
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fRejectInsaneFee)
|
||||
bool* pfMissingInputs, bool fRejectAbsurdFee)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (pfMissingInputs)
|
||||
|
@ -1067,8 +1067,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
dFreeCount += nSize;
|
||||
}
|
||||
|
||||
if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
|
||||
return error("AcceptToMemoryPool: insane fees %s, %d > %d",
|
||||
if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
|
||||
return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",
|
||||
hash.ToString(),
|
||||
nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
|
||||
|
||||
|
@ -1426,7 +1426,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
|||
|
||||
bool CScriptCheck::operator()() {
|
||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore), &error)) {
|
||||
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) {
|
||||
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
|
||||
}
|
||||
return true;
|
||||
|
@ -1796,6 +1796,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
|
||||
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
|
||||
|
||||
// Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded:
|
||||
if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, Params().EnforceBlockUpgradeMajority())) {
|
||||
flags |= SCRIPT_VERIFY_DERSIG;
|
||||
}
|
||||
|
||||
CBlockUndo blockundo;
|
||||
|
||||
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
|
||||
|
@ -2681,6 +2686,13 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
|
|||
REJECT_OBSOLETE, "bad-version");
|
||||
}
|
||||
|
||||
// Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded:
|
||||
if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, Params().RejectBlockOutdatedMajority()))
|
||||
{
|
||||
return state.Invalid(error("%s : rejected nVersion=2 block", __func__),
|
||||
REJECT_OBSOLETE, "bad-version");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4623,12 +4635,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|||
LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
|
||||
pto->fDisconnect = true;
|
||||
}
|
||||
// In case there is a block that has been in flight from this peer for (1 + 0.5 * N) times the block interval
|
||||
// In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval
|
||||
// (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to
|
||||
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
|
||||
// being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
|
||||
// to unreasonably increase our timeout.
|
||||
if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (2 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) {
|
||||
if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) {
|
||||
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id);
|
||||
pto->fDisconnect = true;
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ void FlushStateToDisk();
|
|||
|
||||
/** (try to) add transaction to memory pool **/
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fRejectInsaneFee=false);
|
||||
bool* pfMissingInputs, bool fRejectAbsurdFee=false);
|
||||
|
||||
|
||||
struct CNodeStateStats {
|
||||
|
|
|
@ -24,7 +24,7 @@ class CBlockHeader
|
|||
{
|
||||
public:
|
||||
// header
|
||||
static const int32_t CURRENT_VERSION=2;
|
||||
static const int32_t CURRENT_VERSION=3;
|
||||
int32_t nVersion;
|
||||
uint256 hashPrevBlock;
|
||||
uint256 hashMerkleRoot;
|
||||
|
|
|
@ -278,7 +278,6 @@ void BitcoinAmountField::setValue(const CAmount& value)
|
|||
void BitcoinAmountField::setReadOnly(bool fReadOnly)
|
||||
{
|
||||
amount->setReadOnly(fReadOnly);
|
||||
unit->setEnabled(!fReadOnly);
|
||||
}
|
||||
|
||||
void BitcoinAmountField::unitChanged(int idx)
|
||||
|
|
|
@ -526,8 +526,8 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
|
|||
msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
|
||||
msgParams.second = CClientUIInterface::MSG_ERROR;
|
||||
break;
|
||||
case WalletModel::InsaneFee:
|
||||
msgParams.first = tr("A fee higher than %1 is considered an insanely high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000));
|
||||
case WalletModel::AbsurdFee:
|
||||
msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000));
|
||||
break;
|
||||
case WalletModel::PaymentRequestExpired:
|
||||
msgParams.first = tr("Payment request expired!");
|
||||
|
|
|
@ -279,9 +279,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
|||
return TransactionCreationFailed;
|
||||
}
|
||||
|
||||
// reject insane fee > 0.1 bitcoin
|
||||
// reject absurdly high fee > 0.1 bitcoin
|
||||
if (nFeeRequired > 10000000)
|
||||
return InsaneFee;
|
||||
return AbsurdFee;
|
||||
}
|
||||
|
||||
return SendCoinsReturn(OK);
|
||||
|
|
|
@ -111,7 +111,7 @@ public:
|
|||
DuplicateAddress,
|
||||
TransactionCreationFailed, // Error returned when wallet is still locked
|
||||
TransactionCommitFailed,
|
||||
InsaneFee,
|
||||
AbsurdFee,
|
||||
PaymentRequestExpired
|
||||
};
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ Value getblockcount(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getblockcount", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
return chainActive.Height();
|
||||
}
|
||||
|
||||
|
@ -121,6 +122,7 @@ Value getbestblockhash(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getbestblockhash", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
return chainActive.Tip()->GetBlockHash().GetHex();
|
||||
}
|
||||
|
||||
|
@ -137,6 +139,7 @@ Value getdifficulty(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getdifficulty", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
return GetDifficulty();
|
||||
}
|
||||
|
||||
|
@ -173,6 +176,8 @@ Value getrawmempool(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getrawmempool", "true")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
bool fVerbose = false;
|
||||
if (params.size() > 0)
|
||||
fVerbose = params[0].get_bool();
|
||||
|
@ -233,6 +238,8 @@ Value getblockhash(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getblockhash", "1000")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
int nHeight = params[0].get_int();
|
||||
if (nHeight < 0 || nHeight > chainActive.Height())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||
|
@ -277,6 +284,8 @@ Value getblock(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
std::string strHash = params[0].get_str();
|
||||
uint256 hash(uint256S(strHash));
|
||||
|
||||
|
@ -326,6 +335,8 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("gettxoutsetinfo", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
Object ret;
|
||||
|
||||
CCoinsStats stats;
|
||||
|
@ -380,6 +391,8 @@ Value gettxout(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("gettxout", "\"txid\", 1")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
Object ret;
|
||||
|
||||
std::string strHash = params[0].get_str();
|
||||
|
@ -436,6 +449,8 @@ Value verifychain(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("verifychain", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
int nCheckLevel = GetArg("-checklevel", 3);
|
||||
int nCheckDepth = GetArg("-checkblocks", 288);
|
||||
if (params.size() > 0)
|
||||
|
@ -467,6 +482,8 @@ Value getblockchaininfo(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getblockchaininfo", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
Object obj;
|
||||
obj.push_back(Pair("chain", Params().NetworkIDString()));
|
||||
obj.push_back(Pair("blocks", (int)chainActive.Height()));
|
||||
|
@ -526,6 +543,8 @@ Value getchaintips(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getchaintips", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
/* Build up a list of chain tips. We start with the list of all
|
||||
known blocks, and successively remove blocks that appear as pprev
|
||||
of another block. */
|
||||
|
|
|
@ -91,6 +91,8 @@ Value importprivkey(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
string strSecret = params[0].get_str();
|
||||
|
@ -158,6 +160,8 @@ Value importaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
CScript script;
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
|
@ -223,6 +227,8 @@ Value importwallet(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("importwallet", "\"test\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
ifstream file;
|
||||
|
@ -322,6 +328,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
string strAddress = params[0].get_str();
|
||||
|
@ -351,6 +359,8 @@ Value dumpwallet(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("dumpwallet", "\"test\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
ofstream file;
|
||||
|
|
|
@ -88,6 +88,7 @@ Value getnetworkhashps(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getnetworkhashps", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
|
||||
}
|
||||
|
||||
|
@ -107,6 +108,7 @@ Value getgenerate(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getgenerate", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
return GetBoolArg("-gen", false);
|
||||
}
|
||||
|
||||
|
@ -200,7 +202,6 @@ Value setgenerate(const Array& params, bool fHelp)
|
|||
|
||||
return Value::null;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -228,6 +229,9 @@ Value getmininginfo(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getmininginfo", "")
|
||||
);
|
||||
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
Object obj;
|
||||
obj.push_back(Pair("blocks", (int)chainActive.Height()));
|
||||
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
|
||||
|
@ -268,8 +272,9 @@ Value prioritisetransaction(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
|
||||
);
|
||||
|
||||
uint256 hash = ParseHashStr(params[0].get_str(), "txid");
|
||||
LOCK(cs_main);
|
||||
|
||||
uint256 hash = ParseHashStr(params[0].get_str(), "txid");
|
||||
CAmount nAmount = params[2].get_int64();
|
||||
|
||||
mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
|
||||
|
@ -358,6 +363,8 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getblocktemplate", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
std::string strMode = "template";
|
||||
Value lpval = Value::null;
|
||||
if (params.size() > 0)
|
||||
|
@ -439,10 +446,6 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||
}
|
||||
|
||||
// Release the wallet and main lock while waiting
|
||||
#ifdef ENABLE_WALLET
|
||||
if(pwalletMain)
|
||||
LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet);
|
||||
#endif
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
{
|
||||
checktxtime = boost::get_system_time() + boost::posix_time::minutes(1);
|
||||
|
@ -460,10 +463,6 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||
}
|
||||
}
|
||||
ENTER_CRITICAL_SECTION(cs_main);
|
||||
#ifdef ENABLE_WALLET
|
||||
if(pwalletMain)
|
||||
ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet);
|
||||
#endif
|
||||
|
||||
if (!IsRPCRunning())
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
|
||||
|
|
|
@ -69,6 +69,12 @@ Value getinfo(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getinfo", "")
|
||||
);
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
|
||||
#else
|
||||
LOCK(cs_main);
|
||||
#endif
|
||||
|
||||
proxyType proxy;
|
||||
GetProxy(NET_IPV4, proxy);
|
||||
|
||||
|
@ -172,6 +178,12 @@ Value validateaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
|
||||
);
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
|
||||
#else
|
||||
LOCK(cs_main);
|
||||
#endif
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
bool isValid = address.IsValid();
|
||||
|
||||
|
@ -329,6 +341,8 @@ Value verifymessage(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
string strAddress = params[0].get_str();
|
||||
string strSign = params[1].get_str();
|
||||
string strMessage = params[2].get_str();
|
||||
|
@ -372,6 +386,8 @@ Value setmocktime(const Array& params, bool fHelp)
|
|||
if (!Params().MineBlocksOnDemand())
|
||||
throw runtime_error("setmocktime for regression testing (-regtest mode) only");
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
RPCTypeCheck(params, boost::assign::list_of(int_type));
|
||||
SetMockTime(params[0].get_int64());
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ Value getconnectioncount(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getconnectioncount", "")
|
||||
);
|
||||
|
||||
LOCK(cs_vNodes);
|
||||
LOCK2(cs_main, cs_vNodes);
|
||||
|
||||
return (int)vNodes.size();
|
||||
}
|
||||
|
||||
|
@ -52,7 +53,8 @@ Value ping(const Array& params, bool fHelp)
|
|||
);
|
||||
|
||||
// Request that each node send a ping during next message processing pass
|
||||
LOCK(cs_vNodes);
|
||||
LOCK2(cs_main, cs_vNodes);
|
||||
|
||||
BOOST_FOREACH(CNode* pNode, vNodes) {
|
||||
pNode->fPingQueued = true;
|
||||
}
|
||||
|
@ -113,6 +115,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getpeerinfo", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
vector<CNodeStats> vstats;
|
||||
CopyNodeStats(vstats);
|
||||
|
||||
|
@ -411,6 +415,8 @@ Value getnetworkinfo(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getnetworkinfo", "")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
Object obj;
|
||||
obj.push_back(Pair("version", CLIENT_VERSION));
|
||||
obj.push_back(Pair("subversion",
|
||||
|
|
|
@ -169,6 +169,8 @@ Value getrawtransaction(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
uint256 hash = ParseHashV(params[0], "parameter 1");
|
||||
|
||||
bool fVerbose = false;
|
||||
|
@ -256,6 +258,7 @@ Value listunspent(const Array& params, bool fHelp)
|
|||
Array results;
|
||||
vector<COutput> vecOutputs;
|
||||
assert(pwalletMain != NULL);
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false);
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs) {
|
||||
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
|
||||
|
@ -334,6 +337,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type));
|
||||
|
||||
Array inputs = params[0].get_array();
|
||||
|
@ -428,6 +432,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
RPCTypeCheck(params, boost::assign::list_of(str_type));
|
||||
|
||||
CTransaction tx;
|
||||
|
@ -466,6 +471,7 @@ Value decodescript(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("decodescript", "\"hexstring\"")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
RPCTypeCheck(params, boost::assign::list_of(str_type));
|
||||
|
||||
Object r;
|
||||
|
@ -532,6 +538,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
|
||||
);
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
|
||||
#else
|
||||
LOCK(cs_main);
|
||||
#endif
|
||||
RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true);
|
||||
|
||||
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
|
||||
|
@ -591,7 +602,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|||
}
|
||||
}
|
||||
#ifdef ENABLE_WALLET
|
||||
else
|
||||
else if (pwalletMain)
|
||||
EnsureWalletIsUnlocked();
|
||||
#endif
|
||||
|
||||
|
@ -688,7 +699,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
|||
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
|
||||
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
|
||||
}
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i)))
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
|
||||
fComplete = false;
|
||||
}
|
||||
|
||||
|
@ -722,6 +733,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type));
|
||||
|
||||
// parse hex string from parameter
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
#include "base58.h"
|
||||
#include "init.h"
|
||||
#include "main.h"
|
||||
#include "random.h"
|
||||
#include "sync.h"
|
||||
#include "ui_interface.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet.h"
|
||||
#endif
|
||||
|
@ -23,11 +25,13 @@
|
|||
#include <boost/iostreams/concepts.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/signals2/signal.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include "json/json_spirit_writer_template.h"
|
||||
|
||||
using namespace boost::asio;
|
||||
using namespace json_spirit;
|
||||
using namespace RPCServer;
|
||||
using namespace std;
|
||||
|
||||
static std::string strRPCUserColonPass;
|
||||
|
@ -46,6 +50,34 @@ static boost::asio::io_service::work *rpc_dummy_work = NULL;
|
|||
static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
|
||||
static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors;
|
||||
|
||||
static struct CRPCSignals
|
||||
{
|
||||
boost::signals2::signal<void ()> Started;
|
||||
boost::signals2::signal<void ()> Stopped;
|
||||
boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
|
||||
boost::signals2::signal<void (const CRPCCommand&)> PostCommand;
|
||||
} g_rpcSignals;
|
||||
|
||||
void RPCServer::OnStarted(boost::function<void ()> slot)
|
||||
{
|
||||
g_rpcSignals.Started.connect(slot);
|
||||
}
|
||||
|
||||
void RPCServer::OnStopped(boost::function<void ()> slot)
|
||||
{
|
||||
g_rpcSignals.Stopped.connect(slot);
|
||||
}
|
||||
|
||||
void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot)
|
||||
{
|
||||
g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
|
||||
}
|
||||
|
||||
void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
|
||||
{
|
||||
g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
|
||||
}
|
||||
|
||||
void RPCTypeCheck(const Array& params,
|
||||
const list<Value_type>& typesExpected,
|
||||
bool fAllowNull)
|
||||
|
@ -239,116 +271,114 @@ Value stop(const Array& params, bool fHelp)
|
|||
* Call Table
|
||||
*/
|
||||
static const CRPCCommand vRPCCommands[] =
|
||||
{ // category name actor (function) okSafeMode threadSafe reqWallet
|
||||
// --------------------- ------------------------ ----------------------- ---------- ---------- ---------
|
||||
{ // category name actor (function) okSafeMode reqWallet
|
||||
// --------------------- ------------------------ ----------------------- ---------- ---------
|
||||
/* Overall control/query calls */
|
||||
{ "control", "getinfo", &getinfo, true, false, false }, /* uses wallet if enabled */
|
||||
{ "control", "help", &help, true, true, false },
|
||||
{ "control", "stop", &stop, true, true, false },
|
||||
{ "control", "getinfo", &getinfo, true, false }, /* uses wallet if enabled */
|
||||
{ "control", "help", &help, true, false },
|
||||
{ "control", "stop", &stop, true, false },
|
||||
|
||||
/* P2P networking */
|
||||
{ "network", "getnetworkinfo", &getnetworkinfo, true, false, false },
|
||||
{ "network", "addnode", &addnode, true, true, false },
|
||||
{ "network", "getaddednodeinfo", &getaddednodeinfo, true, true, false },
|
||||
{ "network", "getconnectioncount", &getconnectioncount, true, false, false },
|
||||
{ "network", "getnettotals", &getnettotals, true, true, false },
|
||||
{ "network", "getpeerinfo", &getpeerinfo, true, false, false },
|
||||
{ "network", "ping", &ping, true, false, false },
|
||||
{ "network", "getnetworkinfo", &getnetworkinfo, true, false },
|
||||
{ "network", "addnode", &addnode, true, false },
|
||||
{ "network", "getaddednodeinfo", &getaddednodeinfo, true, false },
|
||||
{ "network", "getconnectioncount", &getconnectioncount, true, false },
|
||||
{ "network", "getnettotals", &getnettotals, true, false },
|
||||
{ "network", "getpeerinfo", &getpeerinfo, true, false },
|
||||
{ "network", "ping", &ping, true, false },
|
||||
|
||||
/* Block chain and UTXO */
|
||||
{ "blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false },
|
||||
{ "blockchain", "getbestblockhash", &getbestblockhash, true, false, false },
|
||||
{ "blockchain", "getblockcount", &getblockcount, true, false, false },
|
||||
{ "blockchain", "getblock", &getblock, true, false, false },
|
||||
{ "blockchain", "getblockhash", &getblockhash, true, false, false },
|
||||
{ "blockchain", "getchaintips", &getchaintips, true, false, false },
|
||||
{ "blockchain", "getdifficulty", &getdifficulty, true, false, false },
|
||||
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false },
|
||||
{ "blockchain", "getrawmempool", &getrawmempool, true, false, false },
|
||||
{ "blockchain", "gettxout", &gettxout, true, false, false },
|
||||
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
|
||||
{ "blockchain", "verifychain", &verifychain, true, false, false },
|
||||
{ "blockchain", "invalidateblock", &invalidateblock, true, true, false },
|
||||
{ "blockchain", "reconsiderblock", &reconsiderblock, true, true, false },
|
||||
{ "blockchain", "getblockchaininfo", &getblockchaininfo, true, false },
|
||||
{ "blockchain", "getbestblockhash", &getbestblockhash, true, false },
|
||||
{ "blockchain", "getblockcount", &getblockcount, true, false },
|
||||
{ "blockchain", "getblock", &getblock, true, false },
|
||||
{ "blockchain", "getblockhash", &getblockhash, true, false },
|
||||
{ "blockchain", "getchaintips", &getchaintips, true, false },
|
||||
{ "blockchain", "getdifficulty", &getdifficulty, true, false },
|
||||
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true, false },
|
||||
{ "blockchain", "getrawmempool", &getrawmempool, true, false },
|
||||
{ "blockchain", "gettxout", &gettxout, true, false },
|
||||
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false },
|
||||
{ "blockchain", "verifychain", &verifychain, true, false },
|
||||
|
||||
/* Mining */
|
||||
{ "mining", "getblocktemplate", &getblocktemplate, true, false, false },
|
||||
{ "mining", "getmininginfo", &getmininginfo, true, false, false },
|
||||
{ "mining", "getnetworkhashps", &getnetworkhashps, true, false, false },
|
||||
{ "mining", "prioritisetransaction", &prioritisetransaction, true, false, false },
|
||||
{ "mining", "submitblock", &submitblock, true, true, false },
|
||||
{ "mining", "getblocktemplate", &getblocktemplate, true, false },
|
||||
{ "mining", "getmininginfo", &getmininginfo, true, false },
|
||||
{ "mining", "getnetworkhashps", &getnetworkhashps, true, false },
|
||||
{ "mining", "prioritisetransaction", &prioritisetransaction, true, false },
|
||||
{ "mining", "submitblock", &submitblock, true, false },
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
/* Coin generation */
|
||||
{ "generating", "getgenerate", &getgenerate, true, false, false },
|
||||
{ "generating", "setgenerate", &setgenerate, true, true, false },
|
||||
{ "generating", "getgenerate", &getgenerate, true, false },
|
||||
{ "generating", "setgenerate", &setgenerate, true, false },
|
||||
#endif
|
||||
|
||||
/* Raw transactions */
|
||||
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true, false, false },
|
||||
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false, false },
|
||||
{ "rawtransactions", "decodescript", &decodescript, true, false, false },
|
||||
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true, false, false },
|
||||
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false, false },
|
||||
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false, false, false }, /* uses wallet if enabled */
|
||||
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true, false },
|
||||
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false },
|
||||
{ "rawtransactions", "decodescript", &decodescript, true, false },
|
||||
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true, false },
|
||||
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false },
|
||||
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false, false }, /* uses wallet if enabled */
|
||||
|
||||
/* Utility functions */
|
||||
{ "util", "createmultisig", &createmultisig, true, true , false },
|
||||
{ "util", "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */
|
||||
{ "util", "verifymessage", &verifymessage, true, false, false },
|
||||
{ "util", "estimatefee", &estimatefee, true, true, false },
|
||||
{ "util", "estimatepriority", &estimatepriority, true, true, false },
|
||||
{ "util", "createmultisig", &createmultisig, true, false },
|
||||
{ "util", "validateaddress", &validateaddress, true, false }, /* uses wallet if enabled */
|
||||
{ "util", "verifymessage", &verifymessage, true, false },
|
||||
{ "util", "estimatefee", &estimatefee, true, false },
|
||||
{ "util", "estimatepriority", &estimatepriority, true, false },
|
||||
|
||||
/* Not shown in help */
|
||||
{ "hidden", "invalidateblock", &invalidateblock, true, true, false },
|
||||
{ "hidden", "reconsiderblock", &reconsiderblock, true, true, false },
|
||||
{ "hidden", "setmocktime", &setmocktime, true, false, false },
|
||||
{ "hidden", "invalidateblock", &invalidateblock, true, false },
|
||||
{ "hidden", "reconsiderblock", &reconsiderblock, true, false },
|
||||
{ "hidden", "setmocktime", &setmocktime, true, false },
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
/* Wallet */
|
||||
{ "wallet", "addmultisigaddress", &addmultisigaddress, true, false, true },
|
||||
{ "wallet", "backupwallet", &backupwallet, true, false, true },
|
||||
{ "wallet", "dumpprivkey", &dumpprivkey, true, false, true },
|
||||
{ "wallet", "dumpwallet", &dumpwallet, true, false, true },
|
||||
{ "wallet", "encryptwallet", &encryptwallet, true, false, true },
|
||||
{ "wallet", "getaccountaddress", &getaccountaddress, true, false, true },
|
||||
{ "wallet", "getaccount", &getaccount, true, false, true },
|
||||
{ "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, false, true },
|
||||
{ "wallet", "getbalance", &getbalance, false, false, true },
|
||||
{ "wallet", "getnewaddress", &getnewaddress, true, false, true },
|
||||
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, true, false, true },
|
||||
{ "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
|
||||
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
|
||||
{ "wallet", "gettransaction", &gettransaction, false, false, true },
|
||||
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, false, true },
|
||||
{ "wallet", "getwalletinfo", &getwalletinfo, false, false, true },
|
||||
{ "wallet", "importprivkey", &importprivkey, true, false, true },
|
||||
{ "wallet", "importwallet", &importwallet, true, false, true },
|
||||
{ "wallet", "importaddress", &importaddress, true, false, true },
|
||||
{ "wallet", "keypoolrefill", &keypoolrefill, true, false, true },
|
||||
{ "wallet", "listaccounts", &listaccounts, false, false, true },
|
||||
{ "wallet", "listaddressgroupings", &listaddressgroupings, false, false, true },
|
||||
{ "wallet", "listlockunspent", &listlockunspent, false, false, true },
|
||||
{ "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
|
||||
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
|
||||
{ "wallet", "listsinceblock", &listsinceblock, false, false, true },
|
||||
{ "wallet", "listtransactions", &listtransactions, false, false, true },
|
||||
{ "wallet", "listunspent", &listunspent, false, false, true },
|
||||
{ "wallet", "lockunspent", &lockunspent, true, false, true },
|
||||
{ "wallet", "move", &movecmd, false, false, true },
|
||||
{ "wallet", "sendfrom", &sendfrom, false, false, true },
|
||||
{ "wallet", "sendmany", &sendmany, false, false, true },
|
||||
{ "wallet", "claimname", &claimname, false, false, true },
|
||||
{ "wallet", "listnameclaims", &listnameclaims, false, false, true },
|
||||
{ "wallet", "updatename", &updatename, false, false, true },
|
||||
{ "wallet", "abandonname", &abandonname, false, false, true },
|
||||
{ "wallet", "sendtoaddress", &sendtoaddress, false, false, true },
|
||||
{ "wallet", "setaccount", &setaccount, true, false, true },
|
||||
{ "wallet", "settxfee", &settxfee, true, false, true },
|
||||
{ "wallet", "signmessage", &signmessage, true, false, true },
|
||||
{ "wallet", "walletlock", &walletlock, true, false, true },
|
||||
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, true, false, true },
|
||||
{ "wallet", "walletpassphrase", &walletpassphrase, true, false, true },
|
||||
{ "wallet", "addmultisigaddress", &addmultisigaddress, true, true },
|
||||
{ "wallet", "backupwallet", &backupwallet, true, true },
|
||||
{ "wallet", "dumpprivkey", &dumpprivkey, true, true },
|
||||
{ "wallet", "dumpwallet", &dumpwallet, true, true },
|
||||
{ "wallet", "encryptwallet", &encryptwallet, true, true },
|
||||
{ "wallet", "getaccountaddress", &getaccountaddress, true, true },
|
||||
{ "wallet", "getaccount", &getaccount, true, true },
|
||||
{ "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, true },
|
||||
{ "wallet", "getbalance", &getbalance, false, true },
|
||||
{ "wallet", "getnewaddress", &getnewaddress, true, true },
|
||||
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, true, true },
|
||||
{ "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, true },
|
||||
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, true },
|
||||
{ "wallet", "gettransaction", &gettransaction, false, true },
|
||||
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, true },
|
||||
{ "wallet", "getwalletinfo", &getwalletinfo, false, true },
|
||||
{ "wallet", "importprivkey", &importprivkey, true, true },
|
||||
{ "wallet", "importwallet", &importwallet, true, true },
|
||||
{ "wallet", "importaddress", &importaddress, true, true },
|
||||
{ "wallet", "keypoolrefill", &keypoolrefill, true, true },
|
||||
{ "wallet", "listaccounts", &listaccounts, false, true },
|
||||
{ "wallet", "listaddressgroupings", &listaddressgroupings, false, true },
|
||||
{ "wallet", "listlockunspent", &listlockunspent, false, true },
|
||||
{ "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, true },
|
||||
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, true },
|
||||
{ "wallet", "listsinceblock", &listsinceblock, false, true },
|
||||
{ "wallet", "listtransactions", &listtransactions, false, true },
|
||||
{ "wallet", "listunspent", &listunspent, false, true },
|
||||
{ "wallet", "lockunspent", &lockunspent, true, true },
|
||||
{ "wallet", "move", &movecmd, false, true },
|
||||
{ "wallet", "sendfrom", &sendfrom, false, true },
|
||||
{ "wallet", "sendmany", &sendmany, false, true },
|
||||
{ "wallet", "claimname", &claimname, false, true },
|
||||
{ "wallet", "listnameclaims", &listnameclaims, false, true },
|
||||
{ "wallet", "updatename", &updatename, false, true },
|
||||
{ "wallet", "abandonname", &abandonname, false, true },
|
||||
{ "wallet", "sendtoaddress", &sendtoaddress, false, true },
|
||||
{ "wallet", "setaccount", &setaccount, true, true },
|
||||
{ "wallet", "settxfee", &settxfee, true, true },
|
||||
{ "wallet", "signmessage", &signmessage, true, true },
|
||||
{ "wallet", "walletlock", &walletlock, true, true },
|
||||
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, true, true },
|
||||
{ "wallet", "walletpassphrase", &walletpassphrase, true, true },
|
||||
#endif // ENABLE_WALLET
|
||||
};
|
||||
|
||||
|
@ -697,6 +727,7 @@ void StartRPCThreads()
|
|||
for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
|
||||
rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service));
|
||||
fRPCRunning = true;
|
||||
g_rpcSignals.Started();
|
||||
}
|
||||
|
||||
void StartDummyRPCThread()
|
||||
|
@ -739,7 +770,7 @@ void StopRPCThreads()
|
|||
deadlineTimers.clear();
|
||||
|
||||
rpc_io_service->stop();
|
||||
cvBlockChange.notify_all();
|
||||
g_rpcSignals.Stopped();
|
||||
if (rpc_worker_group != NULL)
|
||||
rpc_worker_group->join_all();
|
||||
delete rpc_dummy_work; rpc_dummy_work = NULL;
|
||||
|
@ -982,45 +1013,20 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
|
|||
const CRPCCommand *pcmd = tableRPC[strMethod];
|
||||
if (!pcmd)
|
||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pcmd->reqWallet && !pwalletMain)
|
||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
|
||||
#endif
|
||||
|
||||
// Observe safe mode
|
||||
string strWarning = GetWarnings("rpc");
|
||||
if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
|
||||
!pcmd->okSafeMode)
|
||||
throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
|
||||
g_rpcSignals.PreCommand(*pcmd);
|
||||
|
||||
try
|
||||
{
|
||||
// Execute
|
||||
Value result;
|
||||
{
|
||||
if (pcmd->threadSafe)
|
||||
result = pcmd->actor(params, false);
|
||||
#ifdef ENABLE_WALLET
|
||||
else if (!pwalletMain) {
|
||||
LOCK(cs_main);
|
||||
result = pcmd->actor(params, false);
|
||||
} else {
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
result = pcmd->actor(params, false);
|
||||
}
|
||||
#else // ENABLE_WALLET
|
||||
else {
|
||||
LOCK(cs_main);
|
||||
result = pcmd->actor(params, false);
|
||||
}
|
||||
#endif // !ENABLE_WALLET
|
||||
}
|
||||
return result;
|
||||
return pcmd->actor(params, false);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw JSONRPCError(RPC_MISC_ERROR, e.what());
|
||||
}
|
||||
|
||||
g_rpcSignals.PostCommand(*pcmd);
|
||||
}
|
||||
|
||||
std::string HelpExampleCli(string methodname, string args){
|
||||
|
|
|
@ -19,6 +19,16 @@
|
|||
#include "json/json_spirit_utils.h"
|
||||
#include "json/json_spirit_writer_template.h"
|
||||
|
||||
class CRPCCommand;
|
||||
|
||||
namespace RPCServer
|
||||
{
|
||||
void OnStarted(boost::function<void ()> slot);
|
||||
void OnStopped(boost::function<void ()> slot);
|
||||
void OnPreCommand(boost::function<void (const CRPCCommand&)> slot);
|
||||
void OnPostCommand(boost::function<void (const CRPCCommand&)> slot);
|
||||
}
|
||||
|
||||
class CBlockIndex;
|
||||
class CNetAddr;
|
||||
|
||||
|
@ -88,7 +98,6 @@ public:
|
|||
std::string name;
|
||||
rpcfn_type actor;
|
||||
bool okSafeMode;
|
||||
bool threadSafe;
|
||||
bool reqWallet;
|
||||
};
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ Value getnewaddress(const Array& params, bool fHelp)
|
|||
"If 'account' is specified (DEPRECATED), it is added to the address book \n"
|
||||
"so payments received with the address will be credited to 'account'.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. if not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
|
||||
"1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
|
||||
"\nResult:\n"
|
||||
"\"bitcoinaddress\" (string) The new bitcoin address\n"
|
||||
"\nExamples:\n"
|
||||
|
@ -91,6 +91,8 @@ Value getnewaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getnewaddress", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Parse the account first so we don't generate a key if there's an error
|
||||
string strAccount;
|
||||
if (params.size() > 0)
|
||||
|
@ -165,13 +167,14 @@ Value getaccountaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getaccountaddress", "\"myaccount\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Parse the account first so we don't generate a key if there's an error
|
||||
string strAccount = AccountFromValue(params[0]);
|
||||
|
||||
Value ret;
|
||||
|
||||
ret = GetAccountAddress(strAccount).ToString();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -190,6 +193,8 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getrawchangeaddress", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (!pwalletMain->IsLocked())
|
||||
pwalletMain->TopUpKeyPool();
|
||||
|
||||
|
@ -220,11 +225,12 @@ Value setaccount(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
|
||||
|
||||
string strAccount;
|
||||
if (params.size() > 1)
|
||||
strAccount = AccountFromValue(params[1]);
|
||||
|
@ -263,6 +269,8 @@ Value getaccount(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
|
@ -293,6 +301,8 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strAccount = AccountFromValue(params[0]);
|
||||
|
||||
// Find all addresses that have the given account
|
||||
|
@ -731,6 +741,8 @@ Value sendtoaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
|
@ -777,6 +789,8 @@ Value listaddressgroupings(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("listaddressgroupings", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
Array jsonGroupings;
|
||||
map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
|
||||
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
|
||||
|
@ -822,6 +836,8 @@ Value signmessage(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
string strAddress = params[0].get_str();
|
||||
|
@ -872,6 +888,8 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Bitcoin address
|
||||
CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
|
@ -925,6 +943,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Minimum confirmations
|
||||
int nMinDepth = 1;
|
||||
if (params.size() > 1)
|
||||
|
@ -1011,6 +1031,8 @@ Value getbalance(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getbalance", "\"*\", 6")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (params.size() == 0)
|
||||
return ValueFromAmount(pwalletMain->GetBalance());
|
||||
|
||||
|
@ -1063,6 +1085,9 @@ Value getunconfirmedbalance(const Array ¶ms, bool fHelp)
|
|||
throw runtime_error(
|
||||
"getunconfirmedbalance\n"
|
||||
"Returns the server's total unconfirmed balance\n");
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
|
||||
}
|
||||
|
||||
|
@ -1089,6 +1114,8 @@ Value movecmd(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strFrom = AccountFromValue(params[0]);
|
||||
string strTo = AccountFromValue(params[1]);
|
||||
CAmount nAmount = AmountFromValue(params[2]);
|
||||
|
@ -1161,6 +1188,8 @@ Value sendfrom(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strAccount = AccountFromValue(params[0]);
|
||||
CBitcoinAddress address(params[1].get_str());
|
||||
if (!address.IsValid())
|
||||
|
@ -1218,6 +1247,8 @@ Value sendmany(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strAccount = AccountFromValue(params[0]);
|
||||
Object sendTo = params[1].get_obj();
|
||||
int nMinDepth = 1;
|
||||
|
@ -1303,6 +1334,8 @@ Value addmultisigaddress(const Array& params, bool fHelp)
|
|||
throw runtime_error(msg);
|
||||
}
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strAccount;
|
||||
if (params.size() > 2)
|
||||
strAccount = AccountFromValue(params[2]);
|
||||
|
@ -1478,6 +1511,8 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
return ListReceived(params, false);
|
||||
}
|
||||
|
||||
|
@ -1509,6 +1544,8 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
return ListReceived(params, true);
|
||||
}
|
||||
|
||||
|
@ -1660,6 +1697,8 @@ Value listtransactions(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strAccount = "*";
|
||||
if (params.size() > 0)
|
||||
strAccount = params[0].get_str();
|
||||
|
@ -1740,6 +1779,8 @@ Value listaccounts(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("listaccounts", "6")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
int nMinDepth = 1;
|
||||
if (params.size() > 0)
|
||||
nMinDepth = params[0].get_int();
|
||||
|
@ -1828,6 +1869,8 @@ Value listsinceblock(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
CBlockIndex *pindex = NULL;
|
||||
int target_confirms = 1;
|
||||
isminefilter filter = ISMINE_SPENDABLE;
|
||||
|
@ -1914,6 +1957,8 @@ Value gettransaction(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
uint256 hash;
|
||||
hash.SetHex(params[0].get_str());
|
||||
|
||||
|
@ -1962,6 +2007,8 @@ Value backupwallet(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strDest = params[0].get_str();
|
||||
if (!BackupWallet(*pwalletMain, strDest))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
|
||||
|
@ -1984,6 +2031,8 @@ Value keypoolrefill(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("keypoolrefill", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
|
||||
unsigned int kpSize = 0;
|
||||
if (params.size() > 0) {
|
||||
|
@ -2031,6 +2080,8 @@ Value walletpassphrase(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (fHelp)
|
||||
return true;
|
||||
if (!pwalletMain->IsCrypted())
|
||||
|
@ -2078,6 +2129,8 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (fHelp)
|
||||
return true;
|
||||
if (!pwalletMain->IsCrypted())
|
||||
|
@ -2124,6 +2177,8 @@ Value walletlock(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("walletlock", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (fHelp)
|
||||
return true;
|
||||
if (!pwalletMain->IsCrypted())
|
||||
|
@ -2165,6 +2220,8 @@ Value encryptwallet(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (fHelp)
|
||||
return true;
|
||||
if (pwalletMain->IsCrypted())
|
||||
|
@ -2229,6 +2286,8 @@ Value lockunspent(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
if (params.size() == 1)
|
||||
RPCTypeCheck(params, boost::assign::list_of(bool_type));
|
||||
else
|
||||
|
@ -2298,6 +2357,8 @@ Value listlockunspent(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("listlockunspent", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
vector<COutPoint> vOutpts;
|
||||
pwalletMain->ListLockedCoins(vOutpts);
|
||||
|
||||
|
@ -2329,6 +2390,8 @@ Value settxfee(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("settxfee", "0.00001")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
// Amount
|
||||
CAmount nAmount = 0;
|
||||
if (params[0].get_real() != 0.0)
|
||||
|
@ -2360,6 +2423,8 @@ Value getwalletinfo(const Array& params, bool fHelp)
|
|||
+ HelpExampleRpc("getwalletinfo", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
Object obj;
|
||||
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
|
||||
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
|
||||
|
|
|
@ -78,7 +78,7 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i
|
|||
// Regardless of the verification result, the tx did not error.
|
||||
set_error(err, bitcoinconsensus_ERR_OK);
|
||||
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, SignatureChecker(tx, nIn), NULL);
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL);
|
||||
} catch (const std::exception&) {
|
||||
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ enum
|
|||
{
|
||||
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
|
||||
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
|
||||
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
|
||||
};
|
||||
|
||||
/// Returns 1 if the input nIn of the serialized transaction pointed to by
|
||||
|
|
|
@ -93,76 +93,76 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
|
|||
* in which case a single 0 byte is necessary and even required).
|
||||
*
|
||||
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
||||
*
|
||||
* This function is consensus-critical since BIP66.
|
||||
*/
|
||||
bool static IsDERSignature(const valtype &vchSig) {
|
||||
bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
|
||||
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
|
||||
// * total-length: 1-byte length descriptor of everything that follows,
|
||||
// excluding the sighash byte.
|
||||
// * R-length: 1-byte length descriptor of the R value that follows.
|
||||
// * R: arbitrary-length big-endian encoded R value. It must use the shortest
|
||||
// possible encoding for a positive integers (which means no null bytes at
|
||||
// the start, except a single one when the next byte has its highest bit set).
|
||||
// * S-length: 1-byte length descriptor of the S value that follows.
|
||||
// * S: arbitrary-length big-endian encoded S value. The same rules apply.
|
||||
// * sighash: 1-byte value indicating what data is hashed (not part of the DER
|
||||
// signature)
|
||||
|
||||
if (vchSig.size() < 9) {
|
||||
// Non-canonical signature: too short
|
||||
return false;
|
||||
}
|
||||
if (vchSig.size() > 73) {
|
||||
// Non-canonical signature: too long
|
||||
return false;
|
||||
}
|
||||
if (vchSig[0] != 0x30) {
|
||||
// Non-canonical signature: wrong type
|
||||
return false;
|
||||
}
|
||||
if (vchSig[1] != vchSig.size()-3) {
|
||||
// Non-canonical signature: wrong length marker
|
||||
return false;
|
||||
}
|
||||
unsigned int nLenR = vchSig[3];
|
||||
if (5 + nLenR >= vchSig.size()) {
|
||||
// Non-canonical signature: S length misplaced
|
||||
return false;
|
||||
}
|
||||
unsigned int nLenS = vchSig[5+nLenR];
|
||||
if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) {
|
||||
// Non-canonical signature: R+S length mismatch
|
||||
return false;
|
||||
}
|
||||
// Minimum and maximum size constraints.
|
||||
if (sig.size() < 9) return false;
|
||||
if (sig.size() > 73) return false;
|
||||
|
||||
const unsigned char *R = &vchSig[4];
|
||||
if (R[-2] != 0x02) {
|
||||
// Non-canonical signature: R value type mismatch
|
||||
return false;
|
||||
}
|
||||
if (nLenR == 0) {
|
||||
// Non-canonical signature: R length is zero
|
||||
return false;
|
||||
}
|
||||
if (R[0] & 0x80) {
|
||||
// Non-canonical signature: R value negative
|
||||
return false;
|
||||
}
|
||||
if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) {
|
||||
// Non-canonical signature: R value excessively padded
|
||||
return false;
|
||||
}
|
||||
// A signature is of type 0x30 (compound).
|
||||
if (sig[0] != 0x30) return false;
|
||||
|
||||
// Make sure the length covers the entire signature.
|
||||
if (sig[1] != sig.size() - 3) return false;
|
||||
|
||||
// Extract the length of the R element.
|
||||
unsigned int lenR = sig[3];
|
||||
|
||||
// Make sure the length of the S element is still inside the signature.
|
||||
if (5 + lenR >= sig.size()) return false;
|
||||
|
||||
// Extract the length of the S element.
|
||||
unsigned int lenS = sig[5 + lenR];
|
||||
|
||||
// Verify that the length of the signature matches the sum of the length
|
||||
// of the elements.
|
||||
if ((size_t)(lenR + lenS + 7) != sig.size()) return false;
|
||||
|
||||
// Check whether the R element is an integer.
|
||||
if (sig[2] != 0x02) return false;
|
||||
|
||||
// Zero-length integers are not allowed for R.
|
||||
if (lenR == 0) return false;
|
||||
|
||||
// Negative numbers are not allowed for R.
|
||||
if (sig[4] & 0x80) return false;
|
||||
|
||||
// Null bytes at the start of R are not allowed, unless R would
|
||||
// otherwise be interpreted as a negative number.
|
||||
if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;
|
||||
|
||||
// Check whether the S element is an integer.
|
||||
if (sig[lenR + 4] != 0x02) return false;
|
||||
|
||||
// Zero-length integers are not allowed for S.
|
||||
if (lenS == 0) return false;
|
||||
|
||||
// Negative numbers are not allowed for S.
|
||||
if (sig[lenR + 6] & 0x80) return false;
|
||||
|
||||
// Null bytes at the start of S are not allowed, unless S would otherwise be
|
||||
// interpreted as a negative number.
|
||||
if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false;
|
||||
|
||||
const unsigned char *S = &vchSig[6+nLenR];
|
||||
if (S[-2] != 0x02) {
|
||||
// Non-canonical signature: S value type mismatch
|
||||
return false;
|
||||
}
|
||||
if (nLenS == 0) {
|
||||
// Non-canonical signature: S length is zero
|
||||
return false;
|
||||
}
|
||||
if (S[0] & 0x80) {
|
||||
// Non-canonical signature: S value negative
|
||||
return false;
|
||||
}
|
||||
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) {
|
||||
// Non-canonical signature: S value excessively padded
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
|
||||
if (!IsDERSignature(vchSig)) {
|
||||
if (!IsValidSignatureEncoding(vchSig)) {
|
||||
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
||||
}
|
||||
unsigned int nLenR = vchSig[3];
|
||||
|
@ -194,7 +194,7 @@ bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, Sc
|
|||
if (vchSig.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) {
|
||||
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) {
|
||||
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
||||
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
|
||||
// serror is set
|
||||
|
@ -1058,12 +1058,12 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
|
|||
return ss.GetHash();
|
||||
}
|
||||
|
||||
bool SignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
return pubkey.Verify(sighash, vchSig);
|
||||
}
|
||||
|
||||
bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
||||
bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
||||
{
|
||||
CPubKey pubkey(vchPubKey);
|
||||
if (!pubkey.IsValid())
|
||||
|
@ -1076,7 +1076,7 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
|
|||
int nHashType = vchSig.back();
|
||||
vchSig.pop_back();
|
||||
|
||||
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
|
||||
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
|
||||
|
||||
if (!VerifySignature(vchSig, pubkey, sighash))
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define BITCOIN_SCRIPT_INTERPRETER_H
|
||||
|
||||
#include "script_error.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
@ -90,20 +91,29 @@ public:
|
|||
virtual ~BaseSignatureChecker() {}
|
||||
};
|
||||
|
||||
class SignatureChecker : public BaseSignatureChecker
|
||||
class TransactionSignatureChecker : public BaseSignatureChecker
|
||||
{
|
||||
private:
|
||||
const CTransaction& txTo;
|
||||
const CTransaction* txTo;
|
||||
unsigned int nIn;
|
||||
|
||||
protected:
|
||||
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
|
||||
public:
|
||||
SignatureChecker(const CTransaction& txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
|
||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
|
||||
};
|
||||
|
||||
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
const CTransaction txTo;
|
||||
|
||||
public:
|
||||
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {}
|
||||
};
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
|
||||
|
||||
|
|
|
@ -74,14 +74,14 @@ public:
|
|||
|
||||
}
|
||||
|
||||
bool CachingSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
static CSignatureCache signatureCache;
|
||||
|
||||
if (signatureCache.Get(sighash, vchSig, pubkey))
|
||||
return true;
|
||||
|
||||
if (!SignatureChecker::VerifySignature(vchSig, pubkey, sighash))
|
||||
if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
|
||||
return false;
|
||||
|
||||
if (store)
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
|
||||
class CPubKey;
|
||||
|
||||
class CachingSignatureChecker : public SignatureChecker
|
||||
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
bool store;
|
||||
|
||||
public:
|
||||
CachingSignatureChecker(const CTransaction& txToIn, unsigned int nInIn, bool storeIn=true) : SignatureChecker(txToIn, nInIn), store(storeIn) {}
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {}
|
||||
|
||||
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
};
|
||||
|
|
|
@ -125,7 +125,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl
|
|||
}
|
||||
|
||||
// Test solution
|
||||
return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(txTo, nIn));
|
||||
return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn));
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
|
@ -176,7 +176,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction&
|
|||
if (sigs.count(pubkey))
|
||||
continue; // Already got a sig for this pubkey
|
||||
|
||||
if (SignatureChecker(txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
|
||||
if (TransactionSignatureChecker(&txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
|
||||
{
|
||||
sigs[pubkey] = sig;
|
||||
break;
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
};
|
||||
|
||||
static const unsigned int MAX_OP_RETURN_RELAY = 40; //! bytes
|
||||
static const unsigned int MAX_OP_RETURN_RELAY = 80; //! bytes
|
||||
extern unsigned nMaxDatacarrierBytes;
|
||||
|
||||
/**
|
||||
|
@ -45,6 +45,7 @@ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
|||
* blocks and we must accept those blocks.
|
||||
*/
|
||||
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
SCRIPT_VERIFY_DERSIG |
|
||||
SCRIPT_VERIFY_STRICTENC |
|
||||
SCRIPT_VERIFY_MINIMALDATA |
|
||||
SCRIPT_VERIFY_NULLDUMMY |
|
||||
|
|
11
src/sync.h
11
src/sync.h
|
@ -142,6 +142,17 @@ public:
|
|||
Enter(pszName, pszFile, nLine);
|
||||
}
|
||||
|
||||
CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false)
|
||||
{
|
||||
if (!pmutexIn) return;
|
||||
|
||||
lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
|
||||
if (fTry)
|
||||
TryEnter(pszName, pszFile, nLine);
|
||||
else
|
||||
Enter(pszName, pszFile, nLine);
|
||||
}
|
||||
|
||||
~CMutexLock()
|
||||
{
|
||||
if (lock.owns_lock())
|
||||
|
|
|
@ -510,6 +510,16 @@
|
|||
"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid."
|
||||
],
|
||||
|
||||
["Increase DERSIG test coverage"],
|
||||
["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Overly long signature is incorrectly encoded for DERSIG"],
|
||||
["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Missing S is incorrectly encoded for DERSIG"],
|
||||
["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "S with invalid S length is incorrectly encoded for DERSIG"],
|
||||
["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer R is incorrectly encoded for DERSIG"],
|
||||
["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer S is incorrectly encoded for DERSIG"],
|
||||
["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Zero-length R is incorrectly encoded for DERSIG"],
|
||||
["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "Zero-length S is incorrectly encoded for DERSIG"],
|
||||
["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Negative S is incorrectly encoded for DERSIG"],
|
||||
|
||||
["Automatically generated test cases"],
|
||||
[
|
||||
"0x47 0x3044022053205076a7bb12d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
|
||||
|
@ -589,6 +599,102 @@
|
|||
"DERSIG",
|
||||
"P2PK NOT with too much R padding"
|
||||
],
|
||||
[
|
||||
"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
||||
"DERSIG",
|
||||
"BIP66 example 1, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||
"",
|
||||
"BIP66 example 2, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||
"DERSIG",
|
||||
"BIP66 example 2, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
||||
"",
|
||||
"BIP66 example 3, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
||||
"DERSIG",
|
||||
"BIP66 example 3, with DERSIG"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
||||
"",
|
||||
"BIP66 example 5, without DERSIG"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
||||
"DERSIG",
|
||||
"BIP66 example 5, with DERSIG"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||
"DERSIG",
|
||||
"BIP66 example 6, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x304402200b3d0b0375bb15c14620afa4aa10ae90a0d6a046ce217bc20fe0bc1ced68c1b802204b550acab90ae6d3478057c9ad24f9df743815b799b6449dd7e7f6d3bc6e274c01",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
|
||||
"DERSIG",
|
||||
"BIP66 example 7, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
|
||||
"",
|
||||
"BIP66 example 8, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
|
||||
"DERSIG",
|
||||
"BIP66 example 8, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
|
||||
"",
|
||||
"BIP66 example 9, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
|
||||
"DERSIG",
|
||||
"BIP66 example 9, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0 0x47 0x30440220afa76a8f60622f813b05711f051c6c3407e32d1b1b70b0576c1f01b54e4c05c702200d58e9df044fd1845cabfbeef6e624ba0401daf7d7e084736f9ff601c3783bf501",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
|
||||
"DERSIG",
|
||||
"BIP66 example 10, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
|
||||
"",
|
||||
"BIP66 example 11, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
|
||||
"DERSIG",
|
||||
"BIP66 example 11, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
|
||||
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
|
||||
|
|
|
@ -688,6 +688,16 @@
|
|||
"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature."
|
||||
],
|
||||
|
||||
["Increase test coverage for DERSIG"],
|
||||
["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "Overly long signature is correctly encoded"],
|
||||
["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "Missing S is correctly encoded"],
|
||||
["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "", "S with invalid S length is correctly encoded"],
|
||||
["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Non-integer R is correctly encoded"],
|
||||
["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Non-integer S is correctly encoded"],
|
||||
["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Zero-length R is correctly encoded"],
|
||||
["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "Zero-length S is correctly encoded for DERSIG"],
|
||||
["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Negative S is correctly encoded"],
|
||||
|
||||
["Automatically generated test cases"],
|
||||
[
|
||||
"0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
|
||||
|
@ -755,6 +765,54 @@
|
|||
"",
|
||||
"P2PK NOT with bad sig with too much R padding but no DERSIG"
|
||||
],
|
||||
[
|
||||
"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
||||
"",
|
||||
"BIP66 example 1, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||
"",
|
||||
"BIP66 example 4, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||
"DERSIG",
|
||||
"BIP66 example 4, with DERSIG"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||
"",
|
||||
"BIP66 example 6, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x304402200b3d0b0375bb15c14620afa4aa10ae90a0d6a046ce217bc20fe0bc1ced68c1b802204b550acab90ae6d3478057c9ad24f9df743815b799b6449dd7e7f6d3bc6e274c01",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
|
||||
"",
|
||||
"BIP66 example 7, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0 0x47 0x30440220afa76a8f60622f813b05711f051c6c3407e32d1b1b70b0576c1f01b54e4c05c702200d58e9df044fd1845cabfbeef6e624ba0401daf7d7e084736f9ff601c3783bf501",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
|
||||
"",
|
||||
"BIP66 example 10, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
|
||||
"",
|
||||
"BIP66 example 12, without DERSIG"
|
||||
],
|
||||
[
|
||||
"0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0",
|
||||
"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
|
||||
"DERSIG",
|
||||
"BIP66 example 12, with DERSIG"
|
||||
],
|
||||
[
|
||||
"0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
|
||||
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
[
|
||||
"300602010002010001",
|
||||
"3008020200ff020200ff01",
|
||||
"304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001",
|
||||
"30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01",
|
||||
"3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
[
|
||||
"non-hex strings are ignored",
|
||||
|
||||
"too short:", "30050201FF020001",
|
||||
"too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11",
|
||||
"type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101",
|
||||
"R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001",
|
||||
|
||||
"R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
|
||||
|
||||
"S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001",
|
||||
"S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"
|
||||
]
|
|
@ -82,20 +82,20 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
|||
keys.assign(1,key[0]);
|
||||
keys.push_back(key[1]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err));
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keys.assign(1,key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 1: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 1: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
||||
|
||||
keys.assign(1,key[1]);
|
||||
keys.push_back(key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 2: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 2: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
|
||||
|
@ -106,18 +106,18 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
|||
s = sign_multisig(a_or_b, keys, txTo[1], 0);
|
||||
if (i == 0 || i == 1)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
}
|
||||
s.clear();
|
||||
s << OP_0 << OP_1;
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
|
||||
|
||||
|
||||
|
@ -129,12 +129,12 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
|||
s = sign_multisig(escrow, keys, txTo[2], 0);
|
||||
if (i < j && i < 3 && j < 3)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
|
|||
txTo.vin[0].scriptSig = scriptSig;
|
||||
txTo.vout[0].nValue = 1;
|
||||
|
||||
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0), &err);
|
||||
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bo
|
|||
ScriptError err;
|
||||
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey));
|
||||
CMutableTransaction tx2 = tx;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(tx, 0), &err) == expect, message);
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0), &err) == expect, message);
|
||||
BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
@ -406,6 +406,79 @@ BOOST_AUTO_TEST_CASE(script_build)
|
|||
"P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG
|
||||
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
|
||||
|
||||
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
|
||||
"BIP66 example 1, without DERSIG", 0
|
||||
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
|
||||
"BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
|
||||
"BIP66 example 2, without DERSIG", 0
|
||||
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
|
||||
"BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
|
||||
"BIP66 example 3, without DERSIG", 0
|
||||
).Num(0));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
|
||||
"BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0));
|
||||
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
|
||||
"BIP66 example 4, without DERSIG", 0
|
||||
).Num(0));
|
||||
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
|
||||
"BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
|
||||
"BIP66 example 5, without DERSIG", 0
|
||||
).Num(1));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
|
||||
"BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(1));
|
||||
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
|
||||
"BIP66 example 6, without DERSIG", 0
|
||||
).Num(1));
|
||||
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
|
||||
"BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(1));
|
||||
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
|
||||
"BIP66 example 7, without DERSIG", 0
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
|
||||
"BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
|
||||
"BIP66 example 8, without DERSIG", 0
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
|
||||
"BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
|
||||
"BIP66 example 9, without DERSIG", 0
|
||||
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
|
||||
"BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
|
||||
"BIP66 example 10, without DERSIG", 0
|
||||
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
|
||||
"BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
|
||||
"BIP66 example 11, without DERSIG", 0
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
|
||||
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
|
||||
"BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
|
||||
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
|
||||
"BIP66 example 12, without DERSIG", 0
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
|
||||
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
|
||||
"BIP66 example 12, with DERSIG", SCRIPT_VERIFY_DERSIG
|
||||
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
|
||||
|
||||
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
|
||||
"P2PK with high S but no LOW_S", 0
|
||||
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
|
||||
|
@ -682,18 +755,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
|
|||
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
|
||||
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
txTo12.vout[0].nValue = 2;
|
||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
|
||||
|
@ -715,54 +788,54 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
|||
std::vector<CKey> keys;
|
||||
keys.push_back(key1); keys.push_back(key2);
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key3);
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key3);
|
||||
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
|
||||
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
|
||||
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
|
||||
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
|
||||
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
|
||||
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear(); // Must have signatures
|
||||
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
|||
|
||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||
verify_flags, SignatureChecker(tx, i), &err),
|
||||
verify_flags, TransactionSignatureChecker(&tx, i), &err),
|
||||
strTest);
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
|||
|
||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||
verify_flags, SignatureChecker(tx, i), &err);
|
||||
verify_flags, TransactionSignatureChecker(&tx, i), &err);
|
||||
}
|
||||
BOOST_CHECK_MESSAGE(!fValid, strTest);
|
||||
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
@ -347,12 +347,12 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||
t.vout[0].scriptPubKey = CScript() << OP_1;
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
|
||||
// 40-byte TX_NULL_DATA (standard)
|
||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||
// 80-byte TX_NULL_DATA (standard)
|
||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||
BOOST_CHECK(IsStandardTx(t, reason));
|
||||
|
||||
// 41-byte TX_NULL_DATA (non-standard)
|
||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
||||
// 81-byte TX_NULL_DATA (non-standard)
|
||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
|
||||
// TX_NULL_DATA w/o PUSHDATA
|
||||
|
|
61
src/txdb.cpp
61
src/txdb.cpp
|
@ -14,35 +14,42 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static const char DB_COINS = 'c';
|
||||
static const char DB_BLOCK_FILES = 'f';
|
||||
static const char DB_TXINDEX = 't';
|
||||
static const char DB_BLOCK_INDEX = 'b';
|
||||
|
||||
static const char DB_BEST_BLOCK = 'B';
|
||||
static const char DB_FLAG = 'F';
|
||||
static const char DB_REINDEX_FLAG = 'R';
|
||||
static const char DB_LAST_BLOCK = 'l';
|
||||
|
||||
|
||||
void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
|
||||
if (coins.IsPruned()) {
|
||||
LogPrintf("BatchWriteCoins erasing %s\n", hash.GetHex().c_str());
|
||||
batch.Erase(make_pair('c', hash));
|
||||
}
|
||||
else {
|
||||
LogPrintf("BatchWriteCoins writing %s\n", hash.GetHex().c_str());
|
||||
batch.Write(make_pair('c', hash), coins);
|
||||
}
|
||||
if (coins.IsPruned())
|
||||
batch.Erase(make_pair(DB_COINS, hash));
|
||||
else
|
||||
batch.Write(make_pair(DB_COINS, hash), coins);
|
||||
}
|
||||
|
||||
void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
|
||||
batch.Write('B', hash);
|
||||
batch.Write(DB_BEST_BLOCK, hash);
|
||||
}
|
||||
|
||||
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
|
||||
}
|
||||
|
||||
bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
|
||||
return db.Read(make_pair('c', txid), coins);
|
||||
return db.Read(make_pair(DB_COINS, txid), coins);
|
||||
}
|
||||
|
||||
bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
|
||||
return db.Exists(make_pair('c', txid));
|
||||
return db.Exists(make_pair(DB_COINS, txid));
|
||||
}
|
||||
|
||||
uint256 CCoinsViewDB::GetBestBlock() const {
|
||||
uint256 hashBestChain;
|
||||
if (!db.Read('B', hashBestChain))
|
||||
if (!db.Read(DB_BEST_BLOCK, hashBestChain))
|
||||
return uint256();
|
||||
return hashBestChain;
|
||||
}
|
||||
|
@ -71,23 +78,23 @@ CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevel
|
|||
}
|
||||
|
||||
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
|
||||
return Read(make_pair('f', nFile), info);
|
||||
return Read(make_pair(DB_BLOCK_FILES, nFile), info);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
|
||||
if (fReindexing)
|
||||
return Write('R', '1');
|
||||
return Write(DB_REINDEX_FLAG, '1');
|
||||
else
|
||||
return Erase('R');
|
||||
return Erase(DB_REINDEX_FLAG);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
|
||||
fReindexing = Exists('R');
|
||||
fReindexing = Exists(DB_REINDEX_FLAG);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
|
||||
return Read('l', nFile);
|
||||
return Read(DB_LAST_BLOCK, nFile);
|
||||
}
|
||||
|
||||
bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
|
||||
|
@ -108,7 +115,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
|
|||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
char chType;
|
||||
ssKey >> chType;
|
||||
if (chType == 'c') {
|
||||
if (chType == DB_COINS) {
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CCoins coins;
|
||||
|
@ -146,33 +153,33 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
|
|||
bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
|
||||
CLevelDBBatch batch;
|
||||
for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
|
||||
batch.Write(make_pair('f', it->first), *it->second);
|
||||
batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second);
|
||||
}
|
||||
batch.Write('l', nLastFile);
|
||||
batch.Write(DB_LAST_BLOCK, nLastFile);
|
||||
for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
|
||||
batch.Write(make_pair('b', (*it)->GetBlockHash()), CDiskBlockIndex(*it));
|
||||
batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
|
||||
}
|
||||
return WriteBatch(batch, true);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
|
||||
return Read(make_pair('t', txid), pos);
|
||||
return Read(make_pair(DB_TXINDEX, txid), pos);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
|
||||
CLevelDBBatch batch;
|
||||
for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
|
||||
batch.Write(make_pair('t', it->first), it->second);
|
||||
batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
|
||||
return Write(std::make_pair('F', name), fValue ? '1' : '0');
|
||||
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
|
||||
char ch;
|
||||
if (!Read(std::make_pair('F', name), ch))
|
||||
if (!Read(std::make_pair(DB_FLAG, name), ch))
|
||||
return false;
|
||||
fValue = ch == '1';
|
||||
return true;
|
||||
|
@ -183,7 +190,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
|||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||
|
||||
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
|
||||
ssKeySet << make_pair('b', uint256());
|
||||
ssKeySet << make_pair(DB_BLOCK_INDEX, uint256());
|
||||
pcursor->Seek(ssKeySet.str());
|
||||
|
||||
// Load mapBlockIndex
|
||||
|
@ -194,7 +201,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
|||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
char chType;
|
||||
ssKey >> chType;
|
||||
if (chType == 'b') {
|
||||
if (chType == DB_BLOCK_INDEX) {
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CDiskBlockIndex diskindex;
|
||||
|
|
199
src/wallet.cpp
199
src/wallet.cpp
|
@ -1020,6 +1020,193 @@ set<uint256> CWalletTx::GetConflicts() const
|
|||
return result;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetDebit(const isminefilter& filter) const
|
||||
{
|
||||
if (vin.empty())
|
||||
return 0;
|
||||
|
||||
CAmount debit = 0;
|
||||
if(filter & ISMINE_SPENDABLE)
|
||||
{
|
||||
if (fDebitCached)
|
||||
debit += nDebitCached;
|
||||
else
|
||||
{
|
||||
nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE);
|
||||
fDebitCached = true;
|
||||
debit += nDebitCached;
|
||||
}
|
||||
}
|
||||
if(filter & ISMINE_WATCH_ONLY)
|
||||
{
|
||||
if(fWatchDebitCached)
|
||||
debit += nWatchDebitCached;
|
||||
else
|
||||
{
|
||||
nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY);
|
||||
fWatchDebitCached = true;
|
||||
debit += nWatchDebitCached;
|
||||
}
|
||||
}
|
||||
return debit;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetCredit(const isminefilter& filter) const
|
||||
{
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
int64_t credit = 0;
|
||||
if (filter & ISMINE_SPENDABLE)
|
||||
{
|
||||
// GetBalance can assume transactions in mapWallet won't change
|
||||
if (fCreditCached)
|
||||
credit += nCreditCached;
|
||||
else
|
||||
{
|
||||
nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
|
||||
fCreditCached = true;
|
||||
credit += nCreditCached;
|
||||
}
|
||||
}
|
||||
if (filter & ISMINE_WATCH_ONLY)
|
||||
{
|
||||
if (fWatchCreditCached)
|
||||
credit += nWatchCreditCached;
|
||||
else
|
||||
{
|
||||
nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
|
||||
fWatchCreditCached = true;
|
||||
credit += nWatchCreditCached;
|
||||
}
|
||||
}
|
||||
return credit;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
|
||||
{
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
|
||||
{
|
||||
if (fUseCache && fImmatureCreditCached)
|
||||
return nImmatureCreditCached;
|
||||
nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
|
||||
fImmatureCreditCached = true;
|
||||
return nImmatureCreditCached;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
|
||||
{
|
||||
if (pwallet == 0)
|
||||
return 0;
|
||||
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
if (fUseCache && fAvailableCreditCached)
|
||||
return nAvailableCreditCached;
|
||||
|
||||
CAmount nCredit = 0;
|
||||
uint256 hashTx = GetHash();
|
||||
for (unsigned int i = 0; i < vout.size(); i++)
|
||||
{
|
||||
if (!pwallet->IsSpent(hashTx, i))
|
||||
{
|
||||
const CTxOut &txout = vout[i];
|
||||
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
|
||||
if (!MoneyRange(nCredit))
|
||||
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
nAvailableCreditCached = nCredit;
|
||||
fAvailableCreditCached = true;
|
||||
return nCredit;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
|
||||
{
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
|
||||
{
|
||||
if (fUseCache && fImmatureWatchCreditCached)
|
||||
return nImmatureWatchCreditCached;
|
||||
nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
|
||||
fImmatureWatchCreditCached = true;
|
||||
return nImmatureWatchCreditCached;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
|
||||
{
|
||||
if (pwallet == 0)
|
||||
return 0;
|
||||
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
if (fUseCache && fAvailableWatchCreditCached)
|
||||
return nAvailableWatchCreditCached;
|
||||
|
||||
CAmount nCredit = 0;
|
||||
for (unsigned int i = 0; i < vout.size(); i++)
|
||||
{
|
||||
if (!pwallet->IsSpent(GetHash(), i))
|
||||
{
|
||||
const CTxOut &txout = vout[i];
|
||||
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
|
||||
if (!MoneyRange(nCredit))
|
||||
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
nAvailableWatchCreditCached = nCredit;
|
||||
fAvailableWatchCreditCached = true;
|
||||
return nCredit;
|
||||
}
|
||||
|
||||
CAmount CWalletTx::GetChange() const
|
||||
{
|
||||
if (fChangeCached)
|
||||
return nChangeCached;
|
||||
nChangeCached = pwallet->GetChange(*this);
|
||||
fChangeCached = true;
|
||||
return nChangeCached;
|
||||
}
|
||||
|
||||
bool CWalletTx::IsTrusted() const
|
||||
{
|
||||
// Quick answer in most cases
|
||||
if (!IsFinalTx(*this))
|
||||
return false;
|
||||
int nDepth = GetDepthInMainChain();
|
||||
if (nDepth >= 1)
|
||||
return true;
|
||||
if (nDepth < 0)
|
||||
return false;
|
||||
if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
|
||||
return false;
|
||||
|
||||
// Trusted if all inputs are from us and are in the mempool:
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
{
|
||||
// Transactions not sent by us: not trusted
|
||||
const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
|
||||
if (parent == NULL)
|
||||
return false;
|
||||
const CTxOut& parentOut = parent->vout[txin.prevout.n];
|
||||
if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWallet::ResendWalletTransactions()
|
||||
{
|
||||
// Do this infrequently and randomly to avoid giving away
|
||||
|
@ -1463,10 +1650,14 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
|
|||
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
|
||||
{
|
||||
CAmount nCredit = pcoin.first->vout[pcoin.second].nValue;
|
||||
//The priority after the next block (depth+1) is used instead of the current,
|
||||
//The coin age after the next block (depth+1) is used instead of the current,
|
||||
//reflecting an assumption the user would accept a bit more delay for
|
||||
//a chance at a free transaction.
|
||||
dPriority += (double)nCredit * (pcoin.first->GetDepthInMainChain()+1);
|
||||
//But mempool inputs might still be in the mempool, so their age stays 0
|
||||
int age = pcoin.first->GetDepthInMainChain();
|
||||
if (age != 0)
|
||||
age += 1;
|
||||
dPriority += (double)nCredit * age;
|
||||
}
|
||||
|
||||
if (fUsingWtxIn)
|
||||
|
@ -2389,9 +2580,9 @@ int CMerkleTx::GetBlocksToMaturity() const
|
|||
}
|
||||
|
||||
|
||||
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee)
|
||||
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
|
||||
{
|
||||
CValidationState state;
|
||||
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee);
|
||||
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
|
||||
}
|
||||
|
||||
|
|
825
src/wallet.h
825
src/wallet.h
|
@ -103,6 +103,329 @@ public:
|
|||
StringMap destdata;
|
||||
};
|
||||
|
||||
|
||||
typedef std::map<std::string, std::string> mapValue_t;
|
||||
|
||||
|
||||
static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
|
||||
{
|
||||
if (!mapValue.count("n"))
|
||||
{
|
||||
nOrderPos = -1; // TODO: calculate elsewhere
|
||||
return;
|
||||
}
|
||||
nOrderPos = atoi64(mapValue["n"].c_str());
|
||||
}
|
||||
|
||||
|
||||
static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
|
||||
{
|
||||
if (nOrderPos == -1)
|
||||
return;
|
||||
mapValue["n"] = i64tostr(nOrderPos);
|
||||
}
|
||||
|
||||
struct COutputEntry
|
||||
{
|
||||
CTxDestination destination;
|
||||
CAmount amount;
|
||||
int vout;
|
||||
};
|
||||
|
||||
/** A transaction with a merkle branch linking it to the block chain. */
|
||||
class CMerkleTx : public CTransaction
|
||||
{
|
||||
private:
|
||||
int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
|
||||
|
||||
public:
|
||||
uint256 hashBlock;
|
||||
std::vector<uint256> vMerkleBranch;
|
||||
int nIndex;
|
||||
|
||||
// memory only
|
||||
mutable bool fMerkleVerified;
|
||||
|
||||
|
||||
CMerkleTx()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
hashBlock = uint256();
|
||||
nIndex = -1;
|
||||
fMerkleVerified = false;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(*(CTransaction*)this);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(hashBlock);
|
||||
READWRITE(vMerkleBranch);
|
||||
READWRITE(nIndex);
|
||||
}
|
||||
|
||||
int SetMerkleBranch(const CBlock& block);
|
||||
|
||||
|
||||
/**
|
||||
* Return depth of transaction in blockchain:
|
||||
* -1 : not in blockchain, and not in memory pool (conflicted transaction)
|
||||
* 0 : in memory pool, waiting to be included in a block
|
||||
* >=1 : this many blocks deep in the main chain
|
||||
*/
|
||||
int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
|
||||
int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
|
||||
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
|
||||
int GetBlocksToMaturity() const;
|
||||
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
|
||||
};
|
||||
|
||||
/**
|
||||
* A transaction with a bunch of additional info that only the owner cares about.
|
||||
* It includes any unrecorded transactions needed to link it back to the block chain.
|
||||
*/
|
||||
class CWalletTx : public CMerkleTx
|
||||
{
|
||||
private:
|
||||
const CWallet* pwallet;
|
||||
|
||||
public:
|
||||
mapValue_t mapValue;
|
||||
std::vector<std::pair<std::string, std::string> > vOrderForm;
|
||||
unsigned int fTimeReceivedIsTxTime;
|
||||
unsigned int nTimeReceived; //! time received by this node
|
||||
unsigned int nTimeSmart;
|
||||
char fFromMe;
|
||||
std::string strFromAccount;
|
||||
int64_t nOrderPos; //! position in ordered transaction list
|
||||
|
||||
// memory only
|
||||
mutable bool fDebitCached;
|
||||
mutable bool fCreditCached;
|
||||
mutable bool fImmatureCreditCached;
|
||||
mutable bool fAvailableCreditCached;
|
||||
mutable bool fWatchDebitCached;
|
||||
mutable bool fWatchCreditCached;
|
||||
mutable bool fImmatureWatchCreditCached;
|
||||
mutable bool fAvailableWatchCreditCached;
|
||||
mutable bool fChangeCached;
|
||||
mutable CAmount nDebitCached;
|
||||
mutable CAmount nCreditCached;
|
||||
mutable CAmount nImmatureCreditCached;
|
||||
mutable CAmount nAvailableCreditCached;
|
||||
mutable CAmount nWatchDebitCached;
|
||||
mutable CAmount nWatchCreditCached;
|
||||
mutable CAmount nImmatureWatchCreditCached;
|
||||
mutable CAmount nAvailableWatchCreditCached;
|
||||
mutable CAmount nChangeCached;
|
||||
|
||||
CWalletTx()
|
||||
{
|
||||
Init(NULL);
|
||||
}
|
||||
|
||||
CWalletTx(const CWallet* pwalletIn)
|
||||
{
|
||||
Init(pwalletIn);
|
||||
}
|
||||
|
||||
CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
|
||||
{
|
||||
Init(pwalletIn);
|
||||
}
|
||||
|
||||
CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
|
||||
{
|
||||
Init(pwalletIn);
|
||||
}
|
||||
|
||||
void Init(const CWallet* pwalletIn)
|
||||
{
|
||||
pwallet = pwalletIn;
|
||||
mapValue.clear();
|
||||
vOrderForm.clear();
|
||||
fTimeReceivedIsTxTime = false;
|
||||
nTimeReceived = 0;
|
||||
nTimeSmart = 0;
|
||||
fFromMe = false;
|
||||
strFromAccount.clear();
|
||||
fDebitCached = false;
|
||||
fCreditCached = false;
|
||||
fImmatureCreditCached = false;
|
||||
fAvailableCreditCached = false;
|
||||
fWatchDebitCached = false;
|
||||
fWatchCreditCached = false;
|
||||
fImmatureWatchCreditCached = false;
|
||||
fAvailableWatchCreditCached = false;
|
||||
fChangeCached = false;
|
||||
nDebitCached = 0;
|
||||
nCreditCached = 0;
|
||||
nImmatureCreditCached = 0;
|
||||
nAvailableCreditCached = 0;
|
||||
nWatchDebitCached = 0;
|
||||
nWatchCreditCached = 0;
|
||||
nAvailableWatchCreditCached = 0;
|
||||
nImmatureWatchCreditCached = 0;
|
||||
nChangeCached = 0;
|
||||
nOrderPos = -1;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
if (ser_action.ForRead())
|
||||
Init(NULL);
|
||||
char fSpent = false;
|
||||
|
||||
if (!ser_action.ForRead())
|
||||
{
|
||||
mapValue["fromaccount"] = strFromAccount;
|
||||
|
||||
WriteOrderPos(nOrderPos, mapValue);
|
||||
|
||||
if (nTimeSmart)
|
||||
mapValue["timesmart"] = strprintf("%u", nTimeSmart);
|
||||
}
|
||||
|
||||
READWRITE(*(CMerkleTx*)this);
|
||||
std::vector<CMerkleTx> vUnused; //! Used to be vtxPrev
|
||||
READWRITE(vUnused);
|
||||
READWRITE(mapValue);
|
||||
READWRITE(vOrderForm);
|
||||
READWRITE(fTimeReceivedIsTxTime);
|
||||
READWRITE(nTimeReceived);
|
||||
READWRITE(fFromMe);
|
||||
READWRITE(fSpent);
|
||||
|
||||
if (ser_action.ForRead())
|
||||
{
|
||||
strFromAccount = mapValue["fromaccount"];
|
||||
|
||||
ReadOrderPos(nOrderPos, mapValue);
|
||||
|
||||
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
|
||||
}
|
||||
|
||||
mapValue.erase("fromaccount");
|
||||
mapValue.erase("version");
|
||||
mapValue.erase("spent");
|
||||
mapValue.erase("n");
|
||||
mapValue.erase("timesmart");
|
||||
}
|
||||
|
||||
//! make sure balances are recalculated
|
||||
void MarkDirty()
|
||||
{
|
||||
fCreditCached = false;
|
||||
fAvailableCreditCached = false;
|
||||
fWatchDebitCached = false;
|
||||
fWatchCreditCached = false;
|
||||
fAvailableWatchCreditCached = false;
|
||||
fImmatureWatchCreditCached = false;
|
||||
fDebitCached = false;
|
||||
fChangeCached = false;
|
||||
}
|
||||
|
||||
void BindWallet(CWallet *pwalletIn)
|
||||
{
|
||||
pwallet = pwalletIn;
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
//! filter decides which addresses will count towards the debit
|
||||
CAmount GetDebit(const isminefilter& filter) const;
|
||||
CAmount GetCredit(const isminefilter& filter) const;
|
||||
CAmount GetImmatureCredit(bool fUseCache=true) const;
|
||||
CAmount GetAvailableCredit(bool fUseCache=true) const;
|
||||
CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const;
|
||||
CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const;
|
||||
CAmount GetChange() const;
|
||||
|
||||
void GetAmounts(std::list<COutputEntry>& listReceived,
|
||||
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
|
||||
|
||||
void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
|
||||
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
|
||||
|
||||
bool IsFromMe(const isminefilter& filter) const
|
||||
{
|
||||
return (GetDebit(filter) > 0);
|
||||
}
|
||||
|
||||
bool IsTrusted() const;
|
||||
|
||||
bool WriteToDisk(CWalletDB *pwalletdb);
|
||||
|
||||
int64_t GetTxTime() const;
|
||||
int GetRequestCount() const;
|
||||
|
||||
void RelayWalletTransaction();
|
||||
|
||||
std::set<uint256> GetConflicts() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class COutput
|
||||
{
|
||||
public:
|
||||
const CWalletTx *tx;
|
||||
int i;
|
||||
int nDepth;
|
||||
bool fSpendable;
|
||||
|
||||
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn)
|
||||
{
|
||||
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Private key that includes an expiration date in case it never gets used. */
|
||||
class CWalletKey
|
||||
{
|
||||
public:
|
||||
CPrivKey vchPrivKey;
|
||||
int64_t nTimeCreated;
|
||||
int64_t nTimeExpires;
|
||||
std::string strComment;
|
||||
//! todo: add something to note what created it (user, getnewaddress, change)
|
||||
//! maybe should have a map<string, string> property map
|
||||
|
||||
CWalletKey(int64_t nExpires=0);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
if (!(nType & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(vchPrivKey);
|
||||
READWRITE(nTimeCreated);
|
||||
READWRITE(nTimeExpires);
|
||||
READWRITE(LIMITED_STRING(strComment, 65536));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
|
||||
* and provides the ability to create new transactions.
|
||||
|
@ -464,508 +787,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
typedef std::map<std::string, std::string> mapValue_t;
|
||||
|
||||
|
||||
static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
|
||||
{
|
||||
if (!mapValue.count("n"))
|
||||
{
|
||||
nOrderPos = -1; // TODO: calculate elsewhere
|
||||
return;
|
||||
}
|
||||
nOrderPos = atoi64(mapValue["n"].c_str());
|
||||
}
|
||||
|
||||
|
||||
static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
|
||||
{
|
||||
if (nOrderPos == -1)
|
||||
return;
|
||||
mapValue["n"] = i64tostr(nOrderPos);
|
||||
}
|
||||
|
||||
struct COutputEntry
|
||||
{
|
||||
CTxDestination destination;
|
||||
CAmount amount;
|
||||
int vout;
|
||||
};
|
||||
|
||||
/** A transaction with a merkle branch linking it to the block chain. */
|
||||
class CMerkleTx : public CTransaction
|
||||
{
|
||||
private:
|
||||
int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
|
||||
|
||||
public:
|
||||
uint256 hashBlock;
|
||||
std::vector<uint256> vMerkleBranch;
|
||||
int nIndex;
|
||||
|
||||
// memory only
|
||||
mutable bool fMerkleVerified;
|
||||
|
||||
|
||||
CMerkleTx()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
hashBlock = uint256();
|
||||
nIndex = -1;
|
||||
fMerkleVerified = false;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(*(CTransaction*)this);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(hashBlock);
|
||||
READWRITE(vMerkleBranch);
|
||||
READWRITE(nIndex);
|
||||
}
|
||||
|
||||
int SetMerkleBranch(const CBlock& block);
|
||||
|
||||
|
||||
/**
|
||||
* Return depth of transaction in blockchain:
|
||||
* -1 : not in blockchain, and not in memory pool (conflicted transaction)
|
||||
* 0 : in memory pool, waiting to be included in a block
|
||||
* >=1 : this many blocks deep in the main chain
|
||||
*/
|
||||
int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
|
||||
int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
|
||||
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
|
||||
int GetBlocksToMaturity() const;
|
||||
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectInsaneFee=true);
|
||||
};
|
||||
|
||||
/**
|
||||
* A transaction with a bunch of additional info that only the owner cares about.
|
||||
* It includes any unrecorded transactions needed to link it back to the block chain.
|
||||
*/
|
||||
class CWalletTx : public CMerkleTx
|
||||
{
|
||||
private:
|
||||
const CWallet* pwallet;
|
||||
|
||||
public:
|
||||
mapValue_t mapValue;
|
||||
std::vector<std::pair<std::string, std::string> > vOrderForm;
|
||||
unsigned int fTimeReceivedIsTxTime;
|
||||
unsigned int nTimeReceived; //! time received by this node
|
||||
unsigned int nTimeSmart;
|
||||
char fFromMe;
|
||||
std::string strFromAccount;
|
||||
int64_t nOrderPos; //! position in ordered transaction list
|
||||
|
||||
// memory only
|
||||
mutable bool fDebitCached;
|
||||
mutable bool fCreditCached;
|
||||
mutable bool fImmatureCreditCached;
|
||||
mutable bool fAvailableCreditCached;
|
||||
mutable bool fWatchDebitCached;
|
||||
mutable bool fWatchCreditCached;
|
||||
mutable bool fImmatureWatchCreditCached;
|
||||
mutable bool fAvailableWatchCreditCached;
|
||||
mutable bool fChangeCached;
|
||||
mutable CAmount nDebitCached;
|
||||
mutable CAmount nCreditCached;
|
||||
mutable CAmount nImmatureCreditCached;
|
||||
mutable CAmount nAvailableCreditCached;
|
||||
mutable CAmount nWatchDebitCached;
|
||||
mutable CAmount nWatchCreditCached;
|
||||
mutable CAmount nImmatureWatchCreditCached;
|
||||
mutable CAmount nAvailableWatchCreditCached;
|
||||
mutable CAmount nChangeCached;
|
||||
|
||||
CWalletTx()
|
||||
{
|
||||
Init(NULL);
|
||||
}
|
||||
|
||||
CWalletTx(const CWallet* pwalletIn)
|
||||
{
|
||||
Init(pwalletIn);
|
||||
}
|
||||
|
||||
CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
|
||||
{
|
||||
Init(pwalletIn);
|
||||
}
|
||||
|
||||
CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
|
||||
{
|
||||
Init(pwalletIn);
|
||||
}
|
||||
|
||||
void Init(const CWallet* pwalletIn)
|
||||
{
|
||||
pwallet = pwalletIn;
|
||||
mapValue.clear();
|
||||
vOrderForm.clear();
|
||||
fTimeReceivedIsTxTime = false;
|
||||
nTimeReceived = 0;
|
||||
nTimeSmart = 0;
|
||||
fFromMe = false;
|
||||
strFromAccount.clear();
|
||||
fDebitCached = false;
|
||||
fCreditCached = false;
|
||||
fImmatureCreditCached = false;
|
||||
fAvailableCreditCached = false;
|
||||
fWatchDebitCached = false;
|
||||
fWatchCreditCached = false;
|
||||
fImmatureWatchCreditCached = false;
|
||||
fAvailableWatchCreditCached = false;
|
||||
fChangeCached = false;
|
||||
nDebitCached = 0;
|
||||
nCreditCached = 0;
|
||||
nImmatureCreditCached = 0;
|
||||
nAvailableCreditCached = 0;
|
||||
nWatchDebitCached = 0;
|
||||
nWatchCreditCached = 0;
|
||||
nAvailableWatchCreditCached = 0;
|
||||
nImmatureWatchCreditCached = 0;
|
||||
nChangeCached = 0;
|
||||
nOrderPos = -1;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
if (ser_action.ForRead())
|
||||
Init(NULL);
|
||||
char fSpent = false;
|
||||
|
||||
if (!ser_action.ForRead())
|
||||
{
|
||||
mapValue["fromaccount"] = strFromAccount;
|
||||
|
||||
WriteOrderPos(nOrderPos, mapValue);
|
||||
|
||||
if (nTimeSmart)
|
||||
mapValue["timesmart"] = strprintf("%u", nTimeSmart);
|
||||
}
|
||||
|
||||
READWRITE(*(CMerkleTx*)this);
|
||||
std::vector<CMerkleTx> vUnused; //! Used to be vtxPrev
|
||||
READWRITE(vUnused);
|
||||
READWRITE(mapValue);
|
||||
READWRITE(vOrderForm);
|
||||
READWRITE(fTimeReceivedIsTxTime);
|
||||
READWRITE(nTimeReceived);
|
||||
READWRITE(fFromMe);
|
||||
READWRITE(fSpent);
|
||||
|
||||
if (ser_action.ForRead())
|
||||
{
|
||||
strFromAccount = mapValue["fromaccount"];
|
||||
|
||||
ReadOrderPos(nOrderPos, mapValue);
|
||||
|
||||
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
|
||||
}
|
||||
|
||||
mapValue.erase("fromaccount");
|
||||
mapValue.erase("version");
|
||||
mapValue.erase("spent");
|
||||
mapValue.erase("n");
|
||||
mapValue.erase("timesmart");
|
||||
}
|
||||
|
||||
//! make sure balances are recalculated
|
||||
void MarkDirty()
|
||||
{
|
||||
fCreditCached = false;
|
||||
fAvailableCreditCached = false;
|
||||
fWatchDebitCached = false;
|
||||
fWatchCreditCached = false;
|
||||
fAvailableWatchCreditCached = false;
|
||||
fImmatureWatchCreditCached = false;
|
||||
fDebitCached = false;
|
||||
fChangeCached = false;
|
||||
}
|
||||
|
||||
void BindWallet(CWallet *pwalletIn)
|
||||
{
|
||||
pwallet = pwalletIn;
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
//! filter decides which addresses will count towards the debit
|
||||
CAmount GetDebit(const isminefilter& filter) const
|
||||
{
|
||||
if (vin.empty())
|
||||
return 0;
|
||||
|
||||
CAmount debit = 0;
|
||||
if(filter & ISMINE_SPENDABLE)
|
||||
{
|
||||
if (fDebitCached)
|
||||
debit += nDebitCached;
|
||||
else
|
||||
{
|
||||
nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE);
|
||||
fDebitCached = true;
|
||||
debit += nDebitCached;
|
||||
}
|
||||
}
|
||||
if(filter & ISMINE_WATCH_ONLY)
|
||||
{
|
||||
if(fWatchDebitCached)
|
||||
debit += nWatchDebitCached;
|
||||
else
|
||||
{
|
||||
nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY);
|
||||
fWatchDebitCached = true;
|
||||
debit += nWatchDebitCached;
|
||||
}
|
||||
}
|
||||
return debit;
|
||||
}
|
||||
|
||||
CAmount GetCredit(const isminefilter& filter) const
|
||||
{
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
int64_t credit = 0;
|
||||
if (filter & ISMINE_SPENDABLE)
|
||||
{
|
||||
// GetBalance can assume transactions in mapWallet won't change
|
||||
if (fCreditCached)
|
||||
credit += nCreditCached;
|
||||
else
|
||||
{
|
||||
nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
|
||||
fCreditCached = true;
|
||||
credit += nCreditCached;
|
||||
}
|
||||
}
|
||||
if (filter & ISMINE_WATCH_ONLY)
|
||||
{
|
||||
if (fWatchCreditCached)
|
||||
credit += nWatchCreditCached;
|
||||
else
|
||||
{
|
||||
nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
|
||||
fWatchCreditCached = true;
|
||||
credit += nWatchCreditCached;
|
||||
}
|
||||
}
|
||||
return credit;
|
||||
}
|
||||
|
||||
CAmount GetImmatureCredit(bool fUseCache=true) const
|
||||
{
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
|
||||
{
|
||||
if (fUseCache && fImmatureCreditCached)
|
||||
return nImmatureCreditCached;
|
||||
nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
|
||||
fImmatureCreditCached = true;
|
||||
return nImmatureCreditCached;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CAmount GetAvailableCredit(bool fUseCache=true) const
|
||||
{
|
||||
if (pwallet == 0)
|
||||
return 0;
|
||||
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
if (fUseCache && fAvailableCreditCached)
|
||||
return nAvailableCreditCached;
|
||||
|
||||
CAmount nCredit = 0;
|
||||
uint256 hashTx = GetHash();
|
||||
for (unsigned int i = 0; i < vout.size(); i++)
|
||||
{
|
||||
if (!pwallet->IsSpent(hashTx, i))
|
||||
{
|
||||
const CTxOut &txout = vout[i];
|
||||
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
|
||||
if (!MoneyRange(nCredit))
|
||||
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
nAvailableCreditCached = nCredit;
|
||||
fAvailableCreditCached = true;
|
||||
return nCredit;
|
||||
}
|
||||
|
||||
CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const
|
||||
{
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
|
||||
{
|
||||
if (fUseCache && fImmatureWatchCreditCached)
|
||||
return nImmatureWatchCreditCached;
|
||||
nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
|
||||
fImmatureWatchCreditCached = true;
|
||||
return nImmatureWatchCreditCached;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const
|
||||
{
|
||||
if (pwallet == 0)
|
||||
return 0;
|
||||
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
if (IsCoinBase() && GetBlocksToMaturity() > 0)
|
||||
return 0;
|
||||
|
||||
if (fUseCache && fAvailableWatchCreditCached)
|
||||
return nAvailableWatchCreditCached;
|
||||
|
||||
CAmount nCredit = 0;
|
||||
for (unsigned int i = 0; i < vout.size(); i++)
|
||||
{
|
||||
if (!pwallet->IsSpent(GetHash(), i))
|
||||
{
|
||||
const CTxOut &txout = vout[i];
|
||||
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
|
||||
if (!MoneyRange(nCredit))
|
||||
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
nAvailableWatchCreditCached = nCredit;
|
||||
fAvailableWatchCreditCached = true;
|
||||
return nCredit;
|
||||
}
|
||||
|
||||
CAmount GetChange() const
|
||||
{
|
||||
if (fChangeCached)
|
||||
return nChangeCached;
|
||||
nChangeCached = pwallet->GetChange(*this);
|
||||
fChangeCached = true;
|
||||
return nChangeCached;
|
||||
}
|
||||
|
||||
void GetAmounts(std::list<COutputEntry>& listReceived,
|
||||
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
|
||||
|
||||
void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
|
||||
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
|
||||
|
||||
bool IsFromMe(const isminefilter& filter) const
|
||||
{
|
||||
return (GetDebit(filter) > 0);
|
||||
}
|
||||
|
||||
bool IsTrusted() const
|
||||
{
|
||||
// Quick answer in most cases
|
||||
if (!IsFinalTx(*this))
|
||||
return false;
|
||||
int nDepth = GetDepthInMainChain();
|
||||
if (nDepth >= 1)
|
||||
return true;
|
||||
if (nDepth < 0)
|
||||
return false;
|
||||
if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
|
||||
return false;
|
||||
|
||||
// Trusted if all inputs are from us and are in the mempool:
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
{
|
||||
// Transactions not sent by us: not trusted
|
||||
const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
|
||||
if (parent == NULL)
|
||||
return false;
|
||||
const CTxOut& parentOut = parent->vout[txin.prevout.n];
|
||||
if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteToDisk(CWalletDB *pwalletdb);
|
||||
|
||||
int64_t GetTxTime() const;
|
||||
int GetRequestCount() const;
|
||||
|
||||
void RelayWalletTransaction();
|
||||
|
||||
std::set<uint256> GetConflicts() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class COutput
|
||||
{
|
||||
public:
|
||||
const CWalletTx *tx;
|
||||
int i;
|
||||
int nDepth;
|
||||
bool fSpendable;
|
||||
|
||||
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn)
|
||||
{
|
||||
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Private key that includes an expiration date in case it never gets used. */
|
||||
class CWalletKey
|
||||
{
|
||||
public:
|
||||
CPrivKey vchPrivKey;
|
||||
int64_t nTimeCreated;
|
||||
int64_t nTimeExpires;
|
||||
std::string strComment;
|
||||
//! todo: add something to note what created it (user, getnewaddress, change)
|
||||
//! maybe should have a map<string, string> property map
|
||||
|
||||
CWalletKey(int64_t nExpires=0);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
if (!(nType & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(vchPrivKey);
|
||||
READWRITE(nTimeCreated);
|
||||
READWRITE(nTimeExpires);
|
||||
READWRITE(LIMITED_STRING(strComment, 65536));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Account information.
|
||||
* Stored in wallet with key "acc"+string account name.
|
||||
|
|
Loading…
Reference in a new issue