Implement a hard fork for extended/infinite claim expiration times #112

Closed
lbrynaut wants to merge 247 commits from claim-expiration into master
76 changed files with 1617 additions and 1172 deletions
Showing only changes of commit cd3f33c1fc - Show all commits

View file

@ -38,7 +38,7 @@ AC_DEFUN([BITCOIN_FIND_BDB48],[
done done
if test "x$bdbpath" = "xX"; then if test "x$bdbpath" = "xX"; then
AC_MSG_RESULT([no]) 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 elif test "x$bdb48path" = "xX"; then
BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx) 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])],[ AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[

View file

@ -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 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 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 on new hosts. For now, a build architecture of x86_64 is assumed, either on
Linux or OSX. Linux or OSX.

View file

@ -205,7 +205,7 @@ endef
# These functions create the build targets for each package. They must be # 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 # 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 # 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. # happened to be computed already.
#set the type for host/build packages. #set the type for host/build packages.

View file

@ -3,7 +3,7 @@ Bitcoin Core 0.10.99
Setup 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 Running
--------------------- ---------------------

View file

@ -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.

View file

@ -159,7 +159,7 @@ tar -xzvf db-4.8.30.NC.tar.gz
# Build the library and install to our prefix # Build the library and install to our prefix
cd db-4.8.30.NC/build_unix/ 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 ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX
make install make install
@ -196,7 +196,7 @@ Hardening enables the following features:
* Position Independent Executable * Position Independent Executable
Build position independent code to take advantage of Address Space Layout Randomization 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 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 The stack and heap are randomly located by default but this allows the code section to be
randomly located as well. randomly located as well.

View file

@ -24,7 +24,7 @@ Table of Contents
- [Connecting to the VM](#connecting-to-the-vm) - [Connecting to the VM](#connecting-to-the-vm)
- [Setting up Debian for gitian building](#setting-up-debian-for-gitian-building) - [Setting up Debian for gitian building](#setting-up-debian-for-gitian-building)
- [Installing gitian](#installing-gitian) - [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) - [Getting and building the inputs](#getting-and-building-the-inputs)
- [Building Bitcoin](#building-bitcoin) - [Building Bitcoin](#building-bitcoin)
- [Building an alternative repository](#building-an-alternative-repository) - [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 - Disk size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side
- Push the `Create` button - 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 This DVD image can be validated using a SHA256 hashing tool, for example on
Unixy OSes by entering the following in a terminal: 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) # (must return OK)
After creating the VM, we need to configure it. 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 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. - 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*. **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 ```bash
git clone https://github.com/devrandom/gitian-builder.git git clone https://github.com/devrandom/gitian-builder.git
git clone https://github.com/bitcoin/bitcoin 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. Gitian needs a virtual image of the operating system to build in.
Currently this is Ubuntu Precise for x86_64. Currently this is Ubuntu Precise x86_64.
These images will be copied and used every time that a build is started to This image will be copied and used every time that a build is started to
make sure that the build is deterministic. 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`: Execute the following as user `debian`:
@ -303,7 +300,7 @@ cd gitian-builder
bin/make-base-vm --lxc --arch amd64 --suite precise 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*. **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. 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. 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 At any time you can check the package installation and build progress with
```bash ```bash
tail -f var/install.log tail -f var/install.log
tail -f var/build.log tail -f var/build.log
```
Output from `gbuild` will look something like 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 in `gitian.sigs` to your signing machine and do
```bash ```bash
gpg --detach-sign ${VERSION}-linux/${SIGNER}/bitcoin-build.assert gpg --detach-sign ${VERSION}-linux/${SIGNER}/bitcoin-linux-build.assert
gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-build.assert gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-win-build.assert
gpg --detach-sign ${VERSION}-osx/${SIGNER}/bitcoin-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 This will create the `.sig` files that can be committed together with the `.assert` files to assert your

View file

@ -12,7 +12,7 @@ Base class for new regression tests.
### [listtransactions.py](listtransactions.py) ### [listtransactions.py](listtransactions.py)
Tests for the listtransactions RPC call. Tests for the listtransactions RPC call.
### [util.py](util.sh) ### [util.py](util.py)
Generally useful functions. Generally useful functions.
Bash-based tests, to be ported to Python: Bash-based tests, to be ported to Python:

90
qa/rpc-tests/bipdersig.py Executable file
View 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()

View file

@ -95,6 +95,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
def run_test(self): def run_test(self):
node = self.nodes[0] node = self.nodes[0]
node.setgenerate(True, 1) # Mine a block to leave initial block download
tmpl = node.getblocktemplate() tmpl = node.getblocktemplate()
if 'coinbasetxn' not in tmpl: if 'coinbasetxn' not in tmpl:
rawcoinbase = encodeUNum(tmpl['height']) rawcoinbase = encodeUNum(tmpl['height'])

View file

@ -61,7 +61,7 @@ class WalletTest (BitcoinTestFramework):
walletinfo = self.nodes[0].getwalletinfo() walletinfo = self.nodes[0].getwalletinfo()
assert_equal(walletinfo['immature_balance'], 0) 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.nodes[0].setgenerate(True, 1)
self.sync_all() self.sync_all()

View file

@ -20,8 +20,6 @@ EXTRA_DIST += \
JSON_TEST_FILES = \ JSON_TEST_FILES = \
test/data/script_valid.json \ test/data/script_valid.json \
test/data/base58_keys_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_encode_decode.json \
test/data/base58_keys_invalid.json \ test/data/base58_keys_invalid.json \
test/data/script_invalid.json \ test/data/script_invalid.json \

View file

@ -149,7 +149,7 @@ bool CAlert::CheckSignature() const
{ {
CPubKey key(Params().AlertKey()); CPubKey key(Params().AlertKey());
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
return error("CAlert::CheckSignature() : verify signature failed"); return error("CAlert::CheckSignature(): verify signature failed");
// Now unserialize the data // Now unserialize the data
CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);

View file

@ -436,7 +436,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
BOOST_FOREACH(const CTransaction& txv, txVariants) { BOOST_FOREACH(const CTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); 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; fComplete = false;
} }

View file

@ -186,11 +186,11 @@ public:
vSeeds.clear(); vSeeds.clear();
//vFixedSeeds.clear(); //vFixedSeeds.clear();
base58Prefixes[PUBKEY_ADDRESS] = boost::assign::list_of(0); base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = boost::assign::list_of(5); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
base58Prefixes[SECRET_KEY] = boost::assign::list_of(128); base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E); 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); 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)); 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("bluematt.me", "testnet-seed.bluematt.me"));
//vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de")); //vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
base58Prefixes[PUBKEY_ADDRESS] = boost::assign::list_of(111); base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = boost::assign::list_of(196); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
base58Prefixes[SECRET_KEY] = boost::assign::list_of(239); base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF); 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); 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)); convertSeed6(vFixedSeeds, pnSeed6_test, ARRAYLEN(pnSeed6_test));

View file

@ -81,7 +81,7 @@ private:
fAllOk &= fOk; fAllOk &= fOk;
nTodo -= nNow; nTodo -= nNow;
if (nTodo == 0 && !fMaster) 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(); condMaster.notify_one();
} else { } else {
// first iteration // first iteration

View file

@ -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; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); 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); 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; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); 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)); 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() bool CCryptoKeyStore::SetCrypted()
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
@ -161,20 +174,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{ {
const CPubKey &vchPubKey = (*mi).second.first; const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second; 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; CKey key;
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
if (key.GetPubKey() != vchPubKey)
{ {
keyFail = true; keyFail = true;
break; break;
@ -243,13 +244,7 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{ {
const CPubKey &vchPubKey = (*mi).second.first; const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second; const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CKeyingMaterial vchSecret; return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
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 false; return false;

View file

@ -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. /** Keystore which keeps the private keys encrypted.
* It derives from the basic key store, which is used if no encryption is active. * It derives from the basic key store, which is used if no encryption is active.
*/ */

View file

@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown()
fDbEnvInit = false; fDbEnvInit = false;
int ret = dbenv.close(0); int ret = dbenv.close(0);
if (ret != 0) if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb) if (!fMockDb)
DbEnv(0).remove(path.string().c_str(), 0); DbEnv(0).remove(path.string().c_str(), 0);
} }
@ -75,7 +75,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
boost::filesystem::path pathLogDir = path / "database"; boost::filesystem::path pathLogDir = path / "database";
TryCreateDirectory(pathLogDir); TryCreateDirectory(pathLogDir);
boost::filesystem::path pathErrorFile = path / "db.log"; boost::filesystem::path pathErrorFile = path / "db.log";
LogPrintf("CDBEnv::Open : LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string()); LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
unsigned int nEnvFlags = 0; unsigned int nEnvFlags = 0;
if (GetBoolArg("-privdb", true)) if (GetBoolArg("-privdb", true))
@ -102,7 +102,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
nEnvFlags, nEnvFlags,
S_IRUSR | S_IWUSR); S_IRUSR | S_IWUSR);
if (ret != 0) if (ret != 0)
return error("CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
fDbEnvInit = true; fDbEnvInit = true;
fMockDb = false; fMockDb = false;
@ -112,7 +112,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
void CDBEnv::MakeMock() void CDBEnv::MakeMock()
{ {
if (fDbEnvInit) if (fDbEnvInit)
throw runtime_error("CDBEnv::MakeMock : Already initialized"); throw runtime_error("CDBEnv::MakeMock: Already initialized");
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
@ -135,7 +135,7 @@ void CDBEnv::MakeMock()
DB_PRIVATE, DB_PRIVATE,
S_IRUSR | S_IWUSR); S_IRUSR | S_IWUSR);
if (ret > 0) if (ret > 0)
throw runtime_error(strprintf("CDBEnv::MakeMock : Error %d opening database environment.", ret)); throw runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret));
fDbEnvInit = true; fDbEnvInit = true;
fMockDb = true; fMockDb = true;
@ -172,14 +172,14 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector<CDBEnv::
Db db(&dbenv, 0); Db db(&dbenv, 0);
int result = db.verify(strFile.c_str(), NULL, &strDump, flags); int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
if (result == DB_VERIFY_BAD) { if (result == DB_VERIFY_BAD) {
LogPrintf("CDBEnv::Salvage : Database salvage found errors, all data may not be recoverable.\n"); LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n");
if (!fAggressive) { if (!fAggressive) {
LogPrintf("CDBEnv::Salvage : Rerun with aggressive mode to ignore errors and continue.\n"); LogPrintf("CDBEnv::Salvage: Rerun with aggressive mode to ignore errors and continue.\n");
return false; return false;
} }
} }
if (result != 0 && result != DB_VERIFY_BAD) { if (result != 0 && result != DB_VERIFY_BAD) {
LogPrintf("CDBEnv::Salvage : Database salvage failed with result %d.\n", result); LogPrintf("CDBEnv::Salvage: Database salvage failed with result %d.\n", result);
return false; return false;
} }
@ -233,7 +233,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
{ {
LOCK(bitdb.cs_db); LOCK(bitdb.cs_db);
if (!bitdb.Open(GetDataDir())) if (!bitdb.Open(GetDataDir()))
throw runtime_error("CDB : Failed to open database environment."); throw runtime_error("CDB: Failed to open database environment.");
strFile = strFilename; strFile = strFilename;
++bitdb.mapFileUseCount[strFile]; ++bitdb.mapFileUseCount[strFile];
@ -246,7 +246,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
DbMpoolFile* mpf = pdb->get_mpf(); DbMpoolFile* mpf = pdb->get_mpf();
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
if (ret != 0) if (ret != 0)
throw runtime_error(strprintf("CDB : Failed to configure for no temp file backing for database %s", strFile)); throw runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
} }
ret = pdb->open(NULL, // Txn pointer ret = pdb->open(NULL, // Txn pointer
@ -261,7 +261,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
pdb = NULL; pdb = NULL;
--bitdb.mapFileUseCount[strFile]; --bitdb.mapFileUseCount[strFile];
strFile = ""; strFile = "";
throw runtime_error(strprintf("CDB : Error %d, can't open database %s", ret, strFile)); throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFile));
} }
if (fCreate && !Exists(string("version"))) { if (fCreate && !Exists(string("version"))) {
@ -342,7 +342,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
bitdb.mapFileUseCount.erase(strFile); bitdb.mapFileUseCount.erase(strFile);
bool fSuccess = true; bool fSuccess = true;
LogPrintf("CDB::Rewrite : Rewriting %s...\n", strFile); LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile);
string strFileRes = strFile + ".rewrite"; string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {} { // surround usage of db with extra {}
CDB db(strFile.c_str(), "r"); CDB db(strFile.c_str(), "r");
@ -355,7 +355,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
DB_CREATE, // Flags DB_CREATE, // Flags
0); 0);
if (ret > 0) { if (ret > 0) {
LogPrintf("CDB::Rewrite : Can't create database file %s\n", strFileRes); LogPrintf("CDB::Rewrite: Can't create database file %s\n", strFileRes);
fSuccess = false; fSuccess = false;
} }
@ -404,7 +404,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
fSuccess = false; fSuccess = false;
} }
if (!fSuccess) if (!fSuccess)
LogPrintf("CDB::Rewrite : Failed to rewrite database file %s\n", strFileRes); LogPrintf("CDB::Rewrite: Failed to rewrite database file %s\n", strFileRes);
return fSuccess; return fSuccess;
} }
} }
@ -418,7 +418,7 @@ void CDBEnv::Flush(bool fShutdown)
{ {
int64_t nStart = GetTimeMillis(); int64_t nStart = GetTimeMillis();
// Flush log data to the actual data file on all files that are not in use // Flush log data to the actual data file on all files that are not in use
LogPrint("db", "CDBEnv::Flush : Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); LogPrint("db", "CDBEnv::Flush: Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started");
if (!fDbEnvInit) if (!fDbEnvInit)
return; return;
{ {
@ -427,21 +427,21 @@ void CDBEnv::Flush(bool fShutdown)
while (mi != mapFileUseCount.end()) { while (mi != mapFileUseCount.end()) {
string strFile = (*mi).first; string strFile = (*mi).first;
int nRefCount = (*mi).second; int nRefCount = (*mi).second;
LogPrint("db", "CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount); LogPrint("db", "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
if (nRefCount == 0) { if (nRefCount == 0) {
// Move log data to the dat file // Move log data to the dat file
CloseDb(strFile); CloseDb(strFile);
LogPrint("db", "CDBEnv::Flush : %s checkpoint\n", strFile); LogPrint("db", "CDBEnv::Flush: %s checkpoint\n", strFile);
dbenv.txn_checkpoint(0, 0, 0); dbenv.txn_checkpoint(0, 0, 0);
LogPrint("db", "CDBEnv::Flush : %s detach\n", strFile); LogPrint("db", "CDBEnv::Flush: %s detach\n", strFile);
if (!fMockDb) if (!fMockDb)
dbenv.lsn_reset(strFile.c_str(), 0); dbenv.lsn_reset(strFile.c_str(), 0);
LogPrint("db", "CDBEnv::Flush : %s closed\n", strFile); LogPrint("db", "CDBEnv::Flush: %s closed\n", strFile);
mapFileUseCount.erase(mi++); mapFileUseCount.erase(mi++);
} else } else
mi++; mi++;
} }
LogPrint("db", "CDBEnv::Flush : Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); LogPrint("db", "CDBEnv::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
if (fShutdown) { if (fShutdown) {
char** listp; char** listp;
if (mapFileUseCount.empty()) { if (mapFileUseCount.empty()) {

View file

@ -236,6 +236,26 @@ bool static Bind(const CService &addr, unsigned int flags) {
return true; 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) std::string HelpMessage(HelpMessageMode mode)
{ {
// When adding new options to the categories, please keep and ensure alphabetical ordering. // 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) if (fServer)
{ {
uiInterface.InitMessage.connect(SetRPCWarmupStatus); uiInterface.InitMessage.connect(SetRPCWarmupStatus);
RPCServer::OnStopped(&OnRPCStopped);
RPCServer::OnPreCommand(&OnRPCPreCommand);
StartRPCThreads(); StartRPCThreads();
} }
@ -979,7 +1001,7 @@ bool AppInit2(boost::thread_group& threadGroup)
} catch (const boost::filesystem::filesystem_error& e) { } catch (const boost::filesystem::filesystem_error& e) {
// Note: hardlink creation failing is not a disaster, it just means // Note: hardlink creation failing is not a disaster, it just means
// blocks will get re-downloaded from peers. // blocks will get re-downloaded from peers.
LogPrintf("Error hardlinking blk%04u.dat : %s\n", i, e.what()); LogPrintf("Error hardlinking blk%04u.dat: %s\n", i, e.what());
break; break;
} }
} }

View file

@ -7,8 +7,6 @@
#include "crypter.h" #include "crypter.h"
#include "key.h" #include "key.h"
#include "script/script.h"
#include "script/standard.h"
#include "util.h" #include "util.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -36,7 +34,7 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
bool CBasicKeyStore::AddCScript(const CScript& redeemScript) bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{ {
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
return error("CBasicKeyStore::AddCScript() : redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE); return error("CBasicKeyStore::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
mapScripts[CScriptID(redeemScript)] = redeemScript; mapScripts[CScriptID(redeemScript)] = redeemScript;

View file

@ -8,14 +8,13 @@
#include "key.h" #include "key.h"
#include "pubkey.h" #include "pubkey.h"
#include "script/script.h"
#include "script/standard.h"
#include "sync.h" #include "sync.h"
#include <boost/signals2/signal.hpp> #include <boost/signals2/signal.hpp>
#include <boost/variant.hpp> #include <boost/variant.hpp>
class CScript;
class CScriptID;
/** A virtual base class for key stores */ /** A virtual base class for key stores */
class CKeyStore class CKeyStore
{ {

View file

@ -747,7 +747,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// non-standard. Note that this EvalScript() call will // non-standard. Note that this EvalScript() call will
// be quick, because if there are any operations // be quick, because if there are any operations
// beside "push data" in the scriptSig // beside "push data" in the scriptSig
// IsStandard() will have already returned false // IsStandardTx() will have already returned false
// and this method isn't called. // and this method isn't called.
vector<vector<unsigned char> > stack; vector<vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker())) if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
@ -824,14 +824,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{ {
// Basic checks that don't depend on any context // Basic checks that don't depend on any context
if (tx.vin.empty()) if (tx.vin.empty())
return state.DoS(10, error("CheckTransaction() : vin empty"), return state.DoS(10, error("CheckTransaction(): vin empty"),
REJECT_INVALID, "bad-txns-vin-empty"); REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty()) if (tx.vout.empty())
return state.DoS(10, error("CheckTransaction() : vout empty"), return state.DoS(10, error("CheckTransaction(): vout empty"),
REJECT_INVALID, "bad-txns-vout-empty"); REJECT_INVALID, "bad-txns-vout-empty");
// Size limits // Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckTransaction() : size limits failed"), return state.DoS(100, error("CheckTransaction(): size limits failed"),
REJECT_INVALID, "bad-txns-oversize"); REJECT_INVALID, "bad-txns-oversize");
// Check for negative or overflow output values // Check for negative or overflow output values
@ -839,14 +839,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
BOOST_FOREACH(const CTxOut& txout, tx.vout) BOOST_FOREACH(const CTxOut& txout, tx.vout)
{ {
if (txout.nValue < 0) if (txout.nValue < 0)
return state.DoS(100, error("CheckTransaction() : txout.nValue negative"), return state.DoS(100, error("CheckTransaction(): txout.nValue negative"),
REJECT_INVALID, "bad-txns-vout-negative"); REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY) if (txout.nValue > MAX_MONEY)
return state.DoS(100, error("CheckTransaction() : txout.nValue too high"), return state.DoS(100, error("CheckTransaction(): txout.nValue too high"),
REJECT_INVALID, "bad-txns-vout-toolarge"); REJECT_INVALID, "bad-txns-vout-toolarge");
nValueOut += txout.nValue; nValueOut += txout.nValue;
if (!MoneyRange(nValueOut)) if (!MoneyRange(nValueOut))
return state.DoS(100, error("CheckTransaction() : txout total out of range"), return state.DoS(100, error("CheckTransaction(): txout total out of range"),
REJECT_INVALID, "bad-txns-txouttotal-toolarge"); REJECT_INVALID, "bad-txns-txouttotal-toolarge");
} }
@ -855,7 +855,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
BOOST_FOREACH(const CTxIn& txin, tx.vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
{ {
if (vInOutPoints.count(txin.prevout)) if (vInOutPoints.count(txin.prevout))
return state.DoS(100, error("CheckTransaction() : duplicate inputs"), return state.DoS(100, error("CheckTransaction(): duplicate inputs"),
REJECT_INVALID, "bad-txns-inputs-duplicate"); REJECT_INVALID, "bad-txns-inputs-duplicate");
vInOutPoints.insert(txin.prevout); vInOutPoints.insert(txin.prevout);
} }
@ -863,14 +863,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
if (tx.IsCoinBase()) if (tx.IsCoinBase())
{ {
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, error("CheckTransaction() : coinbase script size"), return state.DoS(100, error("CheckTransaction(): coinbase script size"),
REJECT_INVALID, "bad-cb-length"); REJECT_INVALID, "bad-cb-length");
} }
else else
{ {
BOOST_FOREACH(const CTxIn& txin, tx.vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull()) if (txin.prevout.IsNull())
return state.DoS(10, error("CheckTransaction() : prevout is null"), return state.DoS(10, error("CheckTransaction(): prevout is null"),
REJECT_INVALID, "bad-txns-prevout-null"); REJECT_INVALID, "bad-txns-prevout-null");
} }
@ -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 AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectInsaneFee) bool* pfMissingInputs, bool fRejectAbsurdFee)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
if (pfMissingInputs) if (pfMissingInputs)
@ -926,7 +926,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
string reason; string reason;
if (Params().RequireStandard() && !IsStandardTx(tx, reason)) if (Params().RequireStandard() && !IsStandardTx(tx, reason))
return state.DoS(0, return state.DoS(0,
error("AcceptToMemoryPool : nonstandard transaction: %s", reason), error("AcceptToMemoryPool: nonstandard transaction: %s", reason),
REJECT_NONSTANDARD, reason); REJECT_NONSTANDARD, reason);
// Only accept nLockTime-using transactions that can be mined in the next // Only accept nLockTime-using transactions that can be mined in the next
@ -946,7 +946,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// timestamp applications where it matters. // timestamp applications where it matters.
if (!IsFinalTx(tx, chainActive.Height() + 1)) if (!IsFinalTx(tx, chainActive.Height() + 1))
return state.DoS(0, return state.DoS(0,
error("AcceptToMemoryPool : non-final"), error("AcceptToMemoryPool: non-final"),
REJECT_NONSTANDARD, "non-final"); REJECT_NONSTANDARD, "non-final");
// is it already in the memory pool? // is it already in the memory pool?
@ -995,7 +995,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// are the actual inputs available? // are the actual inputs available?
if (!view.HaveInputs(tx)) if (!view.HaveInputs(tx))
return state.Invalid(error("AcceptToMemoryPool : inputs already spent"), return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),
REJECT_DUPLICATE, "bad-txns-inputs-spent"); REJECT_DUPLICATE, "bad-txns-inputs-spent");
// Bring the best block into scope // Bring the best block into scope
@ -1020,7 +1020,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
nSigOps += GetP2SHSigOpCount(tx, view); nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_STANDARD_TX_SIGOPS) if (nSigOps > MAX_STANDARD_TX_SIGOPS)
return state.DoS(0, return state.DoS(0,
error("AcceptToMemoryPool : too many sigops %s, %d > %d", error("AcceptToMemoryPool: too many sigops %s, %d > %d",
hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS), hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),
REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
@ -1034,7 +1034,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Don't accept it if it can't get into a block // Don't accept it if it can't get into a block
CAmount txMinFee = GetMinRelayFee(tx, nSize, true); CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee) if (fLimitFree && nFees < txMinFee)
return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d", return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",
hash.ToString(), nFees, txMinFee), hash.ToString(), nFees, txMinFee),
REJECT_INSUFFICIENTFEE, "insufficient fee"); REJECT_INSUFFICIENTFEE, "insufficient fee");
@ -1061,14 +1061,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// -limitfreerelay unit is thousand-bytes-per-minute // -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB // At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000) if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
return state.DoS(0, error("AcceptToMemoryPool : free transaction rejected by rate limiter"), return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"),
REJECT_INSUFFICIENTFEE, "rate limited free transaction"); REJECT_INSUFFICIENTFEE, "rate limited free transaction");
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize; dFreeCount += nSize;
} }
if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
return error("AcceptToMemoryPool: insane fees %s, %d > %d", return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",
hash.ToString(), hash.ToString(),
nFees, ::minRelayTxFee.GetFee(nSize) * 10000); nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
@ -1127,11 +1127,11 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
fseek(file.Get(), postx.nTxOffset, SEEK_CUR); fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
file >> txOut; file >> txOut;
} catch (const std::exception& e) { } catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); return error("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
hashBlock = header.GetHash(); hashBlock = header.GetHash();
if (txOut.GetHash() != hash) if (txOut.GetHash() != hash)
return error("%s : txid mismatch", __func__); return error("%s: txid mismatch", __func__);
return true; return true;
} }
} }
@ -1180,7 +1180,7 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
// Open history file to append // Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull()) if (fileout.IsNull())
return error("WriteBlockToDisk : OpenBlockFile failed"); return error("WriteBlockToDisk: OpenBlockFile failed");
// Write index header // Write index header
unsigned int nSize = fileout.GetSerializeSize(block); unsigned int nSize = fileout.GetSerializeSize(block);
@ -1189,7 +1189,7 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
// Write block // Write block
long fileOutPos = ftell(fileout.Get()); long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0) if (fileOutPos < 0)
return error("WriteBlockToDisk : ftell failed"); return error("WriteBlockToDisk: ftell failed");
pos.nPos = (unsigned int)fileOutPos; pos.nPos = (unsigned int)fileOutPos;
fileout << block; fileout << block;
@ -1203,19 +1203,19 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
// Open history file to read // Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull()) if (filein.IsNull())
return error("ReadBlockFromDisk : OpenBlockFile failed"); return error("ReadBlockFromDisk: OpenBlockFile failed");
// Read block // Read block
try { try {
filein >> block; filein >> block;
} }
catch (const std::exception& e) { catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); return error("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
// Check the header // Check the header
if (!CheckProofOfWork(block.GetHash(), block.nBits)) if (!CheckProofOfWork(block.GetHash(), block.nBits))
return error("ReadBlockFromDisk : Errors in block header"); return error("ReadBlockFromDisk: Errors in block header");
return true; return true;
} }
@ -1225,7 +1225,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
if (!ReadBlockFromDisk(block, pindex->GetBlockPos())) if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
return false; return false;
if (block.GetHash() != pindex->GetBlockHash()) if (block.GetHash() != pindex->GetBlockHash())
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index"); return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index");
return true; return true;
} }
@ -1426,8 +1426,8 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool CScriptCheck::operator()() { bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; 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 ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
} }
return true; return true;
} }
@ -1442,7 +1442,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network. // for an attacker to attempt to split the network.
if (!inputs.HaveInputs(tx)) if (!inputs.HaveInputs(tx))
return state.Invalid(error("CheckInputs() : %s inputs unavailable", tx.GetHash().ToString())); return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
// While checking, GetBestBlock() refers to the parent block. // While checking, GetBestBlock() refers to the parent block.
// This is also true for mempool checks. // This is also true for mempool checks.
@ -1460,31 +1460,31 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
if (coins->IsCoinBase()) { if (coins->IsCoinBase()) {
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) if (nSpendHeight - coins->nHeight < COINBASE_MATURITY)
return state.Invalid( return state.Invalid(
error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
} }
// Check for negative or overflow input values // Check for negative or overflow input values
nValueIn += coins->vout[prevout.n].nValue; nValueIn += coins->vout[prevout.n].nValue;
if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs() : txin values out of range"), return state.DoS(100, error("CheckInputs(): txin values out of range"),
REJECT_INVALID, "bad-txns-inputvalues-outofrange"); REJECT_INVALID, "bad-txns-inputvalues-outofrange");
} }
if (nValueIn < tx.GetValueOut()) if (nValueIn < tx.GetValueOut())
return state.DoS(100, error("CheckInputs() : %s value in (%s) < value out (%s)", return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s)",
tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())), tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())),
REJECT_INVALID, "bad-txns-in-belowout"); REJECT_INVALID, "bad-txns-in-belowout");
// Tally transaction fees // Tally transaction fees
CAmount nTxFee = nValueIn - tx.GetValueOut(); CAmount nTxFee = nValueIn - tx.GetValueOut();
if (nTxFee < 0) if (nTxFee < 0)
return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()), return state.DoS(100, error("CheckInputs(): %s nTxFee < 0", tx.GetHash().ToString()),
REJECT_INVALID, "bad-txns-fee-negative"); REJECT_INVALID, "bad-txns-fee-negative");
nFees += nTxFee; nFees += nTxFee;
if (!MoneyRange(nFees)) if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs() : nFees out of range"), return state.DoS(100, error("CheckInputs(): nFees out of range"),
REJECT_INVALID, "bad-txns-fee-outofrange"); REJECT_INVALID, "bad-txns-fee-outofrange");
// The first loop above does all the inexpensive checks. // The first loop above does all the inexpensive checks.
@ -1541,7 +1541,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
// Open history file to append // Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull()) if (fileout.IsNull())
return error("%s : OpenUndoFile failed", __func__); return error("%s: OpenUndoFile failed", __func__);
// Write index header // Write index header
unsigned int nSize = fileout.GetSerializeSize(blockundo); unsigned int nSize = fileout.GetSerializeSize(blockundo);
@ -1550,7 +1550,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
// Write undo data // Write undo data
long fileOutPos = ftell(fileout.Get()); long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0) if (fileOutPos < 0)
return error("%s : ftell failed", __func__); return error("%s: ftell failed", __func__);
pos.nPos = (unsigned int)fileOutPos; pos.nPos = (unsigned int)fileOutPos;
fileout << blockundo; fileout << blockundo;
@ -1568,7 +1568,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
// Open history file to read // Open history file to read
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull()) if (filein.IsNull())
return error("%s : OpenBlockFile failed", __func__); return error("%s: OpenBlockFile failed", __func__);
// Read block // Read block
uint256 hashChecksum; uint256 hashChecksum;
@ -1577,7 +1577,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
filein >> hashChecksum; filein >> hashChecksum;
} }
catch (const std::exception& e) { catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); return error("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
// Verify checksum // Verify checksum
@ -1585,7 +1585,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
hasher << hashBlock; hasher << hashBlock;
hasher << blockundo; hasher << blockundo;
if (hashChecksum != hasher.GetHash()) if (hashChecksum != hasher.GetHash())
return error("%s : Checksum mismatch", __func__); return error("%s: Checksum mismatch", __func__);
return true; return true;
} }
@ -1604,12 +1604,12 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
CBlockUndo blockUndo; CBlockUndo blockUndo;
CDiskBlockPos pos = pindex->GetUndoPos(); CDiskBlockPos pos = pindex->GetUndoPos();
if (pos.IsNull()) if (pos.IsNull())
return error("DisconnectBlock() : no undo data available"); return error("DisconnectBlock(): no undo data available");
if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash()))
return error("DisconnectBlock() : failure reading undo data"); return error("DisconnectBlock(): failure reading undo data");
if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock() : block and undo data inconsistent"); return error("DisconnectBlock(): block and undo data inconsistent");
// undo transactions in reverse order // undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) { for (int i = block.vtx.size() - 1; i >= 0; i--) {
@ -1632,7 +1632,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (outsBlock.nVersion < 0) if (outsBlock.nVersion < 0)
outs->nVersion = outsBlock.nVersion; outs->nVersion = outsBlock.nVersion;
if (*outs != outsBlock) if (*outs != outsBlock)
fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted"); fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted");
// remove any NCC claims // remove any NCC claims
for (unsigned int i = 0; i < tx.vout.size(); ++i) for (unsigned int i = 0; i < tx.vout.size(); ++i)
@ -1658,7 +1658,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (i > 0) { // not coinbases if (i > 0) { // not coinbases
const CTxUndo &txundo = blockUndo.vtxundo[i-1]; const CTxUndo &txundo = blockUndo.vtxundo[i-1];
if (txundo.vprevout.size() != tx.vin.size()) if (txundo.vprevout.size() != tx.vin.size())
return error("DisconnectBlock() : transaction and undo data inconsistent"); return error("DisconnectBlock(): transaction and undo data inconsistent");
for (unsigned int j = tx.vin.size(); j-- > 0;) { for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint &out = tx.vin[j].prevout; const COutPoint &out = tx.vin[j].prevout;
const CTxInUndo &undo = txundo.vprevout[j]; const CTxInUndo &undo = txundo.vprevout[j];
@ -1666,17 +1666,17 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (undo.nHeight != 0) { if (undo.nHeight != 0) {
// undo data contains height: this is the last output of the prevout tx being spent // undo data contains height: this is the last output of the prevout tx being spent
if (!coins->IsPruned()) if (!coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing transaction"); fClean = fClean && error("DisconnectBlock(): undo data overwriting existing transaction");
coins->Clear(); coins->Clear();
coins->fCoinBase = undo.fCoinBase; coins->fCoinBase = undo.fCoinBase;
coins->nHeight = undo.nHeight; coins->nHeight = undo.nHeight;
coins->nVersion = undo.nVersion; coins->nVersion = undo.nVersion;
} else { } else {
if (coins->IsPruned()) if (coins->IsPruned())
fClean = fClean && error("DisconnectBlock() : undo data adding output to missing transaction"); fClean = fClean && error("DisconnectBlock(): undo data adding output to missing transaction");
} }
if (coins->IsAvailable(out.n)) if (coins->IsAvailable(out.n))
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output"); fClean = fClean && error("DisconnectBlock(): undo data overwriting existing output");
if (coins->vout.size() < out.n+1) if (coins->vout.size() < out.n+1)
coins->vout.resize(out.n+1); coins->vout.resize(out.n+1);
@ -1785,7 +1785,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
BOOST_FOREACH(const CTransaction& tx, block.vtx) { BOOST_FOREACH(const CTransaction& tx, block.vtx) {
const CCoins* coins = view.AccessCoins(tx.GetHash()); const CCoins* coins = view.AccessCoins(tx.GetHash());
if (coins && !coins->IsPruned()) if (coins && !coins->IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30"); REJECT_INVALID, "bad-txns-BIP30");
} }
} }
@ -1796,6 +1796,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; 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; CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
@ -1815,13 +1820,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
nInputs += tx.vin.size(); nInputs += tx.vin.size();
nSigOps += GetLegacySigOpCount(tx); nSigOps += GetLegacySigOpCount(tx);
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many sigops"), return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops"); REJECT_INVALID, "bad-blk-sigops");
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
{ {
if (!view.HaveInputs(tx)) if (!view.HaveInputs(tx))
return state.DoS(100, error("ConnectBlock() : inputs missing/spent"), return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
REJECT_INVALID, "bad-txns-inputs-missingorspent"); REJECT_INVALID, "bad-txns-inputs-missingorspent");
if (fStrictPayToScriptHash) if (fStrictPayToScriptHash)
@ -1831,7 +1836,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// an incredibly-expensive-to-validate block. // an incredibly-expensive-to-validate block.
nSigOps += GetP2SHSigOpCount(tx, view); nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock() : too many sigops"), return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops"); REJECT_INVALID, "bad-blk-sigops");
} }
@ -1901,7 +1906,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (block.vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) if (block.vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
return state.DoS(100, return state.DoS(100,
error("ConnectBlock() : coinbase pays too much (actual=%d vs limit=%d)", error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)), block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)),
REJECT_INVALID, "bad-cb-amount"); REJECT_INVALID, "bad-cb-amount");
@ -1919,7 +1924,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (pindex->GetUndoPos().IsNull()) { if (pindex->GetUndoPos().IsNull()) {
CDiskBlockPos pos; CDiskBlockPos pos;
if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock() : FindUndoPos failed"); return error("ConnectBlock(): FindUndoPos failed");
if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash())) if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash()))
return state.Abort("Failed to write undo data"); return state.Abort("Failed to write undo data");
@ -2072,7 +2077,7 @@ bool static DisconnectTip(CValidationState &state) {
CCoinsViewCache view(pcoinsTip); CCoinsViewCache view(pcoinsTip);
CNCCTrieCache trieCache(pnccTrie); CNCCTrieCache trieCache(pnccTrie);
if (!DisconnectBlock(block, state, pindexDelete, view, trieCache)) if (!DisconnectBlock(block, state, pindexDelete, view, trieCache))
return error("DisconnectTip() : DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
assert(view.Flush()); assert(view.Flush());
assert(trieCache.flush()); assert(trieCache.flush());
} }
@ -2134,7 +2139,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
if (!rv) { if (!rv) {
if (state.IsInvalid()) if (state.IsInvalid())
InvalidBlockFound(pindexNew, state); InvalidBlockFound(pindexNew, state);
return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
} }
mapBlockSource.erase(inv.hash); mapBlockSource.erase(inv.hash);
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
@ -2572,12 +2577,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
{ {
// Check proof of work matches claimed amount // Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits))
return state.DoS(50, error("CheckBlockHeader() : proof of work failed"), return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),
REJECT_INVALID, "high-hash"); REJECT_INVALID, "high-hash");
// Check timestamp // Check timestamp
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return state.Invalid(error("CheckBlockHeader() : block timestamp too far in the future"), return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),
REJECT_INVALID, "time-too-new"); REJECT_INVALID, "time-too-new");
return true; return true;
@ -2597,14 +2602,14 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
bool mutated; bool mutated;
uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated); uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated);
if (block.hashMerkleRoot != hashMerkleRoot2) if (block.hashMerkleRoot != hashMerkleRoot2)
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), return state.DoS(100, error("CheckBlock(): hashMerkleRoot mismatch"),
REJECT_INVALID, "bad-txnmrklroot", true); REJECT_INVALID, "bad-txnmrklroot", true);
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences // Check for merkle tree malleability (CVE-2012-2459): repeating sequences
// of transactions in a block without affecting the merkle root of a block, // of transactions in a block without affecting the merkle root of a block,
// while still invalidating it. // while still invalidating it.
if (mutated) if (mutated)
return state.DoS(100, error("CheckBlock() : duplicate transaction"), return state.DoS(100, error("CheckBlock(): duplicate transaction"),
REJECT_INVALID, "bad-txns-duplicate", true); REJECT_INVALID, "bad-txns-duplicate", true);
} }
@ -2614,22 +2619,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
// Size limits // Size limits
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckBlock() : size limits failed"), return state.DoS(100, error("CheckBlock(): size limits failed"),
REJECT_INVALID, "bad-blk-length"); REJECT_INVALID, "bad-blk-length");
// First transaction must be coinbase, the rest must not be // First transaction must be coinbase, the rest must not be
if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
return state.DoS(100, error("CheckBlock() : first tx is not coinbase"), return state.DoS(100, error("CheckBlock(): first tx is not coinbase"),
REJECT_INVALID, "bad-cb-missing"); REJECT_INVALID, "bad-cb-missing");
for (unsigned int i = 1; i < block.vtx.size(); i++) for (unsigned int i = 1; i < block.vtx.size(); i++)
if (block.vtx[i].IsCoinBase()) if (block.vtx[i].IsCoinBase())
return state.DoS(100, error("CheckBlock() : more than one coinbase"), return state.DoS(100, error("CheckBlock(): more than one coinbase"),
REJECT_INVALID, "bad-cb-multiple"); REJECT_INVALID, "bad-cb-multiple");
// Check transactions // Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state)) if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed"); return error("CheckBlock(): CheckTransaction failed");
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, block.vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
@ -2637,7 +2642,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
nSigOps += GetLegacySigOpCount(tx); nSigOps += GetLegacySigOpCount(tx);
} }
if (nSigOps > MAX_BLOCK_SIGOPS) if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"), return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"),
REJECT_INVALID, "bad-blk-sigops", true); REJECT_INVALID, "bad-blk-sigops", true);
return true; return true;
@ -2656,28 +2661,35 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
// Check proof of work // Check proof of work
if ((!Params().SkipProofOfWorkCheck()) && if ((!Params().SkipProofOfWorkCheck()) &&
(block.nBits != GetNextWorkRequired(pindexPrev, &block))) (block.nBits != GetNextWorkRequired(pindexPrev, &block)))
return state.DoS(100, error("%s : incorrect proof of work", __func__), return state.DoS(100, error("%s: incorrect proof of work", __func__),
REJECT_INVALID, "bad-diffbits"); REJECT_INVALID, "bad-diffbits");
// Check timestamp against prev // Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(error("%s : block's timestamp is too early", __func__), return state.Invalid(error("%s: block's timestamp is too early", __func__),
REJECT_INVALID, "time-too-old"); REJECT_INVALID, "time-too-old");
// Check that the block chain matches the known block chain up to a checkpoint // Check that the block chain matches the known block chain up to a checkpoint
if (!Checkpoints::CheckBlock(nHeight, hash)) if (!Checkpoints::CheckBlock(nHeight, hash))
return state.DoS(100, error("%s : rejected by checkpoint lock-in at %d", __func__, nHeight), return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),
REJECT_CHECKPOINT, "checkpoint mismatch"); REJECT_CHECKPOINT, "checkpoint mismatch");
// Don't accept any forks from the main chain prior to last checkpoint // Don't accept any forks from the main chain prior to last checkpoint
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(); CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint();
if (pcheckpoint && nHeight < pcheckpoint->nHeight) if (pcheckpoint && nHeight < pcheckpoint->nHeight)
return state.DoS(100, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight)); return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority()))
{ {
return state.Invalid(error("%s : rejected nVersion=1 block", __func__), return state.Invalid(error("%s: rejected nVersion=1 block", __func__),
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"); REJECT_OBSOLETE, "bad-version");
} }
@ -2691,7 +2703,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
// Check that all transactions are finalized // Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, block.vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) {
return state.DoS(10, error("%s : contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal");
} }
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
@ -2701,7 +2713,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
CScript expect = CScript() << nHeight; CScript expect = CScript() << nHeight;
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) {
return state.DoS(100, error("%s : block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); return state.DoS(100, error("%s: block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height");
} }
} }
@ -2728,7 +2740,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
if (ppindex) if (ppindex)
*ppindex = pindex; *ppindex = pindex;
if (pindex->nStatus & BLOCK_FAILED_MASK) if (pindex->nStatus & BLOCK_FAILED_MASK)
return state.Invalid(error("%s : block is marked invalid", __func__), 0, "duplicate"); return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate");
return true; return true;
} }
@ -2740,10 +2752,10 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
if (hash != Params().HashGenesisBlock()) { if (hash != Params().HashGenesisBlock()) {
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end()) if (mi == mapBlockIndex.end())
return state.DoS(10, error("%s : prev block not found", __func__), 0, "bad-prevblk"); return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk");
pindexPrev = (*mi).second; pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s : prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
} }
if (!ContextualCheckBlockHeader(block, state, pindexPrev)) if (!ContextualCheckBlockHeader(block, state, pindexPrev))
@ -2769,7 +2781,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (pindex->nStatus & BLOCK_HAVE_DATA) { if (pindex->nStatus & BLOCK_HAVE_DATA) {
// TODO: deal better with duplicate blocks. // TODO: deal better with duplicate blocks.
// return state.DoS(20, error("AcceptBlock() : already have block %d %s", pindex->nHeight, pindex->GetBlockHash().ToString()), REJECT_DUPLICATE, "duplicate"); // return state.DoS(20, error("AcceptBlock(): already have block %d %s", pindex->nHeight, pindex->GetBlockHash().ToString()), REJECT_DUPLICATE, "duplicate");
return true; return true;
} }
@ -2790,12 +2802,12 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (dbp != NULL) if (dbp != NULL)
blockPos = *dbp; blockPos = *dbp;
if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL)) if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL))
return error("AcceptBlock() : FindBlockPos failed"); return error("AcceptBlock(): FindBlockPos failed");
if (dbp == NULL) if (dbp == NULL)
if (!WriteBlockToDisk(block, blockPos)) if (!WriteBlockToDisk(block, blockPos))
return state.Abort("Failed to write block"); return state.Abort("Failed to write block");
if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("AcceptBlock() : ReceivedBlockTransactions failed"); return error("AcceptBlock(): ReceivedBlockTransactions failed");
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
return state.Abort(std::string("System error: ") + e.what()); return state.Abort(std::string("System error: ") + e.what());
} }
@ -2826,7 +2838,7 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
LOCK(cs_main); LOCK(cs_main);
MarkBlockAsReceived(pblock->GetHash()); MarkBlockAsReceived(pblock->GetHash());
if (!checked) { if (!checked) {
return error("%s : CheckBlock FAILED", __func__); return error("%s: CheckBlock FAILED", __func__);
} }
// Store to disk // Store to disk
@ -2836,11 +2848,11 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
} }
if (!ret) if (!ret)
return error("%s : AcceptBlock FAILED", __func__); return error("%s: AcceptBlock FAILED", __func__);
} }
if (!ActivateBestChain(state, pblock)) if (!ActivateBestChain(state, pblock))
return error("%s : ActivateBestChain failed", __func__); return error("%s: ActivateBestChain failed", __func__);
return true; return true;
} }
@ -2947,7 +2959,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new // Create new
CBlockIndex* pindexNew = new CBlockIndex(); CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew) if (!pindexNew)
throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); throw runtime_error("LoadBlockIndex(): new CBlockIndex failed");
mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first); pindexNew->phashBlock = &((*mi).first);
@ -3094,24 +3106,24 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
CBlock block; CBlock block;
// check level 0: read from disk // check level 0: read from disk
if (!ReadBlockFromDisk(block, pindex)) if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity // check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(block, state)) if (nCheckLevel >= 1 && !CheckBlock(block, state))
return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 2: verify undo validity // check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) { if (nCheckLevel >= 2 && pindex) {
CBlockUndo undo; CBlockUndo undo;
CDiskBlockPos pos = pindex->GetUndoPos(); CDiskBlockPos pos = pindex->GetUndoPos();
if (!pos.IsNull()) { if (!pos.IsNull()) {
if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash())) if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash()))
return error("VerifyDB() : *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
} }
} }
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks // check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= nCoinCacheSize) { if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= nCoinCacheSize) {
bool fClean = true; bool fClean = true;
if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean)) if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean))
return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
pindexState = pindex->pprev; pindexState = pindex->pprev;
if (!fClean) { if (!fClean) {
nGoodTransactions = 0; nGoodTransactions = 0;
@ -3123,7 +3135,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
return true; return true;
} }
if (pindexFailure) if (pindexFailure)
return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
// check level 4: try reconnecting blocks // check level 4: try reconnecting blocks
if (nCheckLevel >= 4) { if (nCheckLevel >= 4) {
@ -3134,9 +3146,9 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
pindex = chainActive.Next(pindex); pindex = chainActive.Next(pindex);
CBlock block; CBlock block;
if (!ReadBlockFromDisk(block, pindex)) if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
if (!ConnectBlock(block, state, pindex, coins, trieCache)) if (!ConnectBlock(block, state, pindex, coins, trieCache))
return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
} }
} }
@ -3182,18 +3194,18 @@ bool InitBlockIndex() {
CDiskBlockPos blockPos; CDiskBlockPos blockPos;
CValidationState state; CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
return error("LoadBlockIndex() : FindBlockPos failed"); return error("LoadBlockIndex(): FindBlockPos failed");
if (!WriteBlockToDisk(block, blockPos)) if (!WriteBlockToDisk(block, blockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed"); return error("LoadBlockIndex(): writing genesis block to disk failed");
CBlockIndex *pindex = AddToBlockIndex(block); CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("LoadBlockIndex() : genesis block not accepted"); return error("LoadBlockIndex(): genesis block not accepted");
if (!ActivateBestChain(state, &block)) if (!ActivateBestChain(state, &block))
return error("LoadBlockIndex() : genesis block cannot be activated"); return error("LoadBlockIndex(): genesis block cannot be activated");
// Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data
return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); return FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); return error("LoadBlockIndex(): failed to initialize block database: %s", e.what());
} }
} }
@ -3293,7 +3305,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
} }
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what()); LogPrintf("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
} }
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
@ -3357,7 +3369,7 @@ string GetWarnings(string strFor)
return strStatusBar; return strStatusBar;
else if (strFor == "rpc") else if (strFor == "rpc")
return strRPC; return strRPC;
assert(!"GetWarnings() : invalid parameter"); assert(!"GetWarnings(): invalid parameter");
return "error"; return "error";
} }
@ -3924,7 +3936,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vWorkQueue.push_back(inv.hash); vWorkQueue.push_back(inv.hash);
vEraseQueue.push_back(inv.hash); vEraseQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s : accepted %s (poolsz %u)\n", LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n",
pfrom->id, pfrom->cleanSubVer, pfrom->id, pfrom->cleanSubVer,
tx.GetHash().ToString(), tx.GetHash().ToString(),
mempool.mapTx.size()); mempool.mapTx.size());
@ -4386,7 +4398,7 @@ bool ProcessMessages(CNode* pfrom)
memcpy(&nChecksum, &hash, sizeof(nChecksum)); memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum) if (nChecksum != hdr.nChecksum)
{ {
LogPrintf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", LogPrintf("ProcessMessages(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
strCommand, nMessageSize, nChecksum, hdr.nChecksum); strCommand, nMessageSize, nChecksum, hdr.nChecksum);
continue; continue;
} }
@ -4404,12 +4416,12 @@ bool ProcessMessages(CNode* pfrom)
if (strstr(e.what(), "end of data")) if (strstr(e.what(), "end of data"))
{ {
// Allow exceptions from under-length message on vRecv // Allow exceptions from under-length message on vRecv
LogPrintf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand, nMessageSize, e.what()); LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand, nMessageSize, e.what());
} }
else if (strstr(e.what(), "size too large")) else if (strstr(e.what(), "size too large"))
{ {
// Allow exceptions from over-long size // Allow exceptions from over-long size
LogPrintf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand, nMessageSize, e.what()); LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught\n", strCommand, nMessageSize, e.what());
} }
else else
{ {
@ -4623,12 +4635,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
pto->fDisconnect = true; 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 // (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 // 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 // being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
// to unreasonably increase our timeout. // 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); LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id);
pto->fDisconnect = true; pto->fDisconnect = true;
} }

View file

@ -206,7 +206,7 @@ void FlushStateToDisk();
/** (try to) add transaction to memory pool **/ /** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectInsaneFee=false); bool* pfMissingInputs, bool fRejectAbsurdFee=false);
struct CNodeStateStats { struct CNodeStateStats {

View file

@ -373,7 +373,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CValidationState state; CValidationState state;
if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) if (!TestBlockValidity(state, *pblock, pindexPrev, false, false))
throw std::runtime_error("CreateNewBlock() : TestBlockValidity failed"); throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed");
} }
return pblocktemplate.release(); return pblocktemplate.release();
@ -456,7 +456,7 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
{ {
LOCK(cs_main); LOCK(cs_main);
if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
return error("BitcoinMiner : generated block is stale"); return error("BitcoinMiner: generated block is stale");
} }
// Remove key from key pool // Remove key from key pool
@ -471,7 +471,7 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
// Process this block the same as if we had received it from another node // Process this block the same as if we had received it from another node
CValidationState state; CValidationState state;
if (!ProcessNewBlock(state, NULL, pblock)) if (!ProcessNewBlock(state, NULL, pblock))
return error("BitcoinMiner : ProcessNewBlock, block not accepted"); return error("BitcoinMiner: ProcessNewBlock, block not accepted");
return true; return true;
} }

View file

@ -1020,7 +1020,7 @@ void ThreadMapPort()
catch (const boost::thread_interrupted&) catch (const boost::thread_interrupted&)
{ {
r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
LogPrintf("UPNP_DeletePortMapping() returned : %d\n", r); LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
freeUPNPDevlist(devlist); devlist = 0; freeUPNPDevlist(devlist); devlist = 0;
FreeUPNPUrls(&urls); FreeUPNPUrls(&urls);
throw; throw;
@ -1797,21 +1797,21 @@ bool CAddrDB::Write(const CAddrMan& addr)
FILE *file = fopen(pathTmp.string().c_str(), "wb"); FILE *file = fopen(pathTmp.string().c_str(), "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
if (fileout.IsNull()) if (fileout.IsNull())
return error("%s : Failed to open file %s", __func__, pathTmp.string()); return error("%s: Failed to open file %s", __func__, pathTmp.string());
// Write and commit header, data // Write and commit header, data
try { try {
fileout << ssPeers; fileout << ssPeers;
} }
catch (const std::exception& e) { catch (const std::exception& e) {
return error("%s : Serialize or I/O error - %s", __func__, e.what()); return error("%s: Serialize or I/O error - %s", __func__, e.what());
} }
FileCommit(fileout.Get()); FileCommit(fileout.Get());
fileout.fclose(); fileout.fclose();
// replace existing peers.dat, if any, with new peers.dat.XXXX // replace existing peers.dat, if any, with new peers.dat.XXXX
if (!RenameOver(pathTmp, pathAddr)) if (!RenameOver(pathTmp, pathAddr))
return error("%s : Rename-into-place failed", __func__); return error("%s: Rename-into-place failed", __func__);
return true; return true;
} }
@ -1822,7 +1822,7 @@ bool CAddrDB::Read(CAddrMan& addr)
FILE *file = fopen(pathAddr.string().c_str(), "rb"); FILE *file = fopen(pathAddr.string().c_str(), "rb");
CAutoFile filein(file, SER_DISK, CLIENT_VERSION); CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
if (filein.IsNull()) if (filein.IsNull())
return error("%s : Failed to open file %s", __func__, pathAddr.string()); return error("%s: Failed to open file %s", __func__, pathAddr.string());
// use file size to size memory buffer // use file size to size memory buffer
int fileSize = boost::filesystem::file_size(pathAddr); int fileSize = boost::filesystem::file_size(pathAddr);
@ -1840,7 +1840,7 @@ bool CAddrDB::Read(CAddrMan& addr)
filein >> hashIn; filein >> hashIn;
} }
catch (const std::exception& e) { catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); return error("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
filein.fclose(); filein.fclose();
@ -1849,7 +1849,7 @@ bool CAddrDB::Read(CAddrMan& addr)
// verify stored checksum matches input data // verify stored checksum matches input data
uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
if (hashIn != hashTmp) if (hashIn != hashTmp)
return error("%s : Checksum mismatch, data corrupted", __func__); return error("%s: Checksum mismatch, data corrupted", __func__);
unsigned char pchMsgTmp[4]; unsigned char pchMsgTmp[4];
try { try {
@ -1858,13 +1858,13 @@ bool CAddrDB::Read(CAddrMan& addr)
// ... verify the network matches ours // ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s : Invalid network magic number", __func__); return error("%s: Invalid network magic number", __func__);
// de-serialize address data into one CAddrMan object // de-serialize address data into one CAddrMan object
ssPeers >> addr; ssPeers >> addr;
} }
catch (const std::exception& e) { catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); return error("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
return true; return true;

View file

@ -89,11 +89,11 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
// Check range // Check range
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
return error("CheckProofOfWork() : nBits below minimum work"); return error("CheckProofOfWork(): nBits below minimum work");
// Check proof of work matches claimed amount // Check proof of work matches claimed amount
if (UintToArith256(hash) > bnTarget) if (UintToArith256(hash) > bnTarget)
return error("CheckProofOfWork() : hash doesn't match nBits"); return error("CheckProofOfWork(): hash doesn't match nBits");
return true; return true;
} }

View file

@ -24,7 +24,7 @@ class CBlockHeader
{ {
public: public:
// header // header
static const int32_t CURRENT_VERSION=2; static const int32_t CURRENT_VERSION=3;
int32_t nVersion; int32_t nVersion;
uint256 hashPrevBlock; uint256 hashPrevBlock;
uint256 hashMerkleRoot; uint256 hashMerkleRoot;

View file

@ -94,7 +94,7 @@ CAmount CTransaction::GetValueOut() const
{ {
nValueOut += it->nValue; nValueOut += it->nValue;
if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut)) if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
throw std::runtime_error("CTransaction::GetValueOut() : value out of range"); throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
} }
return nValueOut; return nValueOut;
} }

View file

@ -66,7 +66,7 @@ bool CMessageHeader::IsValid() const
// Message size // Message size
if (nMessageSize > MAX_SIZE) if (nMessageSize > MAX_SIZE)
{ {
LogPrintf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand(), nMessageSize); LogPrintf("CMessageHeader::IsValid(): (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand(), nMessageSize);
return false; return false;
} }
@ -117,7 +117,7 @@ CInv::CInv(const std::string& strType, const uint256& hashIn)
} }
} }
if (i == ARRAYLEN(ppszTypeName)) if (i == ARRAYLEN(ppszTypeName))
throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType)); throw std::out_of_range(strprintf("CInv::CInv(string, uint256): unknown type '%s'", strType));
hash = hashIn; hash = hashIn;
} }
@ -134,7 +134,7 @@ bool CInv::IsKnownType() const
const char* CInv::GetCommand() const const char* CInv::GetCommand() const
{ {
if (!IsKnownType()) if (!IsKnownType())
throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type)); throw std::out_of_range(strprintf("CInv::GetCommand(): type=%d unknown type", type));
return ppszTypeName[type]; return ppszTypeName[type];
} }

View file

@ -114,7 +114,7 @@ public:
case CT_NEW: case CT_NEW:
if(inModel) if(inModel)
{ {
qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_NEW, but entry is already in model"; qWarning() << "AddressTablePriv::updateEntry: Warning: Got CT_NEW, but entry is already in model";
break; break;
} }
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
@ -124,7 +124,7 @@ public:
case CT_UPDATED: case CT_UPDATED:
if(!inModel) if(!inModel)
{ {
qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_UPDATED, but entry is not in model"; qWarning() << "AddressTablePriv::updateEntry: Warning: Got CT_UPDATED, but entry is not in model";
break; break;
} }
lower->type = newEntryType; lower->type = newEntryType;
@ -134,7 +134,7 @@ public:
case CT_DELETED: case CT_DELETED:
if(!inModel) if(!inModel)
{ {
qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_DELETED, but entry is not in model"; qWarning() << "AddressTablePriv::updateEntry: Warning: Got CT_DELETED, but entry is not in model";
break; break;
} }
parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1); parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);

View file

@ -278,7 +278,6 @@ void BitcoinAmountField::setValue(const CAmount& value)
void BitcoinAmountField::setReadOnly(bool fReadOnly) void BitcoinAmountField::setReadOnly(bool fReadOnly)
{ {
amount->setReadOnly(fReadOnly); amount->setReadOnly(fReadOnly);
unit->setEnabled(!fReadOnly);
} }
void BitcoinAmountField::unitChanged(int idx) void BitcoinAmountField::unitChanged(int idx)

View file

@ -212,14 +212,14 @@ static void ShowProgress(ClientModel *clientmodel, const std::string &title, int
static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections) static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
{ {
// Too noisy: qDebug() << "NotifyNumConnectionsChanged : " + QString::number(newNumConnections); // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
Q_ARG(int, newNumConnections)); Q_ARG(int, newNumConnections));
} }
static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status) static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status)
{ {
qDebug() << "NotifyAlertChanged : " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status); qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status);
QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(hash.GetHex())), Q_ARG(QString, QString::fromStdString(hash.GetHex())),
Q_ARG(int, status)); Q_ARG(int, status));

View file

@ -32,18 +32,18 @@ bool PaymentRequestPlus::parse(const QByteArray& data)
{ {
bool parseOK = paymentRequest.ParseFromArray(data.data(), data.size()); bool parseOK = paymentRequest.ParseFromArray(data.data(), data.size());
if (!parseOK) { if (!parseOK) {
qWarning() << "PaymentRequestPlus::parse : Error parsing payment request"; qWarning() << "PaymentRequestPlus::parse: Error parsing payment request";
return false; return false;
} }
if (paymentRequest.payment_details_version() > 1) { if (paymentRequest.payment_details_version() > 1) {
qWarning() << "PaymentRequestPlus::parse : Received up-version payment details, version=" << paymentRequest.payment_details_version(); qWarning() << "PaymentRequestPlus::parse: Received up-version payment details, version=" << paymentRequest.payment_details_version();
return false; return false;
} }
parseOK = details.ParseFromString(paymentRequest.serialized_payment_details()); parseOK = details.ParseFromString(paymentRequest.serialized_payment_details());
if (!parseOK) if (!parseOK)
{ {
qWarning() << "PaymentRequestPlus::parse : Error parsing payment details"; qWarning() << "PaymentRequestPlus::parse: Error parsing payment details";
paymentRequest.Clear(); paymentRequest.Clear();
return false; return false;
} }
@ -83,17 +83,17 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
digestAlgorithm = EVP_sha1(); digestAlgorithm = EVP_sha1();
} }
else if (paymentRequest.pki_type() == "none") { else if (paymentRequest.pki_type() == "none") {
qWarning() << "PaymentRequestPlus::getMerchant : Payment request: pki_type == none"; qWarning() << "PaymentRequestPlus::getMerchant: Payment request: pki_type == none";
return false; return false;
} }
else { else {
qWarning() << "PaymentRequestPlus::getMerchant : Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type()); qWarning() << "PaymentRequestPlus::getMerchant: Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type());
return false; return false;
} }
payments::X509Certificates certChain; payments::X509Certificates certChain;
if (!certChain.ParseFromString(paymentRequest.pki_data())) { if (!certChain.ParseFromString(paymentRequest.pki_data())) {
qWarning() << "PaymentRequestPlus::getMerchant : Payment request: error parsing pki_data"; qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error parsing pki_data";
return false; return false;
} }
@ -103,12 +103,12 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size()); QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size());
QSslCertificate qCert(certData, QSsl::Der); QSslCertificate qCert(certData, QSsl::Der);
if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) { if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) {
qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate expired or not yet active: " << qCert; qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate expired or not yet active: " << qCert;
return false; return false;
} }
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
if (qCert.isBlacklisted()) { if (qCert.isBlacklisted()) {
qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate blacklisted: " << qCert; qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate blacklisted: " << qCert;
return false; return false;
} }
#endif #endif
@ -118,7 +118,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
certs.push_back(cert); certs.push_back(cert);
} }
if (certs.empty()) { if (certs.empty()) {
qWarning() << "PaymentRequestPlus::getMerchant : Payment request: empty certificate chain"; qWarning() << "PaymentRequestPlus::getMerchant: Payment request: empty certificate chain";
return false; return false;
} }
@ -134,7 +134,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
// load the signing cert into it and verify. // load the signing cert into it and verify.
X509_STORE_CTX *store_ctx = X509_STORE_CTX_new(); X509_STORE_CTX *store_ctx = X509_STORE_CTX_new();
if (!store_ctx) { if (!store_ctx) {
qWarning() << "PaymentRequestPlus::getMerchant : Payment request: error creating X509_STORE_CTX"; qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error creating X509_STORE_CTX";
return false; return false;
} }
@ -191,7 +191,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
} }
catch (const SSLVerifyError& err) { catch (const SSLVerifyError& err) {
fResult = false; fResult = false;
qWarning() << "PaymentRequestPlus::getMerchant : SSL error: " << err.what(); qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err.what();
} }
if (website) if (website)

View file

@ -97,7 +97,7 @@ static QList<QString> savedPaymentRequests;
static void ReportInvalidCertificate(const QSslCertificate& cert) static void ReportInvalidCertificate(const QSslCertificate& cert)
{ {
qDebug() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); qDebug() << "ReportInvalidCertificate: Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName);
} }
// //
@ -171,7 +171,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
continue; continue;
} }
} }
qWarning() << "PaymentServer::LoadRootCAs : Loaded " << nRootCerts << " root certificates"; qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
// Project for another day: // Project for another day:
// Fetch certificate revocation lists, and add them to certStore. // Fetch certificate revocation lists, and add them to certStore.
@ -244,7 +244,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{ {
// Printing to debug.log is about the best we can do here, the // Printing to debug.log is about the best we can do here, the
// GUI hasn't started yet so we can't pop up a message box. // GUI hasn't started yet so we can't pop up a message box.
qWarning() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg; qWarning() << "PaymentServer::ipcSendCommandLine: Payment request file does not exist: " << arg;
} }
} }
} }
@ -368,10 +368,10 @@ void PaymentServer::initNetManager()
if (optionsModel->getProxySettings(proxy)) { if (optionsModel->getProxySettings(proxy)) {
netManager->setProxy(proxy); netManager->setProxy(proxy);
qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port(); qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
} }
else else
qDebug() << "PaymentServer::initNetManager : No active proxy server found."; qDebug() << "PaymentServer::initNetManager: No active proxy server found.";
connect(netManager, SIGNAL(finished(QNetworkReply*)), connect(netManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(netRequestFinished(QNetworkReply*))); this, SLOT(netRequestFinished(QNetworkReply*)));
@ -415,12 +415,12 @@ void PaymentServer::handleURIOrFile(const QString& s)
if (fetchUrl.isValid()) if (fetchUrl.isValid())
{ {
qDebug() << "PaymentServer::handleURIOrFile : fetchRequest(" << fetchUrl << ")"; qDebug() << "PaymentServer::handleURIOrFile: fetchRequest(" << fetchUrl << ")";
fetchRequest(fetchUrl); fetchRequest(fetchUrl);
} }
else else
{ {
qWarning() << "PaymentServer::handleURIOrFile : Invalid URL: " << fetchUrl; qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl;
emit message(tr("URI handling"), emit message(tr("URI handling"),
tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()), tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
CClientUIInterface::ICON_WARNING); CClientUIInterface::ICON_WARNING);
@ -585,10 +585,10 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
recipient.address = addresses.join("<br />"); recipient.address = addresses.join("<br />");
if (!recipient.authenticatedMerchant.isEmpty()) { if (!recipient.authenticatedMerchant.isEmpty()) {
qDebug() << "PaymentServer::processPaymentRequest : Secure payment request from " << recipient.authenticatedMerchant; qDebug() << "PaymentServer::processPaymentRequest: Secure payment request from " << recipient.authenticatedMerchant;
} }
else { else {
qDebug() << "PaymentServer::processPaymentRequest : Insecure payment request to " << addresses.join(", "); qDebug() << "PaymentServer::processPaymentRequest: Insecure payment request to " << addresses.join(", ");
} }
return true; return true;
@ -643,7 +643,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
else { else {
// This should never happen, because sending coins should have // This should never happen, because sending coins should have
// just unlocked the wallet and refilled the keypool. // just unlocked the wallet and refilled the keypool.
qWarning() << "PaymentServer::fetchPaymentACK : Error getting refund key, refund_to not set"; qWarning() << "PaymentServer::fetchPaymentACK: Error getting refund key, refund_to not set";
} }
} }
@ -655,7 +655,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
} }
else { else {
// This should never happen, either. // This should never happen, either.
qWarning() << "PaymentServer::fetchPaymentACK : Error serializing payment message"; qWarning() << "PaymentServer::fetchPaymentACK: Error serializing payment message";
} }
} }
@ -694,7 +694,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
SendCoinsRecipient recipient; SendCoinsRecipient recipient;
if (!request.parse(data)) if (!request.parse(data))
{ {
qWarning() << "PaymentServer::netRequestFinished : Error parsing payment request"; qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request";
emit message(tr("Payment request error"), emit message(tr("Payment request error"),
tr("Payment request cannot be parsed!"), tr("Payment request cannot be parsed!"),
CClientUIInterface::MSG_ERROR); CClientUIInterface::MSG_ERROR);
@ -712,7 +712,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
QString msg = tr("Bad response from server %1") QString msg = tr("Bad response from server %1")
.arg(reply->request().url().toString()); .arg(reply->request().url().toString());
qWarning() << "PaymentServer::netRequestFinished : " << msg; qWarning() << "PaymentServer::netRequestFinished: " << msg;
emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
} }
else else
@ -728,7 +728,7 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
QString errString; QString errString;
foreach (const QSslError& err, errs) { foreach (const QSslError& err, errs) {
qWarning() << "PaymentServer::reportSslErrors : " << err; qWarning() << "PaymentServer::reportSslErrors: " << err;
errString += err.errorString() + "\n"; errString += err.errorString() + "\n";
} }
emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);

View file

@ -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.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; msgParams.second = CClientUIInterface::MSG_ERROR;
break; break;
case WalletModel::InsaneFee: case WalletModel::AbsurdFee:
msgParams.first = tr("A fee higher than %1 is considered an insanely high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000)); msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000));
break; break;
case WalletModel::PaymentRequestExpired: case WalletModel::PaymentRequestExpired:
msgParams.first = tr("Payment request expired!"); msgParams.first = tr("Payment request expired!");

View file

@ -94,7 +94,7 @@ public:
*/ */
void updateWallet(const uint256 &hash, int status, bool showTransaction) void updateWallet(const uint256 &hash, int status, bool showTransaction)
{ {
qDebug() << "TransactionTablePriv::updateWallet : " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
// Find bounds of this transaction in model // Find bounds of this transaction in model
QList<TransactionRecord>::iterator lower = qLowerBound( QList<TransactionRecord>::iterator lower = qLowerBound(
@ -122,7 +122,7 @@ public:
case CT_NEW: case CT_NEW:
if(inModel) if(inModel)
{ {
qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model"; qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
break; break;
} }
if(showTransaction) if(showTransaction)
@ -132,7 +132,7 @@ public:
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash); std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
if(mi == wallet->mapWallet.end()) if(mi == wallet->mapWallet.end())
{ {
qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet"; qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
break; break;
} }
// Added -- insert at the right position // Added -- insert at the right position
@ -154,7 +154,7 @@ public:
case CT_DELETED: case CT_DELETED:
if(!inModel) if(!inModel)
{ {
qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model"; qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
break; break;
} }
// Removed -- remove entire transaction from table // Removed -- remove entire transaction from table
@ -664,7 +664,7 @@ public:
void invoke(QObject *ttm) void invoke(QObject *ttm)
{ {
QString strHash = QString::fromStdString(hash.GetHex()); QString strHash = QString::fromStdString(hash.GetHex());
qDebug() << "NotifyTransactionChanged : " + strHash + " status= " + QString::number(status); qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection, QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
Q_ARG(QString, strHash), Q_ARG(QString, strHash),
Q_ARG(int, status), Q_ARG(int, status),

View file

@ -279,9 +279,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return TransactionCreationFailed; return TransactionCreationFailed;
} }
// reject insane fee > 0.1 bitcoin // reject absurdly high fee > 0.1 bitcoin
if (nFeeRequired > 10000000) if (nFeeRequired > 10000000)
return InsaneFee; return AbsurdFee;
} }
return SendCoinsReturn(OK); return SendCoinsReturn(OK);
@ -452,7 +452,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
QString strLabel = QString::fromStdString(label); QString strLabel = QString::fromStdString(label);
QString strPurpose = QString::fromStdString(purpose); QString strPurpose = QString::fromStdString(purpose);
qDebug() << "NotifyAddressBookChanged : " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status); qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status);
QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
Q_ARG(QString, strAddress), Q_ARG(QString, strAddress),
Q_ARG(QString, strLabel), Q_ARG(QString, strLabel),

View file

@ -111,7 +111,7 @@ public:
DuplicateAddress, DuplicateAddress,
TransactionCreationFailed, // Error returned when wallet is still locked TransactionCreationFailed, // Error returned when wallet is still locked
TransactionCommitFailed, TransactionCommitFailed,
InsaneFee, AbsurdFee,
PaymentRequestExpired PaymentRequestExpired
}; };

View file

@ -105,6 +105,7 @@ Value getblockcount(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockcount", "") + HelpExampleRpc("getblockcount", "")
); );
LOCK(cs_main);
return chainActive.Height(); return chainActive.Height();
} }
@ -121,6 +122,7 @@ Value getbestblockhash(const Array& params, bool fHelp)
+ HelpExampleRpc("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", "")
); );
LOCK(cs_main);
return chainActive.Tip()->GetBlockHash().GetHex(); return chainActive.Tip()->GetBlockHash().GetHex();
} }
@ -137,6 +139,7 @@ Value getdifficulty(const Array& params, bool fHelp)
+ HelpExampleRpc("getdifficulty", "") + HelpExampleRpc("getdifficulty", "")
); );
LOCK(cs_main);
return GetDifficulty(); return GetDifficulty();
} }
@ -173,6 +176,8 @@ Value getrawmempool(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawmempool", "true") + HelpExampleRpc("getrawmempool", "true")
); );
LOCK(cs_main);
bool fVerbose = false; bool fVerbose = false;
if (params.size() > 0) if (params.size() > 0)
fVerbose = params[0].get_bool(); fVerbose = params[0].get_bool();
@ -233,6 +238,8 @@ Value getblockhash(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockhash", "1000") + HelpExampleRpc("getblockhash", "1000")
); );
LOCK(cs_main);
int nHeight = params[0].get_int(); int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > chainActive.Height()) if (nHeight < 0 || nHeight > chainActive.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
@ -277,6 +284,8 @@ Value getblock(const Array& params, bool fHelp)
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
); );
LOCK(cs_main);
std::string strHash = params[0].get_str(); std::string strHash = params[0].get_str();
uint256 hash(uint256S(strHash)); uint256 hash(uint256S(strHash));
@ -326,6 +335,8 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxoutsetinfo", "") + HelpExampleRpc("gettxoutsetinfo", "")
); );
LOCK(cs_main);
Object ret; Object ret;
CCoinsStats stats; CCoinsStats stats;
@ -380,6 +391,8 @@ Value gettxout(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxout", "\"txid\", 1") + HelpExampleRpc("gettxout", "\"txid\", 1")
); );
LOCK(cs_main);
Object ret; Object ret;
std::string strHash = params[0].get_str(); std::string strHash = params[0].get_str();
@ -436,6 +449,8 @@ Value verifychain(const Array& params, bool fHelp)
+ HelpExampleRpc("verifychain", "") + HelpExampleRpc("verifychain", "")
); );
LOCK(cs_main);
int nCheckLevel = GetArg("-checklevel", 3); int nCheckLevel = GetArg("-checklevel", 3);
int nCheckDepth = GetArg("-checkblocks", 288); int nCheckDepth = GetArg("-checkblocks", 288);
if (params.size() > 0) if (params.size() > 0)
@ -467,6 +482,8 @@ Value getblockchaininfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", "")
); );
LOCK(cs_main);
Object obj; Object obj;
obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("blocks", (int)chainActive.Height()));
@ -526,6 +543,8 @@ Value getchaintips(const Array& params, bool fHelp)
+ HelpExampleRpc("getchaintips", "") + HelpExampleRpc("getchaintips", "")
); );
LOCK(cs_main);
/* Build up a list of chain tips. We start with the list of all /* Build up a list of chain tips. We start with the list of all
known blocks, and successively remove blocks that appear as pprev known blocks, and successively remove blocks that appear as pprev
of another block. */ of another block. */

View file

@ -91,6 +91,8 @@ Value importprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false") + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
string strSecret = params[0].get_str(); string strSecret = params[0].get_str();
@ -158,6 +160,8 @@ Value importaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false") + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
CScript script; CScript script;
CBitcoinAddress address(params[0].get_str()); CBitcoinAddress address(params[0].get_str());
@ -223,6 +227,8 @@ Value importwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("importwallet", "\"test\"") + HelpExampleRpc("importwallet", "\"test\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
ifstream file; ifstream file;
@ -322,6 +328,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"") + HelpExampleRpc("dumpprivkey", "\"myaddress\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
@ -351,6 +359,8 @@ Value dumpwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
ofstream file; ofstream file;

View file

@ -88,6 +88,7 @@ Value getnetworkhashps(const Array& params, bool fHelp)
+ HelpExampleRpc("getnetworkhashps", "") + HelpExampleRpc("getnetworkhashps", "")
); );
LOCK(cs_main);
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); 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", "") + HelpExampleRpc("getgenerate", "")
); );
LOCK(cs_main);
return GetBoolArg("-gen", false); return GetBoolArg("-gen", false);
} }
@ -200,7 +202,6 @@ Value setgenerate(const Array& params, bool fHelp)
return Value::null; return Value::null;
} }
#endif #endif
@ -228,6 +229,9 @@ Value getmininginfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getmininginfo", "") + HelpExampleRpc("getmininginfo", "")
); );
LOCK(cs_main);
Object obj; Object obj;
obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); 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") + 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(); CAmount nAmount = params[2].get_int64();
mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount); 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", "") + HelpExampleRpc("getblocktemplate", "")
); );
LOCK(cs_main);
std::string strMode = "template"; std::string strMode = "template";
Value lpval = Value::null; Value lpval = Value::null;
if (params.size() > 0) if (params.size() > 0)
@ -439,10 +446,6 @@ Value getblocktemplate(const Array& params, bool fHelp)
} }
// Release the wallet and main lock while waiting // 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); LEAVE_CRITICAL_SECTION(cs_main);
{ {
checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); 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); ENTER_CRITICAL_SECTION(cs_main);
#ifdef ENABLE_WALLET
if(pwalletMain)
ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet);
#endif
if (!IsRPCRunning()) if (!IsRPCRunning())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");

View file

@ -69,6 +69,12 @@ Value getinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getinfo", "") + HelpExampleRpc("getinfo", "")
); );
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
proxyType proxy; proxyType proxy;
GetProxy(NET_IPV4, proxy); GetProxy(NET_IPV4, proxy);
@ -172,6 +178,12 @@ Value validateaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + 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()); CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid(); bool isValid = address.IsValid();
@ -329,6 +341,8 @@ Value verifymessage(const Array& params, bool fHelp)
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"") + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
); );
LOCK(cs_main);
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
string strSign = params[1].get_str(); string strSign = params[1].get_str();
string strMessage = params[2].get_str(); string strMessage = params[2].get_str();
@ -372,6 +386,8 @@ Value setmocktime(const Array& params, bool fHelp)
if (!Params().MineBlocksOnDemand()) if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only"); throw runtime_error("setmocktime for regression testing (-regtest mode) only");
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(int_type)); RPCTypeCheck(params, boost::assign::list_of(int_type));
SetMockTime(params[0].get_int64()); SetMockTime(params[0].get_int64());

View file

@ -34,7 +34,8 @@ Value getconnectioncount(const Array& params, bool fHelp)
+ HelpExampleRpc("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", "")
); );
LOCK(cs_vNodes); LOCK2(cs_main, cs_vNodes);
return (int)vNodes.size(); 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 // 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) { BOOST_FOREACH(CNode* pNode, vNodes) {
pNode->fPingQueued = true; pNode->fPingQueued = true;
} }
@ -113,6 +115,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", "")
); );
LOCK(cs_main);
vector<CNodeStats> vstats; vector<CNodeStats> vstats;
CopyNodeStats(vstats); CopyNodeStats(vstats);
@ -411,6 +415,8 @@ Value getnetworkinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", "")
); );
LOCK(cs_main);
Object obj; Object obj;
obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion", obj.push_back(Pair("subversion",

View file

@ -169,6 +169,8 @@ Value getrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
); );
LOCK(cs_main);
uint256 hash = ParseHashV(params[0], "parameter 1"); uint256 hash = ParseHashV(params[0], "parameter 1");
bool fVerbose = false; bool fVerbose = false;
@ -256,6 +258,7 @@ Value listunspent(const Array& params, bool fHelp)
Array results; Array results;
vector<COutput> vecOutputs; vector<COutput> vecOutputs;
assert(pwalletMain != NULL); assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false); pwalletMain->AvailableCoins(vecOutputs, false);
BOOST_FOREACH(const COutput& out, vecOutputs) { BOOST_FOREACH(const COutput& out, vecOutputs) {
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) 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}\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
); );
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type)); RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type));
Array inputs = params[0].get_array(); Array inputs = params[0].get_array();
@ -428,6 +432,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
); );
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)); RPCTypeCheck(params, boost::assign::list_of(str_type));
CTransaction tx; CTransaction tx;
@ -466,6 +471,7 @@ Value decodescript(const Array& params, bool fHelp)
+ HelpExampleRpc("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\"")
); );
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)); RPCTypeCheck(params, boost::assign::list_of(str_type));
Object r; Object r;
@ -532,6 +538,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"") + 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); RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true);
vector<unsigned char> txData(ParseHexV(params[0], "argument 1")); vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
@ -591,7 +602,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
} }
} }
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
else else if (pwalletMain)
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
#endif #endif
@ -688,7 +699,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); 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; fComplete = false;
} }
@ -722,6 +733,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"") + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
); );
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type)); RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type));
// parse hex string from parameter // parse hex string from parameter

View file

@ -7,9 +7,11 @@
#include "base58.h" #include "base58.h"
#include "init.h" #include "init.h"
#include "main.h" #include "random.h"
#include "sync.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "util.h" #include "util.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
#include "wallet.h" #include "wallet.h"
#endif #endif
@ -23,11 +25,13 @@
#include <boost/iostreams/concepts.hpp> #include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp> #include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "json/json_spirit_writer_template.h" #include "json/json_spirit_writer_template.h"
using namespace boost::asio; using namespace boost::asio;
using namespace json_spirit; using namespace json_spirit;
using namespace RPCServer;
using namespace std; using namespace std;
static std::string strRPCUserColonPass; 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<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors; 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, void RPCTypeCheck(const Array& params,
const list<Value_type>& typesExpected, const list<Value_type>& typesExpected,
bool fAllowNull) bool fAllowNull)
@ -239,116 +271,114 @@ Value stop(const Array& params, bool fHelp)
* Call Table * Call Table
*/ */
static const CRPCCommand vRPCCommands[] = static const CRPCCommand vRPCCommands[] =
{ // category name actor (function) okSafeMode threadSafe reqWallet { // category name actor (function) okSafeMode reqWallet
// --------------------- ------------------------ ----------------------- ---------- ---------- --------- // --------------------- ------------------------ ----------------------- ---------- ---------
/* Overall control/query calls */ /* Overall control/query calls */
{ "control", "getinfo", &getinfo, true, false, false }, /* uses wallet if enabled */ { "control", "getinfo", &getinfo, true, false }, /* uses wallet if enabled */
{ "control", "help", &help, true, true, false }, { "control", "help", &help, true, false },
{ "control", "stop", &stop, true, true, false }, { "control", "stop", &stop, true, false },
/* P2P networking */ /* P2P networking */
{ "network", "getnetworkinfo", &getnetworkinfo, true, false, false }, { "network", "getnetworkinfo", &getnetworkinfo, true, false },
{ "network", "addnode", &addnode, true, true, false }, { "network", "addnode", &addnode, true, false },
{ "network", "getaddednodeinfo", &getaddednodeinfo, true, true, false }, { "network", "getaddednodeinfo", &getaddednodeinfo, true, false },
{ "network", "getconnectioncount", &getconnectioncount, true, false, false }, { "network", "getconnectioncount", &getconnectioncount, true, false },
{ "network", "getnettotals", &getnettotals, true, true, false }, { "network", "getnettotals", &getnettotals, true, false },
{ "network", "getpeerinfo", &getpeerinfo, true, false, false }, { "network", "getpeerinfo", &getpeerinfo, true, false },
{ "network", "ping", &ping, true, false, false }, { "network", "ping", &ping, true, false },
/* Block chain and UTXO */ /* Block chain and UTXO */
{ "blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false }, { "blockchain", "getblockchaininfo", &getblockchaininfo, true, false },
{ "blockchain", "getbestblockhash", &getbestblockhash, true, false, false }, { "blockchain", "getbestblockhash", &getbestblockhash, true, false },
{ "blockchain", "getblockcount", &getblockcount, true, false, false }, { "blockchain", "getblockcount", &getblockcount, true, false },
{ "blockchain", "getblock", &getblock, true, false, false }, { "blockchain", "getblock", &getblock, true, false },
{ "blockchain", "getblockhash", &getblockhash, true, false, false }, { "blockchain", "getblockhash", &getblockhash, true, false },
{ "blockchain", "getchaintips", &getchaintips, true, false, false }, { "blockchain", "getchaintips", &getchaintips, true, false },
{ "blockchain", "getdifficulty", &getdifficulty, true, false, false }, { "blockchain", "getdifficulty", &getdifficulty, true, false },
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true, false },
{ "blockchain", "getrawmempool", &getrawmempool, true, false, false }, { "blockchain", "getrawmempool", &getrawmempool, true, false },
{ "blockchain", "gettxout", &gettxout, true, false, false }, { "blockchain", "gettxout", &gettxout, true, false },
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false }, { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false },
{ "blockchain", "verifychain", &verifychain, true, false, false }, { "blockchain", "verifychain", &verifychain, true, false },
{ "blockchain", "invalidateblock", &invalidateblock, true, true, false },
{ "blockchain", "reconsiderblock", &reconsiderblock, true, true, false },
/* Mining */ /* Mining */
{ "mining", "getblocktemplate", &getblocktemplate, true, false, false }, { "mining", "getblocktemplate", &getblocktemplate, true, false },
{ "mining", "getmininginfo", &getmininginfo, true, false, false }, { "mining", "getmininginfo", &getmininginfo, true, false },
{ "mining", "getnetworkhashps", &getnetworkhashps, true, false, false }, { "mining", "getnetworkhashps", &getnetworkhashps, true, false },
{ "mining", "prioritisetransaction", &prioritisetransaction, true, false, false }, { "mining", "prioritisetransaction", &prioritisetransaction, true, false },
{ "mining", "submitblock", &submitblock, true, true, false }, { "mining", "submitblock", &submitblock, true, false },
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
/* Coin generation */ /* Coin generation */
{ "generating", "getgenerate", &getgenerate, true, false, false }, { "generating", "getgenerate", &getgenerate, true, false },
{ "generating", "setgenerate", &setgenerate, true, true, false }, { "generating", "setgenerate", &setgenerate, true, false },
#endif #endif
/* Raw transactions */ /* Raw transactions */
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true, false, false }, { "rawtransactions", "createrawtransaction", &createrawtransaction, true, false },
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false, false }, { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false },
{ "rawtransactions", "decodescript", &decodescript, true, false, false }, { "rawtransactions", "decodescript", &decodescript, true, false },
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true, false, false }, { "rawtransactions", "getrawtransaction", &getrawtransaction, true, false },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false, false }, { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false, false, false }, /* uses wallet if enabled */ { "rawtransactions", "signrawtransaction", &signrawtransaction, false, false }, /* uses wallet if enabled */
/* Utility functions */ /* Utility functions */
{ "util", "createmultisig", &createmultisig, true, true , false }, { "util", "createmultisig", &createmultisig, true, false },
{ "util", "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */ { "util", "validateaddress", &validateaddress, true, false }, /* uses wallet if enabled */
{ "util", "verifymessage", &verifymessage, true, false, false }, { "util", "verifymessage", &verifymessage, true, false },
{ "util", "estimatefee", &estimatefee, true, true, false }, { "util", "estimatefee", &estimatefee, true, false },
{ "util", "estimatepriority", &estimatepriority, true, true, false }, { "util", "estimatepriority", &estimatepriority, true, false },
/* Not shown in help */ /* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, true, true, false }, { "hidden", "invalidateblock", &invalidateblock, true, false },
{ "hidden", "reconsiderblock", &reconsiderblock, true, true, false }, { "hidden", "reconsiderblock", &reconsiderblock, true, false },
{ "hidden", "setmocktime", &setmocktime, true, false, false }, { "hidden", "setmocktime", &setmocktime, true, false },
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
/* Wallet */ /* Wallet */
{ "wallet", "addmultisigaddress", &addmultisigaddress, true, false, true }, { "wallet", "addmultisigaddress", &addmultisigaddress, true, true },
{ "wallet", "backupwallet", &backupwallet, true, false, true }, { "wallet", "backupwallet", &backupwallet, true, true },
{ "wallet", "dumpprivkey", &dumpprivkey, true, false, true }, { "wallet", "dumpprivkey", &dumpprivkey, true, true },
{ "wallet", "dumpwallet", &dumpwallet, true, false, true }, { "wallet", "dumpwallet", &dumpwallet, true, true },
{ "wallet", "encryptwallet", &encryptwallet, true, false, true }, { "wallet", "encryptwallet", &encryptwallet, true, true },
{ "wallet", "getaccountaddress", &getaccountaddress, true, false, true }, { "wallet", "getaccountaddress", &getaccountaddress, true, true },
{ "wallet", "getaccount", &getaccount, true, false, true }, { "wallet", "getaccount", &getaccount, true, true },
{ "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, false, true }, { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, true },
{ "wallet", "getbalance", &getbalance, false, false, true }, { "wallet", "getbalance", &getbalance, false, true },
{ "wallet", "getnewaddress", &getnewaddress, true, false, true }, { "wallet", "getnewaddress", &getnewaddress, true, true },
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, true, false, true }, { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, true },
{ "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, false, true }, { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, true },
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, false, true }, { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, true },
{ "wallet", "gettransaction", &gettransaction, false, false, true }, { "wallet", "gettransaction", &gettransaction, false, true },
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, false, true }, { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, true },
{ "wallet", "getwalletinfo", &getwalletinfo, false, false, true }, { "wallet", "getwalletinfo", &getwalletinfo, false, true },
{ "wallet", "importprivkey", &importprivkey, true, false, true }, { "wallet", "importprivkey", &importprivkey, true, true },
{ "wallet", "importwallet", &importwallet, true, false, true }, { "wallet", "importwallet", &importwallet, true, true },
{ "wallet", "importaddress", &importaddress, true, false, true }, { "wallet", "importaddress", &importaddress, true, true },
{ "wallet", "keypoolrefill", &keypoolrefill, true, false, true }, { "wallet", "keypoolrefill", &keypoolrefill, true, true },
{ "wallet", "listaccounts", &listaccounts, false, false, true }, { "wallet", "listaccounts", &listaccounts, false, true },
{ "wallet", "listaddressgroupings", &listaddressgroupings, false, false, true }, { "wallet", "listaddressgroupings", &listaddressgroupings, false, true },
{ "wallet", "listlockunspent", &listlockunspent, false, false, true }, { "wallet", "listlockunspent", &listlockunspent, false, true },
{ "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, false, true }, { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, true },
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, false, true }, { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, true },
{ "wallet", "listsinceblock", &listsinceblock, false, false, true }, { "wallet", "listsinceblock", &listsinceblock, false, true },
{ "wallet", "listtransactions", &listtransactions, false, false, true }, { "wallet", "listtransactions", &listtransactions, false, true },
{ "wallet", "listunspent", &listunspent, false, false, true }, { "wallet", "listunspent", &listunspent, false, true },
{ "wallet", "lockunspent", &lockunspent, true, false, true }, { "wallet", "lockunspent", &lockunspent, true, true },
{ "wallet", "move", &movecmd, false, false, true }, { "wallet", "move", &movecmd, false, true },
{ "wallet", "sendfrom", &sendfrom, false, false, true }, { "wallet", "sendfrom", &sendfrom, false, true },
{ "wallet", "sendmany", &sendmany, false, false, true }, { "wallet", "sendmany", &sendmany, false, true },
{ "wallet", "claimname", &claimname, false, false, true }, { "wallet", "claimname", &claimname, false, true },
{ "wallet", "listnameclaims", &listnameclaims, false, false, true }, { "wallet", "listnameclaims", &listnameclaims, false, true },
{ "wallet", "updatename", &updatename, false, false, true }, { "wallet", "updatename", &updatename, false, true },
{ "wallet", "abandonname", &abandonname, false, false, true }, { "wallet", "abandonname", &abandonname, false, true },
{ "wallet", "sendtoaddress", &sendtoaddress, false, false, true }, { "wallet", "sendtoaddress", &sendtoaddress, false, true },
{ "wallet", "setaccount", &setaccount, true, false, true }, { "wallet", "setaccount", &setaccount, true, true },
{ "wallet", "settxfee", &settxfee, true, false, true }, { "wallet", "settxfee", &settxfee, true, true },
{ "wallet", "signmessage", &signmessage, true, false, true }, { "wallet", "signmessage", &signmessage, true, true },
{ "wallet", "walletlock", &walletlock, true, false, true }, { "wallet", "walletlock", &walletlock, true, true },
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, true, false, true }, { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, true },
{ "wallet", "walletpassphrase", &walletpassphrase, true, false, true }, { "wallet", "walletpassphrase", &walletpassphrase, true, true },
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
}; };
@ -697,6 +727,7 @@ void StartRPCThreads()
for (int i = 0; i < GetArg("-rpcthreads", 4); i++) for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service)); rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service));
fRPCRunning = true; fRPCRunning = true;
g_rpcSignals.Started();
} }
void StartDummyRPCThread() void StartDummyRPCThread()
@ -739,7 +770,7 @@ void StopRPCThreads()
deadlineTimers.clear(); deadlineTimers.clear();
rpc_io_service->stop(); rpc_io_service->stop();
cvBlockChange.notify_all(); g_rpcSignals.Stopped();
if (rpc_worker_group != NULL) if (rpc_worker_group != NULL)
rpc_worker_group->join_all(); rpc_worker_group->join_all();
delete rpc_dummy_work; rpc_dummy_work = NULL; 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]; const CRPCCommand *pcmd = tableRPC[strMethod];
if (!pcmd) if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); 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 g_rpcSignals.PreCommand(*pcmd);
string strWarning = GetWarnings("rpc");
if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
!pcmd->okSafeMode)
throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
try try
{ {
// Execute // Execute
Value result; return pcmd->actor(params, false);
{
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;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
throw JSONRPCError(RPC_MISC_ERROR, e.what()); throw JSONRPCError(RPC_MISC_ERROR, e.what());
} }
g_rpcSignals.PostCommand(*pcmd);
} }
std::string HelpExampleCli(string methodname, string args){ std::string HelpExampleCli(string methodname, string args){

View file

@ -19,6 +19,16 @@
#include "json/json_spirit_utils.h" #include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.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 CBlockIndex;
class CNetAddr; class CNetAddr;
@ -88,7 +98,6 @@ public:
std::string name; std::string name;
rpcfn_type actor; rpcfn_type actor;
bool okSafeMode; bool okSafeMode;
bool threadSafe;
bool reqWallet; bool reqWallet;
}; };

View file

@ -83,7 +83,7 @@ Value getnewaddress(const Array& params, bool fHelp)
"If 'account' is specified (DEPRECATED), it is added to the address book \n" "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" "so payments received with the address will be credited to 'account'.\n"
"\nArguments:\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" "\nResult:\n"
"\"bitcoinaddress\" (string) The new bitcoin address\n" "\"bitcoinaddress\" (string) The new bitcoin address\n"
"\nExamples:\n" "\nExamples:\n"
@ -91,6 +91,8 @@ Value getnewaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getnewaddress", "") + HelpExampleRpc("getnewaddress", "")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
// Parse the account first so we don't generate a key if there's an error // Parse the account first so we don't generate a key if there's an error
string strAccount; string strAccount;
if (params.size() > 0) if (params.size() > 0)
@ -165,13 +167,14 @@ Value getaccountaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getaccountaddress", "\"myaccount\"") + 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 // Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue(params[0]); string strAccount = AccountFromValue(params[0]);
Value ret; Value ret;
ret = GetAccountAddress(strAccount).ToString(); ret = GetAccountAddress(strAccount).ToString();
return ret; return ret;
} }
@ -190,6 +193,8 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
if (!pwalletMain->IsLocked()) if (!pwalletMain->IsLocked())
pwalletMain->TopUpKeyPool(); pwalletMain->TopUpKeyPool();
@ -220,11 +225,12 @@ Value setaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"") + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
CBitcoinAddress address(params[0].get_str()); CBitcoinAddress address(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
string strAccount; string strAccount;
if (params.size() > 1) if (params.size() > 1)
strAccount = AccountFromValue(params[1]); strAccount = AccountFromValue(params[1]);
@ -263,6 +269,8 @@ Value getaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
CBitcoinAddress address(params[0].get_str()); CBitcoinAddress address(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@ -293,6 +301,8 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getaddressesbyaccount", "\"tabby\"") + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount = AccountFromValue(params[0]); string strAccount = AccountFromValue(params[0]);
// Find all addresses that have the given account // Find all addresses that have the given account
@ -687,7 +697,7 @@ void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew)
if (pwalletMain->IsLocked()) if (pwalletMain->IsLocked())
{ {
strError = "Error: Wallet locked, unable to create transaction!"; strError = "Error: Wallet locked, unable to create transaction!";
LogPrintf("SendMoney() : %s", strError); LogPrintf("SendMoney(): %s", strError);
throw JSONRPCError(RPC_WALLET_ERROR, strError); throw JSONRPCError(RPC_WALLET_ERROR, strError);
} }
@ -701,7 +711,7 @@ void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew)
{ {
if (nValue + nFeeRequired > pwalletMain->GetBalance()) if (nValue + nFeeRequired > pwalletMain->GetBalance())
strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
LogPrintf("SendMoney() : %s\n", strError); LogPrintf("SendMoney(): %s\n", strError);
throw JSONRPCError(RPC_WALLET_ERROR, strError); throw JSONRPCError(RPC_WALLET_ERROR, strError);
} }
if (!pwalletMain->CommitTransaction(wtxNew, reservekey)) if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
@ -731,6 +741,8 @@ Value sendtoaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"") + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
CBitcoinAddress address(params[0].get_str()); CBitcoinAddress address(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@ -777,6 +789,8 @@ Value listaddressgroupings(const Array& params, bool fHelp)
+ HelpExampleRpc("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
Array jsonGroupings; Array jsonGroupings;
map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances(); map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings()) BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
@ -822,6 +836,8 @@ Value signmessage(const Array& params, bool fHelp)
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"") + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
@ -872,6 +888,8 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6") + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
// Bitcoin address // Bitcoin address
CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
@ -925,6 +943,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6") + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
// Minimum confirmations // Minimum confirmations
int nMinDepth = 1; int nMinDepth = 1;
if (params.size() > 1) if (params.size() > 1)
@ -1011,6 +1031,8 @@ Value getbalance(const Array& params, bool fHelp)
+ HelpExampleRpc("getbalance", "\"*\", 6") + HelpExampleRpc("getbalance", "\"*\", 6")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
if (params.size() == 0) if (params.size() == 0)
return ValueFromAmount(pwalletMain->GetBalance()); return ValueFromAmount(pwalletMain->GetBalance());
@ -1063,6 +1085,9 @@ Value getunconfirmedbalance(const Array &params, bool fHelp)
throw runtime_error( throw runtime_error(
"getunconfirmedbalance\n" "getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n"); "Returns the server's total unconfirmed balance\n");
LOCK2(cs_main, pwalletMain->cs_wallet);
return ValueFromAmount(pwalletMain->GetUnconfirmedBalance()); return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
} }
@ -1089,6 +1114,8 @@ Value movecmd(const Array& params, bool fHelp)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"") + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
string strFrom = AccountFromValue(params[0]); string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]); string strTo = AccountFromValue(params[1]);
CAmount nAmount = AmountFromValue(params[2]); 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\"") + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount = AccountFromValue(params[0]); string strAccount = AccountFromValue(params[0]);
CBitcoinAddress address(params[1].get_str()); CBitcoinAddress address(params[1].get_str());
if (!address.IsValid()) if (!address.IsValid())
@ -1218,6 +1247,8 @@ Value sendmany(const Array& params, bool fHelp)
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"") + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount = AccountFromValue(params[0]); string strAccount = AccountFromValue(params[0]);
Object sendTo = params[1].get_obj(); Object sendTo = params[1].get_obj();
int nMinDepth = 1; int nMinDepth = 1;
@ -1303,6 +1334,8 @@ Value addmultisigaddress(const Array& params, bool fHelp)
throw runtime_error(msg); throw runtime_error(msg);
} }
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount; string strAccount;
if (params.size() > 2) if (params.size() > 2)
strAccount = AccountFromValue(params[2]); strAccount = AccountFromValue(params[2]);
@ -1478,6 +1511,8 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
return ListReceived(params, false); return ListReceived(params, false);
} }
@ -1509,6 +1544,8 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true") + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
return ListReceived(params, true); return ListReceived(params, true);
} }
@ -1660,6 +1697,8 @@ Value listtransactions(const Array& params, bool fHelp)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100") + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount = "*"; string strAccount = "*";
if (params.size() > 0) if (params.size() > 0)
strAccount = params[0].get_str(); strAccount = params[0].get_str();
@ -1740,6 +1779,8 @@ Value listaccounts(const Array& params, bool fHelp)
+ HelpExampleRpc("listaccounts", "6") + HelpExampleRpc("listaccounts", "6")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
int nMinDepth = 1; int nMinDepth = 1;
if (params.size() > 0) if (params.size() > 0)
nMinDepth = params[0].get_int(); nMinDepth = params[0].get_int();
@ -1828,6 +1869,8 @@ Value listsinceblock(const Array& params, bool fHelp)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6") + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
CBlockIndex *pindex = NULL; CBlockIndex *pindex = NULL;
int target_confirms = 1; int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE; isminefilter filter = ISMINE_SPENDABLE;
@ -1914,6 +1957,8 @@ Value gettransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
uint256 hash; uint256 hash;
hash.SetHex(params[0].get_str()); hash.SetHex(params[0].get_str());
@ -1962,6 +2007,8 @@ Value backupwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backup.dat\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
string strDest = params[0].get_str(); string strDest = params[0].get_str();
if (!BackupWallet(*pwalletMain, strDest)) if (!BackupWallet(*pwalletMain, strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
@ -1984,6 +2031,8 @@ Value keypoolrefill(const Array& params, bool fHelp)
+ HelpExampleRpc("keypoolrefill", "") + HelpExampleRpc("keypoolrefill", "")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0; unsigned int kpSize = 0;
if (params.size() > 0) { if (params.size() > 0) {
@ -2031,6 +2080,8 @@ Value walletpassphrase(const Array& params, bool fHelp)
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60") + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
if (fHelp) if (fHelp)
return true; return true;
if (!pwalletMain->IsCrypted()) if (!pwalletMain->IsCrypted())
@ -2078,6 +2129,8 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
+ HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
if (fHelp) if (fHelp)
return true; return true;
if (!pwalletMain->IsCrypted()) if (!pwalletMain->IsCrypted())
@ -2124,6 +2177,8 @@ Value walletlock(const Array& params, bool fHelp)
+ HelpExampleRpc("walletlock", "") + HelpExampleRpc("walletlock", "")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
if (fHelp) if (fHelp)
return true; return true;
if (!pwalletMain->IsCrypted()) if (!pwalletMain->IsCrypted())
@ -2165,6 +2220,8 @@ Value encryptwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"") + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
if (fHelp) if (fHelp)
return true; return true;
if (pwalletMain->IsCrypted()) if (pwalletMain->IsCrypted())
@ -2229,6 +2286,8 @@ Value lockunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
if (params.size() == 1) if (params.size() == 1)
RPCTypeCheck(params, boost::assign::list_of(bool_type)); RPCTypeCheck(params, boost::assign::list_of(bool_type));
else else
@ -2298,6 +2357,8 @@ Value listlockunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("listlockunspent", "") + HelpExampleRpc("listlockunspent", "")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
vector<COutPoint> vOutpts; vector<COutPoint> vOutpts;
pwalletMain->ListLockedCoins(vOutpts); pwalletMain->ListLockedCoins(vOutpts);
@ -2329,6 +2390,8 @@ Value settxfee(const Array& params, bool fHelp)
+ HelpExampleRpc("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
// Amount // Amount
CAmount nAmount = 0; CAmount nAmount = 0;
if (params[0].get_real() != 0.0) if (params[0].get_real() != 0.0)
@ -2360,6 +2423,8 @@ Value getwalletinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")
); );
LOCK2(cs_main, pwalletMain->cs_wallet);
Object obj; Object obj;
obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));

View file

@ -78,7 +78,7 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i
// Regardless of the verification result, the tx did not error. // Regardless of the verification result, the tx did not error.
set_error(err, bitcoinconsensus_ERR_OK); 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&) { } catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
} }

View file

@ -46,6 +46,7 @@ enum
{ {
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0, bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts 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 /// Returns 1 if the input nIn of the serialized transaction pointed to by

View file

@ -60,7 +60,7 @@ bool CastToBool(const valtype& vch)
static inline void popstack(vector<valtype>& stack) static inline void popstack(vector<valtype>& stack)
{ {
if (stack.empty()) if (stack.empty())
throw runtime_error("popstack() : stack empty"); throw runtime_error("popstack(): stack empty");
stack.pop_back(); stack.pop_back();
} }
@ -93,76 +93,76 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
* in which case a single 0 byte is necessary and even required). * in which case a single 0 byte is necessary and even required).
* *
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 * 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) { // Minimum and maximum size constraints.
// Non-canonical signature: too short if (sig.size() < 9) return false;
return false; if (sig.size() > 73) 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;
}
const unsigned char *R = &vchSig[4]; // A signature is of type 0x30 (compound).
if (R[-2] != 0x02) { if (sig[0] != 0x30) return false;
// Non-canonical signature: R value type mismatch
return false; // Make sure the length covers the entire signature.
} if (sig[1] != sig.size() - 3) return false;
if (nLenR == 0) {
// Non-canonical signature: R length is zero // Extract the length of the R element.
return false; unsigned int lenR = sig[3];
}
if (R[0] & 0x80) { // Make sure the length of the S element is still inside the signature.
// Non-canonical signature: R value negative if (5 + lenR >= sig.size()) return false;
return false;
} // Extract the length of the S element.
if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) { unsigned int lenS = sig[5 + lenR];
// Non-canonical signature: R value excessively padded
return false; // 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; return true;
} }
bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
if (!IsDERSignature(vchSig)) { if (!IsValidSignatureEncoding(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_DER); return set_error(serror, SCRIPT_ERR_SIG_DER);
} }
unsigned int nLenR = vchSig[3]; unsigned int nLenR = vchSig[3];
@ -194,7 +194,7 @@ bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, Sc
if (vchSig.size() == 0) { if (vchSig.size() == 0) {
return true; 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); return set_error(serror, SCRIPT_ERR_SIG_DER);
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
// serror is set // serror is set
@ -1058,12 +1058,12 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
return ss.GetHash(); 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); 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); CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid()) if (!pubkey.IsValid())
@ -1076,7 +1076,7 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
int nHashType = vchSig.back(); int nHashType = vchSig.back();
vchSig.pop_back(); vchSig.pop_back();
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
if (!VerifySignature(vchSig, pubkey, sighash)) if (!VerifySignature(vchSig, pubkey, sighash))
return false; return false;

View file

@ -7,6 +7,7 @@
#define BITCOIN_SCRIPT_INTERPRETER_H #define BITCOIN_SCRIPT_INTERPRETER_H
#include "script_error.h" #include "script_error.h"
#include "primitives/transaction.h"
#include <vector> #include <vector>
#include <stdint.h> #include <stdint.h>
@ -90,20 +91,29 @@ public:
virtual ~BaseSignatureChecker() {} virtual ~BaseSignatureChecker() {}
}; };
class SignatureChecker : public BaseSignatureChecker class TransactionSignatureChecker : public BaseSignatureChecker
{ {
private: private:
const CTransaction& txTo; const CTransaction* txTo;
unsigned int nIn; unsigned int nIn;
protected: protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public: 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; 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 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); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);

View file

@ -392,7 +392,7 @@ public:
CScript& operator<<(opcodetype opcode) CScript& operator<<(opcodetype opcode)
{ {
if (opcode < 0 || opcode > 0xff) if (opcode < 0 || opcode > 0xff)
throw std::runtime_error("CScript::operator<<() : invalid opcode"); throw std::runtime_error("CScript::operator<<(): invalid opcode");
insert(end(), (unsigned char)opcode); insert(end(), (unsigned char)opcode);
return *this; return *this;
} }

View file

@ -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; static CSignatureCache signatureCache;
if (signatureCache.Get(sighash, vchSig, pubkey)) if (signatureCache.Get(sighash, vchSig, pubkey))
return true; return true;
if (!SignatureChecker::VerifySignature(vchSig, pubkey, sighash)) if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
return false; return false;
if (store) if (store)

View file

@ -12,13 +12,13 @@
class CPubKey; class CPubKey;
class CachingSignatureChecker : public SignatureChecker class CachingTransactionSignatureChecker : public TransactionSignatureChecker
{ {
private: private:
bool store; bool store;
public: 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; bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
}; };

View file

@ -125,7 +125,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl
} }
// Test solution // 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) 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)) if (sigs.count(pubkey))
continue; // Already got a sig for this 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; sigs[pubkey] = sig;
break; break;

View file

@ -25,7 +25,7 @@ public:
CScriptID(const uint160& in) : uint160(in) {} 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; 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. * blocks and we must accept those blocks.
*/ */
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
SCRIPT_VERIFY_DERSIG |
SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_STRICTENC |
SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_MINIMALDATA |
SCRIPT_VERIFY_NULLDUMMY | SCRIPT_VERIFY_NULLDUMMY |

View file

@ -249,7 +249,7 @@ uint64_t ReadCompactSize(Stream& is)
throw std::ios_base::failure("non-canonical ReadCompactSize()"); throw std::ios_base::failure("non-canonical ReadCompactSize()");
} }
if (nSizeRet > (uint64_t)MAX_SIZE) if (nSizeRet > (uint64_t)MAX_SIZE)
throw std::ios_base::failure("ReadCompactSize() : size too large"); throw std::ios_base::failure("ReadCompactSize(): size too large");
return nSizeRet; return nSizeRet;
} }

View file

@ -224,7 +224,7 @@ public:
{ {
if (nReadPosNext > vch.size()) if (nReadPosNext > vch.size())
{ {
throw std::ios_base::failure("CDataStream::read() : end of data"); throw std::ios_base::failure("CDataStream::read(): end of data");
} }
memcpy(pch, &vch[nReadPos], nSize); memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0; nReadPos = 0;
@ -244,7 +244,7 @@ public:
if (nReadPosNext >= vch.size()) if (nReadPosNext >= vch.size())
{ {
if (nReadPosNext > vch.size()) if (nReadPosNext > vch.size())
throw std::ios_base::failure("CDataStream::ignore() : end of data"); throw std::ios_base::failure("CDataStream::ignore(): end of data");
nReadPos = 0; nReadPos = 0;
vch.clear(); vch.clear();
return (*this); return (*this);
@ -374,18 +374,18 @@ public:
CAutoFile& read(char* pch, size_t nSize) CAutoFile& read(char* pch, size_t nSize)
{ {
if (!file) if (!file)
throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
if (fread(pch, 1, nSize, file) != nSize) if (fread(pch, 1, nSize, file) != nSize)
throw std::ios_base::failure(feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
return (*this); return (*this);
} }
CAutoFile& write(const char* pch, size_t nSize) CAutoFile& write(const char* pch, size_t nSize)
{ {
if (!file) if (!file)
throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
if (fwrite(pch, 1, nSize, file) != nSize) if (fwrite(pch, 1, nSize, file) != nSize)
throw std::ios_base::failure("CAutoFile::write : write failed"); throw std::ios_base::failure("CAutoFile::write: write failed");
return (*this); return (*this);
} }
@ -401,7 +401,7 @@ public:
{ {
// Serialize to this stream // Serialize to this stream
if (!file) if (!file)
throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
::Serialize(*this, obj, nType, nVersion); ::Serialize(*this, obj, nType, nVersion);
return (*this); return (*this);
} }
@ -411,7 +411,7 @@ public:
{ {
// Unserialize from this stream // Unserialize from this stream
if (!file) if (!file)
throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
::Unserialize(*this, obj, nType, nVersion); ::Unserialize(*this, obj, nType, nVersion);
return (*this); return (*this);
} }
@ -452,7 +452,7 @@ protected:
return false; return false;
size_t read = fread((void*)&vchBuf[pos], 1, readNow, src); size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
if (read == 0) { if (read == 0) {
throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed"); throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
} else { } else {
nSrcPos += read; nSrcPos += read;
return true; return true;

View file

@ -142,6 +142,17 @@ public:
Enter(pszName, pszFile, nLine); 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() ~CMutexLock()
{ {
if (lock.owns_lock()) if (lock.owns_lock())

View file

@ -37,14 +37,14 @@ public:
if (!BN_copy(this, &b)) if (!BN_copy(this, &b))
{ {
BN_clear_free(this); BN_clear_free(this);
throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); throw bignum_error("CBigNum::CBigNum(const CBigNum&): BN_copy failed");
} }
} }
CBigNum& operator=(const CBigNum& b) CBigNum& operator=(const CBigNum& b)
{ {
if (!BN_copy(this, &b)) if (!BN_copy(this, &b))
throw bignum_error("CBigNum::operator= : BN_copy failed"); throw bignum_error("CBigNum::operator=: BN_copy failed");
return (*this); return (*this);
} }
@ -151,7 +151,7 @@ inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
{ {
CBigNum r; CBigNum r;
if (!BN_add(&r, &a, &b)) if (!BN_add(&r, &a, &b))
throw bignum_error("CBigNum::operator+ : BN_add failed"); throw bignum_error("CBigNum::operator+: BN_add failed");
return r; return r;
} }
@ -159,7 +159,7 @@ inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
{ {
CBigNum r; CBigNum r;
if (!BN_sub(&r, &a, &b)) if (!BN_sub(&r, &a, &b))
throw bignum_error("CBigNum::operator- : BN_sub failed"); throw bignum_error("CBigNum::operator-: BN_sub failed");
return r; return r;
} }

View file

@ -510,6 +510,16 @@
"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid." "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"], ["Automatically generated test cases"],
[ [
"0x47 0x3044022053205076a7bb12d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801", "0x47 0x3044022053205076a7bb12d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
@ -589,6 +599,102 @@
"DERSIG", "DERSIG",
"P2PK NOT with too much R padding" "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", "0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",

View file

@ -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." "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"], ["Automatically generated test cases"],
[ [
"0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801", "0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
@ -755,6 +765,54 @@
"", "",
"P2PK NOT with bad sig with too much R padding but no DERSIG" "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", "0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",

View file

@ -1,7 +0,0 @@
[
"300602010002010001",
"3008020200ff020200ff01",
"304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001",
"30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01",
"3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"
]

View file

@ -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"
]

View file

@ -82,20 +82,20 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys.assign(1,key[0]); keys.assign(1,key[0]);
keys.push_back(key[1]); keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
keys.assign(1,key[i]); keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]); keys.assign(1,key[1]);
keys.push_back(key[i]); keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0); 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)); 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); s = sign_multisig(a_or_b, keys, txTo[1], 0);
if (i == 0 || i == 1) 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
else 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
} }
s.clear(); s.clear();
s << OP_0 << OP_1; 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)); 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); s = sign_multisig(escrow, keys, txTo[2], 0);
if (i < j && i < 3 && j < 3) 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
else 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
} }

View file

@ -43,7 +43,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig; txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1; 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);
} }

View file

@ -93,7 +93,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bo
ScriptError err; ScriptError err;
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey));
CMutableTransaction tx2 = tx; 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); BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
#if defined(HAVE_CONSENSUS_LIB) #if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); 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 "P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); ).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, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with high S but no LOW_S", 0 "P2PK with high S but no LOW_S", 0
).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); ).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
@ -682,18 +755,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2; 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
@ -715,54 +788,54 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
std::vector<CKey> keys; std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2); keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key3); keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key3); keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); // Must have signatures keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
} }

View file

@ -27,7 +27,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
if (nIn >= txTo.vin.size()) if (nIn >= txTo.vin.size())
{ {
printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); printf("ERROR: SignatureHash(): nIn=%d out of range\n", nIn);
return one; return one;
} }
CMutableTransaction txTmp(txTo); CMutableTransaction txTmp(txTo);
@ -58,7 +58,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
unsigned int nOut = nIn; unsigned int nOut = nIn;
if (nOut >= txTmp.vout.size()) if (nOut >= txTmp.vout.size())
{ {
printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); printf("ERROR: SignatureHash(): nOut=%d out of range\n", nOut);
return one; return one;
} }
txTmp.vout.resize(nOut+1); txTmp.vout.resize(nOut+1);

View file

@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], 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); strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); 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()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], 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(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err)); 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; t.vout[0].scriptPubKey = CScript() << OP_1;
BOOST_CHECK(!IsStandardTx(t, reason)); BOOST_CHECK(!IsStandardTx(t, reason));
// 40-byte TX_NULL_DATA (standard) // 80-byte TX_NULL_DATA (standard)
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
BOOST_CHECK(IsStandardTx(t, reason)); BOOST_CHECK(IsStandardTx(t, reason));
// 41-byte TX_NULL_DATA (non-standard) // 81-byte TX_NULL_DATA (non-standard)
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
BOOST_CHECK(!IsStandardTx(t, reason)); BOOST_CHECK(!IsStandardTx(t, reason));
// TX_NULL_DATA w/o PUSHDATA // TX_NULL_DATA w/o PUSHDATA

View file

@ -282,21 +282,21 @@ BOOST_AUTO_TEST_CASE(strprintf_numbers)
{ {
int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */ int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */
uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */ uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */
BOOST_CHECK(strprintf("%s %d %s", B, s64t, E) == B" -9223372036854775807 "E); BOOST_CHECK(strprintf("%s %d %s", B, s64t, E) == B" -9223372036854775807 " E);
BOOST_CHECK(strprintf("%s %u %s", B, u64t, E) == B" 18446744073709551615 "E); BOOST_CHECK(strprintf("%s %u %s", B, u64t, E) == B" 18446744073709551615 " E);
BOOST_CHECK(strprintf("%s %x %s", B, u64t, E) == B" ffffffffffffffff "E); BOOST_CHECK(strprintf("%s %x %s", B, u64t, E) == B" ffffffffffffffff " E);
size_t st = 12345678; /* unsigned size_t test value */ size_t st = 12345678; /* unsigned size_t test value */
ssize_t sst = -12345678; /* signed size_t test value */ ssize_t sst = -12345678; /* signed size_t test value */
BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B" -12345678 "E); BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B" -12345678 " E);
BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B" 12345678 "E); BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B" 12345678 " E);
BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B" bc614e "E); BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B" bc614e " E);
ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */ ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */
ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */ ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */
BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B" -87654321 "E); BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B" -87654321 " E);
BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B" 87654321 "E); BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B" 87654321 " E);
BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B" 5397fb1 "E); BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B" 5397fb1 " E);
} }
#undef B #undef B
#undef E #undef E

View file

@ -14,35 +14,42 @@
using namespace std; 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) { void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
if (coins.IsPruned()) { if (coins.IsPruned())
LogPrintf("BatchWriteCoins erasing %s\n", hash.GetHex().c_str()); batch.Erase(make_pair(DB_COINS, hash));
batch.Erase(make_pair('c', hash)); else
} batch.Write(make_pair(DB_COINS, hash), coins);
else {
LogPrintf("BatchWriteCoins writing %s\n", hash.GetHex().c_str());
batch.Write(make_pair('c', hash), coins);
}
} }
void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { 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) { CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
} }
bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const { 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 { 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 CCoinsViewDB::GetBestBlock() const {
uint256 hashBestChain; uint256 hashBestChain;
if (!db.Read('B', hashBestChain)) if (!db.Read(DB_BEST_BLOCK, hashBestChain))
return uint256(); return uint256();
return hashBestChain; return hashBestChain;
} }
@ -71,23 +78,23 @@ CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevel
} }
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { 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) { bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
if (fReindexing) if (fReindexing)
return Write('R', '1'); return Write(DB_REINDEX_FLAG, '1');
else else
return Erase('R'); return Erase(DB_REINDEX_FLAG);
} }
bool CBlockTreeDB::ReadReindexing(bool &fReindexing) { bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
fReindexing = Exists('R'); fReindexing = Exists(DB_REINDEX_FLAG);
return true; return true;
} }
bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
return Read('l', nFile); return Read(DB_LAST_BLOCK, nFile);
} }
bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { 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); CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
char chType; char chType;
ssKey >> chType; ssKey >> chType;
if (chType == 'c') { if (chType == DB_COINS) {
leveldb::Slice slValue = pcursor->value(); leveldb::Slice slValue = pcursor->value();
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
CCoins coins; CCoins coins;
@ -134,7 +141,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
} }
pcursor->Next(); pcursor->Next();
} catch (const std::exception& e) { } catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); return error("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
} }
stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight; stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
@ -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) { bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
CLevelDBBatch batch; CLevelDBBatch batch;
for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { 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++) { 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); return WriteBatch(batch, true);
} }
bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { 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) { bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
CLevelDBBatch batch; CLevelDBBatch batch;
for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++) 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); return WriteBatch(batch);
} }
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { 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) { bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
char ch; char ch;
if (!Read(std::make_pair('F', name), ch)) if (!Read(std::make_pair(DB_FLAG, name), ch))
return false; return false;
fValue = ch == '1'; fValue = ch == '1';
return true; return true;
@ -183,7 +190,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator()); boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
ssKeySet << make_pair('b', uint256()); ssKeySet << make_pair(DB_BLOCK_INDEX, uint256());
pcursor->Seek(ssKeySet.str()); pcursor->Seek(ssKeySet.str());
// Load mapBlockIndex // Load mapBlockIndex
@ -194,7 +201,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION); CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
char chType; char chType;
ssKey >> chType; ssKey >> chType;
if (chType == 'b') { if (chType == DB_BLOCK_INDEX) {
leveldb::Slice slValue = pcursor->value(); leveldb::Slice slValue = pcursor->value();
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
CDiskBlockIndex diskindex; CDiskBlockIndex diskindex;
@ -216,14 +223,14 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nTx = diskindex.nTx; pindexNew->nTx = diskindex.nTx;
if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
pcursor->Next(); pcursor->Next();
} else { } else {
break; // if shutdown requested or finished loading block index break; // if shutdown requested or finished loading block index
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); return error("%s: Deserialize or I/O error - %s", __func__, e.what());
} }
} }

View file

@ -192,7 +192,7 @@ private:
// Neither or both fee and priority sufficient to get confirmed: // Neither or both fee and priority sufficient to get confirmed:
// don't know why they got confirmed. // don't know why they got confirmed.
} }
LogPrint("estimatefee", "Seen TX confirm: %s : %s fee/%g priority, took %d blocks\n", LogPrint("estimatefee", "Seen TX confirm: %s: %s fee/%g priority, took %d blocks\n",
assignedTo, feeRate.ToString(), dPriority, nBlocksAgo); assignedTo, feeRate.ToString(), dPriority, nBlocksAgo);
} }
@ -658,7 +658,7 @@ CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
minerPolicyEstimator->Write(fileout); minerPolicyEstimator->Write(fileout);
} }
catch (const std::exception&) { catch (const std::exception&) {
LogPrintf("CTxMemPool::WriteFeeEstimates() : unable to write policy estimator data (non-fatal)"); LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)");
return false; return false;
} }
return true; return true;
@ -671,13 +671,13 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
int nVersionRequired, nVersionThatWrote; int nVersionRequired, nVersionThatWrote;
filein >> nVersionRequired >> nVersionThatWrote; filein >> nVersionRequired >> nVersionThatWrote;
if (nVersionRequired > CLIENT_VERSION) if (nVersionRequired > CLIENT_VERSION)
return error("CTxMemPool::ReadFeeEstimates() : up-version (%d) fee estimate file", nVersionRequired); return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired);
LOCK(cs); LOCK(cs);
minerPolicyEstimator->Read(filein, minRelayFee); minerPolicyEstimator->Read(filein, minRelayFee);
} }
catch (const std::exception&) { catch (const std::exception&) {
LogPrintf("CTxMemPool::ReadFeeEstimates() : unable to read policy estimator data (non-fatal)"); LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)");
return false; return false;
} }
return true; return true;

View file

@ -89,7 +89,7 @@ CPubKey CWallet::GenerateNewKey()
nTimeFirstKey = nCreationTime; nTimeFirstKey = nCreationTime;
if (!AddKeyPubKey(secret, pubkey)) if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
return pubkey; return pubkey;
} }
@ -620,7 +620,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
} }
else else
LogPrintf("AddToWallet() : found %s in block %s not in index\n", LogPrintf("AddToWallet(): found %s in block %s not in index\n",
wtxIn.GetHash().ToString(), wtxIn.GetHash().ToString(),
wtxIn.hashBlock.ToString()); wtxIn.hashBlock.ToString());
} }
@ -1020,6 +1020,193 @@ set<uint256> CWalletTx::GetConflicts() const
return result; 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() void CWallet::ResendWalletTransactions()
{ {
// Do this infrequently and randomly to avoid giving away // 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) BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{ {
CAmount nCredit = pcoin.first->vout[pcoin.second].nValue; 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 //reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction. //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) if (fUsingWtxIn)
@ -1640,7 +1831,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
if (!wtxNew.AcceptToMemoryPool(false)) if (!wtxNew.AcceptToMemoryPool(false))
{ {
// This must not fail. The transaction has already been signed and recorded. // This must not fail. The transaction has already been signed and recorded.
LogPrintf("CommitTransaction() : Error: Transaction not valid"); LogPrintf("CommitTransaction(): Error: Transaction not valid");
return false; return false;
} }
wtxNew.RelayWalletTransaction(); wtxNew.RelayWalletTransaction();
@ -1833,7 +2024,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (!setKeyPool.empty()) if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1; nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
throw runtime_error("TopUpKeyPool() : writing generated key failed"); throw runtime_error("TopUpKeyPool(): writing generated key failed");
setKeyPool.insert(nEnd); setKeyPool.insert(nEnd);
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size()); LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
} }
@ -1860,9 +2051,9 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
nIndex = *(setKeyPool.begin()); nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin()); setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool)) if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool() : read failed"); throw runtime_error("ReserveKeyFromKeyPool(): read failed");
if (!HaveKey(keypool.vchPubKey.GetID())) if (!HaveKey(keypool.vchPubKey.GetID()))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
assert(keypool.vchPubKey.IsValid()); assert(keypool.vchPubKey.IsValid());
LogPrintf("keypool reserve %d\n", nIndex); LogPrintf("keypool reserve %d\n", nIndex);
} }
@ -2110,11 +2301,11 @@ void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{ {
CKeyPool keypool; CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool)) if (!walletdb.ReadPool(id, keypool))
throw runtime_error("GetAllReserveKeyHashes() : read failed"); throw runtime_error("GetAllReserveKeyHashes(): read failed");
assert(keypool.vchPubKey.IsValid()); assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID(); CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID)) if (!HaveKey(keyID))
throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool"); throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
setAddress.insert(keyID); setAddress.insert(keyID);
} }
} }
@ -2327,7 +2518,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block)
{ {
vMerkleBranch.clear(); vMerkleBranch.clear();
nIndex = -1; nIndex = -1;
LogPrintf("ERROR: SetMerkleBranch() : couldn't find tx in block\n"); LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n");
return 0; return 0;
} }
@ -2389,9 +2580,9 @@ int CMerkleTx::GetBlocksToMaturity() const
} }
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee) bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
{ {
CValidationState state; CValidationState state;
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee); return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
} }

View file

@ -103,6 +103,329 @@ public:
StringMap destdata; 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, * 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. * and provides the ability to create new transactions.
@ -320,14 +643,14 @@ public:
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const
{ {
if (!MoneyRange(txout.nValue)) if (!MoneyRange(txout.nValue))
throw std::runtime_error("CWallet::GetCredit() : value out of range"); throw std::runtime_error("CWallet::GetCredit(): value out of range");
return ((IsMine(txout) & filter) ? txout.nValue : 0); return ((IsMine(txout) & filter) ? txout.nValue : 0);
} }
bool IsChange(const CTxOut& txout) const; bool IsChange(const CTxOut& txout) const;
CAmount GetChange(const CTxOut& txout) const CAmount GetChange(const CTxOut& txout) const
{ {
if (!MoneyRange(txout.nValue)) if (!MoneyRange(txout.nValue))
throw std::runtime_error("CWallet::GetChange() : value out of range"); throw std::runtime_error("CWallet::GetChange(): value out of range");
return (IsChange(txout) ? txout.nValue : 0); return (IsChange(txout) ? txout.nValue : 0);
} }
bool IsMine(const CTransaction& tx) const bool IsMine(const CTransaction& tx) const
@ -349,7 +672,7 @@ public:
{ {
nDebit += GetDebit(txin, filter); nDebit += GetDebit(txin, filter);
if (!MoneyRange(nDebit)) if (!MoneyRange(nDebit))
throw std::runtime_error("CWallet::GetDebit() : value out of range"); throw std::runtime_error("CWallet::GetDebit(): value out of range");
} }
return nDebit; return nDebit;
} }
@ -360,7 +683,7 @@ public:
{ {
nCredit += GetCredit(txout, filter); nCredit += GetCredit(txout, filter);
if (!MoneyRange(nCredit)) if (!MoneyRange(nCredit))
throw std::runtime_error("CWallet::GetCredit() : value out of range"); throw std::runtime_error("CWallet::GetCredit(): value out of range");
} }
return nCredit; return nCredit;
} }
@ -371,7 +694,7 @@ public:
{ {
nChange += GetChange(txout); nChange += GetChange(txout);
if (!MoneyRange(nChange)) if (!MoneyRange(nChange))
throw std::runtime_error("CWallet::GetChange() : value out of range"); throw std::runtime_error("CWallet::GetChange(): value out of range");
} }
return nChange; return nChange;
} }
@ -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. * Account information.
* Stored in wallet with key "acc"+string account name. * Stored in wallet with key "acc"+string account name.

View file

@ -210,7 +210,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
Dbc* pcursor = GetCursor(); Dbc* pcursor = GetCursor();
if (!pcursor) if (!pcursor)
throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); throw runtime_error("CWalletDB::ListAccountCreditDebit(): cannot create DB cursor");
unsigned int fFlags = DB_SET_RANGE; unsigned int fFlags = DB_SET_RANGE;
while (true) while (true)
{ {
@ -226,7 +226,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
else if (ret != 0) else if (ret != 0)
{ {
pcursor->close(); pcursor->close();
throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB"); throw runtime_error("CWalletDB::ListAccountCreditDebit(): error scanning DB");
} }
// Unserialize // Unserialize