Compare commits
295 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
365df024bc | ||
|
|
c7388aacf8 | ||
|
|
c1392f15be | ||
|
|
05a975a424 | ||
|
|
cf68e084fe | ||
|
|
b2dda538c8 | ||
|
|
366b8bc358 | ||
|
|
2049056cfd | ||
|
|
721ce42f57 | ||
|
|
c7a1c1278b | ||
|
|
c2785585dc | ||
|
|
f94c40ff5c | ||
|
|
47a494e113 | ||
|
|
5e409f22fb | ||
|
|
835ed46634 | ||
|
|
61deba379e | ||
|
|
7f103073ad | ||
|
|
2a37933698 | ||
|
|
15f79c6f71 | ||
|
|
b8055bd495 | ||
|
|
7605755747 | ||
|
|
8b28f02857 | ||
|
|
f093ad8ee7 | ||
|
|
fdb2a280b0 | ||
|
|
bea591911d | ||
|
|
498221e0b1 | ||
|
|
76db08733f | ||
|
|
9d6b0d0649 | ||
|
|
0dcc8d8697 | ||
|
|
f3659638d7 | ||
|
|
18ece76f77 | ||
|
|
30ba82f339 | ||
|
|
cdb5841c88 | ||
|
|
31c1d2c168 | ||
|
|
970017ab38 | ||
|
|
793d180847 | ||
|
|
fd04e03c5d | ||
|
|
9bb03c6cf3 | ||
|
|
c1a159d417 | ||
|
|
4572fcb97b | ||
|
|
07ce01f57a | ||
|
|
04753c7257 | ||
|
|
bdb9519f1b | ||
|
|
cf8d325b30 | ||
|
|
0d94076671 | ||
|
|
136f2b5457 | ||
|
|
5c471cb3fe | ||
|
|
c0f590e889 | ||
|
|
70a022e944 | ||
|
|
bfd7d9469a | ||
|
|
5a6bc0caec | ||
|
|
6c56da6a04 | ||
|
|
f333f3c662 | ||
|
|
ea800f8be1 | ||
|
|
9cfdca809c | ||
|
|
5889aeab25 | ||
|
|
130cfbdb3e | ||
|
|
711b938fb8 | ||
|
|
65b9f2dcd0 | ||
|
|
963262af08 | ||
|
|
147e86b466 | ||
|
|
a9b3541a60 | ||
|
|
3d482768d6 | ||
|
|
37cd25dfc1 | ||
|
|
5a88bc541a | ||
|
|
896dc34d47 | ||
|
|
981b1dc4fe | ||
|
|
aa74130c59 | ||
|
|
28f39f440c | ||
|
|
3280aab174 | ||
|
|
f692fddffa | ||
|
|
aaaa53e7d9 | ||
|
|
b2ff42e8b7 | ||
|
|
6c1b8b2cba | ||
|
|
81f7ae1d1a | ||
|
|
b41a0f11ee | ||
|
|
128458fbd0 | ||
|
|
33ce817739 | ||
|
|
acc9266d63 | ||
|
|
ce5125dc90 | ||
|
|
328300edbe | ||
|
|
1783777646 | ||
|
|
7b1113110a | ||
|
|
4be60421c8 | ||
|
|
2cad5fdadb | ||
|
|
15745d4a5f | ||
|
|
4a01674cd0 | ||
|
|
ebd42b2461 | ||
|
|
339f436170 | ||
|
|
d594808495 | ||
|
|
723a7e543b | ||
|
|
1ff98a1199 | ||
|
|
c9030312dc | ||
|
|
e1a1b1bd07 | ||
|
|
3ff3604939 | ||
|
|
86c6f760bf | ||
|
|
7e10567263 | ||
|
|
c524b0160d | ||
|
|
a697e39f43 | ||
|
|
87ccb59726 | ||
|
|
1799d18d55 | ||
|
|
99e710cb7f | ||
|
|
6002cb96a0 | ||
|
|
2e0cc834fe | ||
|
|
28a2bb7f6b | ||
|
|
5307b027f6 | ||
|
|
b5c6d97be7 | ||
|
|
048483d97c | ||
|
|
1250b472f0 | ||
|
|
871871ddd5 | ||
|
|
8f8110a7e4 | ||
|
|
80c85d212a | ||
|
|
016aa307f5 | ||
|
|
2eb326525d | ||
|
|
1ba845f671 | ||
|
|
861bd066fe | ||
|
|
5ee6256cb4 | ||
|
|
aef9cbc5a5 | ||
|
|
5875a41d34 | ||
|
|
72d0d641b4 | ||
|
|
c651bc036f | ||
|
|
2d822c6bbc | ||
|
|
651323c7c1 | ||
|
|
7364be59db | ||
|
|
4a1dcb5cb6 | ||
|
|
df9c3e9303 | ||
|
|
3c7889fa23 | ||
|
|
e37ae9022b | ||
|
|
1cf20a8348 | ||
|
|
1a3cdfd792 | ||
|
|
cd1ae36d0d | ||
|
|
56187b6710 | ||
|
|
ba398a34e7 | ||
|
|
b05c2c50de | ||
|
|
4babc68a5f | ||
|
|
12db22114d | ||
|
|
7e7f376aa3 | ||
|
|
8f11886982 | ||
|
|
89c06f9a31 | ||
|
|
9f58bcb4aa | ||
|
|
5016f8d86a | ||
|
|
3be2fadaca | ||
|
|
7e0d27119c | ||
|
|
d5a43949b1 | ||
|
|
382e864589 | ||
|
|
d0a9367017 | ||
|
|
cc07c06238 | ||
|
|
24633a987f | ||
|
|
0d8212c1dc | ||
|
|
676d9ab5eb | ||
|
|
f658eabf5e | ||
|
|
ae7055df8b | ||
|
|
1e49556078 | ||
|
|
d2dde7a9ed | ||
|
|
2772cd22cc | ||
|
|
d9a0755029 | ||
|
|
5f16acdcc4 | ||
|
|
4bebe501ad | ||
|
|
c94e438c91 | ||
|
|
7bf7e80a6a | ||
|
|
58aa6a3573 | ||
|
|
e3465d35aa | ||
|
|
a22129364a | ||
|
|
24aabb0e55 | ||
|
|
f1ede0aec7 | ||
|
|
ef78f03a58 | ||
|
|
2763aba114 | ||
|
|
9a5799891e | ||
|
|
15e2c35bf6 | ||
|
|
22f6e42844 | ||
|
|
c70cc4f116 | ||
|
|
29f6df9585 | ||
|
|
a1dbe722fa | ||
|
|
74e674632e | ||
|
|
a336d9a70c | ||
|
|
cc0f35fb8a | ||
|
|
93a91696a5 | ||
|
|
1fe058443f | ||
|
|
5c535ed092 | ||
|
|
e9cd82be93 | ||
|
|
76a82009ad | ||
|
|
9315e34959 | ||
|
|
54cab99423 | ||
|
|
335d42b722 | ||
|
|
f0aff19787 | ||
|
|
4c4fec0da9 | ||
|
|
eeb1599b07 | ||
|
|
6aa007da0c | ||
|
|
653ee225f7 | ||
|
|
35e660860e | ||
|
|
9933c42610 | ||
|
|
47fa1ce9fb | ||
|
|
f58db44275 | ||
|
|
62b721ee15 | ||
|
|
41af7e2b7b | ||
|
|
b04e6f3f69 | ||
|
|
902492eccb | ||
|
|
23a429b5b5 | ||
|
|
5a9a96a306 | ||
|
|
62e2f6178b | ||
|
|
e86fe28fa0 | ||
|
|
09921dee12 | ||
|
|
adb6106f89 | ||
|
|
7ad8147482 | ||
|
|
5f463594b1 | ||
|
|
4fe973a101 | ||
|
|
20ba4ab64a | ||
|
|
d95cce298a | ||
|
|
1a54db48c4 | ||
|
|
136a8ee229 | ||
|
|
856f5b0d13 | ||
|
|
d7ce09ca03 | ||
|
|
5d14babebc | ||
|
|
b549d6ce6b | ||
|
|
c06ea142ae | ||
|
|
d46062c7e6 | ||
|
|
4b87cfeeaa | ||
|
|
75d4da0d9b | ||
|
|
cd1b78f508 | ||
|
|
e407661000 | ||
|
|
fe5717762a | ||
|
|
37ed1a8680 | ||
|
|
628b158a20 | ||
|
|
a7cff7ff18 | ||
|
|
4774e2c59f | ||
|
|
a2d4f33563 | ||
|
|
c469e805e0 | ||
|
|
12acb40d47 | ||
|
|
625e04d9df | ||
|
|
948c869356 | ||
|
|
b253c0b00c | ||
|
|
f9eff703a7 | ||
|
|
e847c3b10a | ||
|
|
9f831dfbd2 | ||
|
|
6cc0258704 | ||
|
|
1cbe9c3d70 | ||
|
|
385f2ddd7c | ||
|
|
3c59c93d42 | ||
|
|
28b2ff0230 | ||
|
|
9f5e949f7e | ||
|
|
847b04d030 | ||
|
|
83daccfeef | ||
|
|
0299bfc068 | ||
|
|
93b76398c1 | ||
|
|
350229b16b | ||
|
|
300180210e | ||
|
|
ebe52b71c8 | ||
|
|
510ab33115 | ||
|
|
8dab96e425 | ||
|
|
07fe5b155a | ||
|
|
b9572db7d5 | ||
|
|
eb33f9c8e4 | ||
|
|
2504f48b6c | ||
|
|
47234b81e6 | ||
|
|
436632ec5b | ||
|
|
15e3d91ccc | ||
|
|
11284db136 | ||
|
|
4282562adf | ||
|
|
7468316108 | ||
|
|
0b052e37a7 | ||
|
|
cc4f0fa86e | ||
|
|
d6002f955f | ||
|
|
cd4badb1c7 | ||
|
|
9a5a191e3c | ||
|
|
c13ea0903a | ||
|
|
2f899db363 | ||
|
|
8811805155 | ||
|
|
8d19469301 | ||
|
|
bca8f6f5e5 | ||
|
|
01f4f6b5ef | ||
|
|
f6f0e617d5 | ||
|
|
b84806651c | ||
|
|
5c704c60d6 | ||
|
|
ee639a9b54 | ||
|
|
1bbe9b9162 | ||
|
|
57f81f1702 | ||
|
|
e7d36757ef | ||
|
|
0a47d4c1fa | ||
|
|
f7ad5a4b97 | ||
|
|
a6c23b842d | ||
|
|
9044a62894 | ||
|
|
17d6193b07 | ||
|
|
d1a048dd2b | ||
|
|
8b57005cf1 | ||
|
|
e0d2b2d119 | ||
|
|
8f4bb3ee9f | ||
|
|
1ee3475d2c | ||
|
|
3d34fa30a9 | ||
|
|
fb9e98690b | ||
|
|
ff6a4caa08 | ||
|
|
7114d5ee8a | ||
|
|
3448695ff4 | ||
|
|
482b48bbd5 | ||
|
|
e39b2ac972 | ||
|
|
338e396678 |
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,3 +1,10 @@
|
||||
*.gcov
|
||||
*.gcda
|
||||
*.gcno
|
||||
vgcore*
|
||||
core*
|
||||
*.orig
|
||||
*.rej
|
||||
*~
|
||||
*.so
|
||||
*.o
|
||||
@ -23,3 +30,9 @@ autom4te.cache
|
||||
config.*
|
||||
ii
|
||||
ar-lib
|
||||
compile
|
||||
test-driver
|
||||
test
|
||||
test-suite.log
|
||||
test.log
|
||||
test.trs
|
||||
|
||||
129
.travis.yml
Normal file
129
.travis.yml
Normal file
@ -0,0 +1,129 @@
|
||||
os: linux
|
||||
language: c
|
||||
compiler: gcc
|
||||
sudo: false
|
||||
env:
|
||||
global:
|
||||
- PKG_CONFIG_LIBDIR="$HOME/lib/pkgconfig"
|
||||
- OPTS="--prefix=$HOME"
|
||||
matrix:
|
||||
include:
|
||||
# Normal build
|
||||
- addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- libjansson-dev
|
||||
- libgcrypt11-dev
|
||||
env: CFLAGS="-Wall" AM_CFLAGS='-Werror'
|
||||
# clang
|
||||
- compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- libjansson-dev
|
||||
- libgcrypt11-dev
|
||||
env: CFLAGS="-Wall -fsanitize=undefined -fno-sanitize-recover -fsanitize=address"
|
||||
# w/o libgcrypt
|
||||
- addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- libjansson-dev
|
||||
# Win32
|
||||
- addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-i686
|
||||
- binutils-mingw-w64-i686
|
||||
- mingw-w64-dev
|
||||
- wine
|
||||
env:
|
||||
- CROSS_TARGET=i686-w64-mingw32
|
||||
EXEEXT=.exe
|
||||
BUILD_LIBS=1
|
||||
WINE_TESTS=1
|
||||
OPTS="$OPTS --disable-static"
|
||||
JANSSON_VERSION=v2.4
|
||||
# Win64
|
||||
- addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-x86-64
|
||||
- binutils-mingw-w64-x86-64
|
||||
- mingw-w64-dev
|
||||
- wine
|
||||
env:
|
||||
- CROSS_TARGET=x86_64-w64-mingw32
|
||||
EXEEXT=.exe
|
||||
BUILD_LIBS=1
|
||||
WINE_TESTS=1
|
||||
OPTS="$OPTS --disable-static"
|
||||
JANSSON_VERSION=v2.4
|
||||
exclude:
|
||||
- compiler: gcc
|
||||
# TODO: Linux32 (or 64) & OS X
|
||||
script:
|
||||
- if [ -n "$CROSS_TARGET" ]; then
|
||||
unset CC;
|
||||
TARGET_OPTS="$TARGET_OPTS --host=$CROSS_TARGET";
|
||||
fi
|
||||
- if [ -n "$BUILD_LIBS" ]; then
|
||||
OPTS="$OPTS --with-gpg-error-prefix=$HOME";
|
||||
git clone git://git.gnupg.org/libgpg-error.git -b libgpg-error-1.13 --depth 1;
|
||||
pushd libgpg-error;
|
||||
./autogen.sh;
|
||||
./configure $TARGET_OPTS $OPTS --disable-languages --disable-doc;
|
||||
make;
|
||||
if [ -z "$WINE_TESTS" ]; then
|
||||
LD_LIBRARY_PATH="$HOME/lib" make check;
|
||||
fi;
|
||||
make install;
|
||||
popd;
|
||||
OPTS="$OPTS --with-libgcrypt-prefix=$HOME";
|
||||
git clone git://git.gnupg.org/libgcrypt.git -b libgcrypt-1.5.4 --depth 1;
|
||||
pushd libgcrypt;
|
||||
./autogen.sh;
|
||||
./configure $TARGET_OPTS $OPTS --disable-ciphers --disable-pubkey-ciphers --disable-random --disable-asm;
|
||||
make;
|
||||
if [ -z "$WINE_TESTS" ]; then
|
||||
LD_LIBRARY_PATH="$HOME/lib" make check;
|
||||
fi;
|
||||
make install;
|
||||
popd;
|
||||
|
||||
git clone https://github.com/akheron/jansson.git -b "$JANSSON_VERSION" --depth 1;
|
||||
pushd jansson;
|
||||
autoreconf -f -i;
|
||||
./configure $TARGET_OPTS $OPTS;
|
||||
make AM_CFLAGS= ;
|
||||
if [ -z "$WINE_TESTS" ]; then
|
||||
LD_LIBRARY_PATH="$HOME/lib" make check;
|
||||
fi;
|
||||
make install;
|
||||
popd;
|
||||
fi
|
||||
- git clone git://github.com/bitcoin/libbase58 -b v0.1.4 --depth 1
|
||||
- pushd libbase58
|
||||
- ./autogen.sh
|
||||
- ./configure $TARGET_OPTS $OPTS
|
||||
- make
|
||||
- if [ -z "$WINE_TESTS" ]; then
|
||||
LD_LIBRARY_PATH="$HOME/lib" make check VERBOSE=1;
|
||||
fi
|
||||
- make install
|
||||
- popd
|
||||
-
|
||||
- ./autogen.sh
|
||||
- ./configure $TARGET_OPTS $OPTS $CONFIGURE_OPTS || { tail -n 1000 config.log; false; };
|
||||
- make
|
||||
- make example$EXEEXT
|
||||
- make test$EXEEXT
|
||||
- if [ -z "$WINE_TESTS" ]; then
|
||||
LSAN_OPTIONS=1 LD_LIBRARY_PATH="$HOME/lib" make check VERBOSE=1;
|
||||
else
|
||||
ln -s $HOME/bin/*.dll .libs/;
|
||||
LSAN_OPTIONS=1 WINEDLLPATH="$PWD/.libs" wine .libs/test.exe;
|
||||
fi
|
||||
- make install
|
||||
3
AUTHORS
3
AUTHORS
@ -1 +1,4 @@
|
||||
Luke Dashjr <luke_libblkmaker@dashjr.org>
|
||||
Andy Alness <andy.alness@gmail.com>
|
||||
Huang Le <4tarhl@gmail.com>
|
||||
Cory Fields <cory-nospam-@coryfields.com>
|
||||
|
||||
2
COPYING
2
COPYING
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2012 Luke Dashjr
|
||||
Copyright 2012-2014 Luke Dashjr
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
370
INSTALL
370
INSTALL
@ -1,370 +0,0 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
HP-UX `make' updates targets which have the same time stamps as
|
||||
their prerequisites, which makes it generally unusable when shipped
|
||||
generated files such as `configure' are involved. Use GNU `make'
|
||||
instead.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
to try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
||||
in your `PATH', put it _after_ `/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in `/boot/common',
|
||||
not `/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS
|
||||
KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of all of the options to `configure', and exit.
|
||||
|
||||
`--help=short'
|
||||
`--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
`configure', and exit. The `short' variant lists options used
|
||||
only in the top level, while the `recursive' variant lists options
|
||||
also present in any nested packages.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names::
|
||||
for more details, including other options available for fine-tuning
|
||||
the installation locations.
|
||||
|
||||
`--no-create'
|
||||
`-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
44
Makefile.am
44
Makefile.am
@ -1,3 +1,8 @@
|
||||
# Copyright 2012-2013 Luke Dashjr
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the standard MIT license. See COPYING for more details.
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la \
|
||||
libblkmaker-@LIBBLKMAKER_API_VERSION@.la
|
||||
@ -7,9 +12,15 @@ libblkmaker_@LIBBLKMAKER_API_VERSION@_la_SOURCES = \
|
||||
base58.c \
|
||||
blkmaker.c \
|
||||
blktemplate.c \
|
||||
hex.c
|
||||
hex.c \
|
||||
private.h
|
||||
|
||||
libblkmaker_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = -version-info $(LIBBLKMAKER_SO_VERSION) -no-undefined
|
||||
libblkmaker_@LIBBLKMAKER_API_VERSION@_la_CFLAGS = \
|
||||
$(libbase58_CFLAGS)
|
||||
libblkmaker_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = \
|
||||
$(libbase58_LIBS) \
|
||||
-no-undefined \
|
||||
-version-info $(LIBBLKMAKER_SO_VERSION)
|
||||
|
||||
libblkmaker_includedir = $(includedir)/libblkmaker-$(LIBBLKMAKER_API_VERSION)
|
||||
libblkmaker_include_HEADERS = \
|
||||
@ -18,16 +29,41 @@ libblkmaker_include_HEADERS = \
|
||||
|
||||
libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_SOURCES = blkmaker_jansson.c
|
||||
libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_DEPENDENCIES = libblkmaker-$(LIBBLKMAKER_API_VERSION).la
|
||||
libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_CFLAGS = $(JANSSON_CFLAGS)
|
||||
libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = \
|
||||
-L.libs \
|
||||
-lblkmaker-$(LIBBLKMAKER_API_VERSION) \
|
||||
-ljansson \
|
||||
$(JANSSON_LIBS) \
|
||||
-no-undefined \
|
||||
-version-info $(LIBBLKMAKER_SO_VERSION)
|
||||
|
||||
libblkmaker_jansson_includedir = $(includedir)/libblkmaker-$(LIBBLKMAKER_API_VERSION)
|
||||
libblkmaker_jansson_include_HEADERS = \
|
||||
blkmaker_jansson.h
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = \
|
||||
libblkmaker_jansson-$(LIBBLKMAKER_API_VERSION).pc
|
||||
|
||||
dist_noinst_SCRIPTS = autogen.sh
|
||||
dist_noinst_SCRIPTS = autogen.sh test.sh
|
||||
dist_noinst_DATA = \
|
||||
AUTHORS COPYING README \
|
||||
example.c \
|
||||
testinput.c
|
||||
|
||||
if HAVE_LIBGCRYPT
|
||||
check_PROGRAMS = test
|
||||
test_SOURCES = test.c
|
||||
test_CFLAGS = $(libbase58_CFLAGS) $(JANSSON_CFLAGS) $(LIBGCRYPT_CFLAGS)
|
||||
test_LDADD = $(libbase58_LIBS) libblkmaker-@LIBBLKMAKER_API_VERSION@.la libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la $(JANSSON_LIBS) $(LIBGCRYPT_LIBS)
|
||||
TESTS = test.sh
|
||||
|
||||
EXTRA_PROGRAMS = example
|
||||
example_SOURCES = example.c
|
||||
example_CFLAGS = $(libbase58_CFLAGS) $(JANSSON_CFLAGS) $(LIBGCRYPT_CFLAGS)
|
||||
example_LDADD = $(libbase58_LIBS) libblkmaker-@LIBBLKMAKER_API_VERSION@.la libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la $(JANSSON_LIBS) $(LIBGCRYPT_LIBS)
|
||||
else
|
||||
example:
|
||||
@echo "libgcrypt is required to build the example, but was not found"
|
||||
.PHONY: example
|
||||
endif
|
||||
|
||||
17
README
17
README
@ -5,12 +5,19 @@ Example dependencies:
|
||||
Jansson 2.1 (to read JSON from stdin)
|
||||
libgcrypt (for SHA256)
|
||||
|
||||
For usage, check out example.c
|
||||
For usage, check out example.c. Run "make example" to build it.
|
||||
|
||||
Note that you must assign blkmk_sha256_impl to a function pointer:
|
||||
bool mysha256(void *hash_out, const void *data, size_t datasz)
|
||||
hash_out must be able to overlap with data!
|
||||
|
||||
Also note that you should NOT roll ntime for data retrieved; while it will
|
||||
probably work, there is no guarantee it won't fall outside the maxtime limits
|
||||
for the blocktemplate. It is usually best to simply get more data as often
|
||||
as it is needed.
|
||||
Also note that you should NOT roll ntime for data retrieved without explicitly
|
||||
checking that it falls within the template's limitations (mintime, maxtime,
|
||||
mintimeoff, and maxtimeoff); read the BIP 23 specification in detail to
|
||||
understand how they work. It is usually best to simply get more data as often
|
||||
as it is needed. For blkmk_get_mdata, you may specify that you intend to roll
|
||||
the ntime header exactly once per second past usetime - it will then set
|
||||
*out_expires such that the expiration occurs before you roll beyond any ntime
|
||||
limits. If you are rolling ntime at any rate other than once per second, you
|
||||
should NOT specify can_roll_ntime to blkmk_get_mdata, and must check that your
|
||||
usage falls within the explicit template limits yourself.
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
#!/bin/sh -e
|
||||
# Written by Luke Dashjr in 2012
|
||||
# This program is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver.
|
||||
|
||||
if test -z "$srcdir"; then
|
||||
srcdir=`dirname "$0"`
|
||||
if test -z "$srcdir"; then
|
||||
@ -6,4 +9,3 @@ if test -z "$srcdir"; then
|
||||
fi
|
||||
fi
|
||||
autoreconf --force --install --verbose "$srcdir"
|
||||
test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
|
||||
|
||||
104
base58.c
104
base58.c
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright 2012 Luke Dashjr
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the standard MIT license. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
@ -8,108 +15,35 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libbase58.h>
|
||||
|
||||
#include <blkmaker.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
static const int8_t b58digits[] = {
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
|
||||
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
|
||||
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
|
||||
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
|
||||
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
|
||||
};
|
||||
|
||||
bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) {
|
||||
const unsigned char *b58u = (void*)b58;
|
||||
unsigned char *binu = bin;
|
||||
size_t outisz = (binsz + 3) / 4;
|
||||
uint32_t outi[outisz];
|
||||
uint64_t t;
|
||||
uint32_t c;
|
||||
size_t i, j;
|
||||
uint8_t bytesleft = binsz % 4;
|
||||
uint32_t zeromask = ~((1 << ((bytesleft) * 8)) - 1);
|
||||
|
||||
if (!b58sz)
|
||||
b58sz = strlen(b58);
|
||||
|
||||
memset(outi, 0, outisz * sizeof(*outi));
|
||||
|
||||
for (i = 0; i < b58sz; ++i)
|
||||
{
|
||||
if (b58u[i] & 0x80)
|
||||
// High-bit set on invalid digit
|
||||
return false;
|
||||
if (b58digits[b58u[i]] == -1)
|
||||
// Invalid base58 digit
|
||||
return false;
|
||||
c = b58digits[b58u[i]];
|
||||
for (j = outisz; j--; )
|
||||
{
|
||||
t = ((uint64_t)outi[j]) * 58 + c;
|
||||
c = (t & 0x3f00000000) >> 32;
|
||||
outi[j] = t & 0xffffffff;
|
||||
}
|
||||
if (c)
|
||||
// Output number too big (carry to the next int32)
|
||||
return false;
|
||||
if (outi[0] & zeromask)
|
||||
// Output number too big (last int32 filled too far)
|
||||
return false;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
switch (bytesleft) {
|
||||
case 3:
|
||||
*(binu++) = (outi[0] & 0xff0000) >> 16;
|
||||
case 2:
|
||||
*(binu++) = (outi[0] & 0xff00) >> 8;
|
||||
case 1:
|
||||
*(binu++) = (outi[0] & 0xff);
|
||||
++j;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (; j < outisz; ++j)
|
||||
{
|
||||
*((uint32_t*)binu) = htonl(outi[j]);
|
||||
binu += sizeof(uint32_t);
|
||||
}
|
||||
return true;
|
||||
return b58tobin(bin, &binsz, b58, b58sz);
|
||||
}
|
||||
|
||||
int _blkmk_b58check(void *bin, size_t binsz, const char *base58str) {
|
||||
unsigned char buf[32];
|
||||
unsigned char *binc = bin;
|
||||
unsigned i;
|
||||
if (!_blkmk_dblsha256(buf, bin, binsz - 4))
|
||||
return -2;
|
||||
if (memcmp(&binc[binsz - 4], buf, 4))
|
||||
return -1;
|
||||
|
||||
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
|
||||
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
|
||||
{} // Just finding the end of zeros, nothing to do in loop
|
||||
if (binc[i] == '\0' || base58str[i] == '1')
|
||||
return -3;
|
||||
|
||||
return binc[0];
|
||||
if (!b58_sha256_impl)
|
||||
b58_sha256_impl = blkmk_sha256_impl;
|
||||
return b58check(bin, binsz, base58str, 34);
|
||||
}
|
||||
|
||||
size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr) {
|
||||
unsigned char addrbin[25];
|
||||
unsigned char *cout = out;
|
||||
const size_t b58sz = strlen(addr);
|
||||
int addrver;
|
||||
size_t rv;
|
||||
|
||||
if (!_blkmk_b58tobin(addrbin, sizeof(addrbin), addr, 0))
|
||||
rv = sizeof(addrbin);
|
||||
if (!b58_sha256_impl)
|
||||
b58_sha256_impl = blkmk_sha256_impl;
|
||||
if (!b58tobin(addrbin, &rv, addr, b58sz))
|
||||
return 0;
|
||||
addrver = _blkmk_b58check(addrbin, sizeof(addrbin), addr);
|
||||
addrver = b58check(addrbin, sizeof(addrbin), addr, b58sz);
|
||||
switch (addrver) {
|
||||
case 0: // Bitcoin pubkey hash
|
||||
case 111: // Testnet pubkey hash
|
||||
|
||||
748
blkmaker.c
748
blkmaker.c
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright 2012-2016 Luke Dashjr
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the standard MIT license. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@ -6,11 +13,32 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <blkmaker.h>
|
||||
#include <blktemplate.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
const char *blkmk_supported_rules[] = {
|
||||
"csv",
|
||||
"segwit",
|
||||
NULL
|
||||
};
|
||||
|
||||
bool blkmk_supports_rule(const char * const rulename) {
|
||||
for (const char **r = blkmk_supported_rules; *r; ++r) {
|
||||
if (!strcmp(rulename, *r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline
|
||||
void my_htole32(unsigned char *buf, uint32_t n) {
|
||||
buf[0] = (n >> 0) % 256;
|
||||
@ -34,19 +62,131 @@ bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) {
|
||||
|
||||
#define dblsha256 _blkmk_dblsha256
|
||||
|
||||
uint64_t blkmk_init_generation2(blktemplate_t *tmpl, void *script, size_t scriptsz, bool *out_newcb) {
|
||||
if (tmpl->cbtxn)
|
||||
static
|
||||
size_t varintDecode(const uint8_t *p, size_t size, uint64_t *n)
|
||||
{
|
||||
if (size > 8 && p[0] == 0xff)
|
||||
{
|
||||
*n = upk_u64le(p, 1);
|
||||
return 9;
|
||||
}
|
||||
if (size > 4 && p[0] == 0xfe)
|
||||
{
|
||||
*n = upk_u32le(p, 1);
|
||||
return 5;
|
||||
}
|
||||
if (size > 2 && p[0] == 0xfd)
|
||||
{
|
||||
*n = upk_u16le(p, 1);
|
||||
return 3;
|
||||
}
|
||||
if (size > 0 && p[0] <= 0xfc)
|
||||
{
|
||||
*n = p[0];
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define max_varint_size (9)
|
||||
|
||||
static
|
||||
char varintEncode(unsigned char *out, uint64_t n) {
|
||||
if (n < 0xfd)
|
||||
{
|
||||
out[0] = n;
|
||||
return 1;
|
||||
}
|
||||
char L;
|
||||
if (n <= 0xffff)
|
||||
{
|
||||
out[0] = '\xfd';
|
||||
L = 3;
|
||||
}
|
||||
else
|
||||
if (n <= 0xffffffff)
|
||||
{
|
||||
out[0] = '\xfe';
|
||||
L = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[0] = '\xff';
|
||||
L = 9;
|
||||
}
|
||||
for (unsigned char i = 1; i < L; ++i)
|
||||
out[i] = (n >> ((i - 1) * 8)) % 256;
|
||||
return L;
|
||||
}
|
||||
|
||||
static uint8_t blkmk_varint_encode_size(const uint64_t n) {
|
||||
uint8_t dummy[max_varint_size];
|
||||
return varintEncode(dummy, n);
|
||||
}
|
||||
|
||||
static
|
||||
int16_t blkmk_count_sigops(const uint8_t * const script, const size_t scriptsz, const bool bip141) {
|
||||
int16_t sigops = 0;
|
||||
for (size_t i = 0; i < scriptsz; ++i) {
|
||||
if (script[i] <= 0x4c /* OP_PUSHDATA1 */) {
|
||||
if (script[i] == 0x4c) {
|
||||
if (i + 1 >= scriptsz) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
i += script[i];
|
||||
} else if (script[i] == 0x4d /* OP_PUSHDATA2 */) {
|
||||
if (i + 2 >= scriptsz) {
|
||||
break;
|
||||
}
|
||||
i += 2 + upk_u16le(script, i + 1);
|
||||
} else if (script[i] == 0x4e /* OP_PUSHDATA4 */) {
|
||||
if (i + 4 >= scriptsz) {
|
||||
break;
|
||||
}
|
||||
i += 4 + upk_u32le(script, i + 1);
|
||||
} else if (script[i] == 0xac /* OP_CHECKSIG */ || script[i] == 0xad /* OP_CHECKSIGVERIFY */) {
|
||||
++sigops;
|
||||
} else if (script[i] == 0xae /* OP_CHECKMULTISIG */ || script[i] == 0xaf /* OP_CHECKMULTISIGVERIFY */) {
|
||||
sigops += 20;
|
||||
}
|
||||
}
|
||||
if (bip141) {
|
||||
sigops *= 4;
|
||||
}
|
||||
return sigops;
|
||||
}
|
||||
|
||||
static int64_t blkmk_calc_gentx_weight(const void * const data, const size_t datasz) {
|
||||
return (datasz * 4) + 2 /* marker & flag */ + 1 /* witness stack count */ + 1 /* stack item size */ + 32 /* stack item: nonce */;
|
||||
}
|
||||
|
||||
static int64_t blktxn_set_gentx_weight(struct blktxn_t * const gentx) {
|
||||
if (gentx->weight < 0) {
|
||||
gentx->weight = blkmk_calc_gentx_weight(gentx->data, gentx->datasz);
|
||||
}
|
||||
return gentx->weight;
|
||||
}
|
||||
|
||||
uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const script, const size_t scriptsz, bool * const inout_newcb) {
|
||||
const bool replace_existing = *inout_newcb;
|
||||
*inout_newcb = false;
|
||||
|
||||
if (tmpl->cbtxn && !(replace_existing && (tmpl->mutations & BMM_GENERATE)))
|
||||
{
|
||||
if (out_newcb)
|
||||
*out_newcb = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out_newcb)
|
||||
*out_newcb = true;
|
||||
if (!tmpl->has_cbvalue) {
|
||||
// TODO: Figure it out from the existing cbtxn
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t datasz = 62 + sizeof(blkheight_t) + scriptsz;
|
||||
unsigned char *data = malloc(datasz);
|
||||
if (scriptsz >= 0xfd)
|
||||
return 0;
|
||||
|
||||
unsigned char *data = malloc(168 + scriptsz);
|
||||
size_t off = 0;
|
||||
if (!data)
|
||||
return 0;
|
||||
@ -71,6 +211,27 @@ uint64_t blkmk_init_generation2(blktemplate_t *tmpl, void *script, size_t script
|
||||
data[off++] = h;
|
||||
data[42] = data[41] - 1;
|
||||
|
||||
if (tmpl->aux_count)
|
||||
{
|
||||
unsigned auxsz = off++;
|
||||
data[auxsz] = 0;
|
||||
++data[41];
|
||||
|
||||
for (unsigned i = 0; i < tmpl->aux_count; ++i)
|
||||
{
|
||||
struct blkaux_t * const aux = &tmpl->auxs[i];
|
||||
if ((size_t)data[41] + aux->datasz > libblkmaker_coinbase_size_limit)
|
||||
{
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
memcpy(&data[off], tmpl->auxs[i].data, aux->datasz);
|
||||
data[41] += aux->datasz;
|
||||
data[auxsz] += aux->datasz;
|
||||
off += aux->datasz;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&data[off],
|
||||
"\xff\xff\xff\xff" // sequence
|
||||
"\x01" // output count
|
||||
@ -79,55 +240,162 @@ uint64_t blkmk_init_generation2(blktemplate_t *tmpl, void *script, size_t script
|
||||
my_htole64(&data[off], tmpl->cbvalue);
|
||||
off += 8;
|
||||
data[off++] = scriptsz;
|
||||
memcpy(&data[off], script, scriptsz);
|
||||
off += scriptsz;
|
||||
if (scriptsz) {
|
||||
memcpy(&data[off], script, scriptsz);
|
||||
off += scriptsz;
|
||||
}
|
||||
memset(&data[off], 0, 4); // lock time
|
||||
off += 4;
|
||||
|
||||
struct blktxn_t *txn = calloc(1, sizeof(*tmpl->cbtxn));
|
||||
const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount);
|
||||
const int16_t sigops_counted = blkmk_count_sigops(script, scriptsz, tmpl->_bip141_sigops);
|
||||
const int64_t gentx_weight = blkmk_calc_gentx_weight(data, off);
|
||||
if (pretx_size + tmpl->txns_datasz + off > tmpl->sizelimit
|
||||
|| (tmpl->txns_weight >= 0 && tmpl->txns_weight + gentx_weight > tmpl->weightlimit)
|
||||
|| (tmpl->txns_sigops >= 0 && tmpl->txns_sigops + sigops_counted > tmpl->sigoplimit)) {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct blktxn_t *txn = malloc(sizeof(*tmpl->cbtxn));
|
||||
if (!txn)
|
||||
{
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
blktxn_init(txn);
|
||||
|
||||
txn->data = data;
|
||||
txn->datasz = off;
|
||||
txn->sigops_ = sigops_counted;
|
||||
txn->weight = gentx_weight;
|
||||
|
||||
if (tmpl->cbtxn)
|
||||
{
|
||||
blktxn_clean(tmpl->cbtxn);
|
||||
free(tmpl->cbtxn);
|
||||
}
|
||||
tmpl->cbtxn = txn;
|
||||
|
||||
tmpl->mutations |= BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE;
|
||||
|
||||
*inout_newcb = true;
|
||||
return tmpl->cbvalue;
|
||||
}
|
||||
|
||||
uint64_t blkmk_init_generation2(blktemplate_t *tmpl, void *script, size_t scriptsz, bool *out_newcb) {
|
||||
bool tmp;
|
||||
if (!out_newcb)
|
||||
out_newcb = &tmp;
|
||||
*out_newcb = false;
|
||||
return blkmk_init_generation3(tmpl, script, scriptsz, out_newcb);
|
||||
}
|
||||
|
||||
uint64_t blkmk_init_generation(blktemplate_t *tmpl, void *script, size_t scriptsz) {
|
||||
return blkmk_init_generation2(tmpl, script, scriptsz, NULL);
|
||||
}
|
||||
|
||||
static
|
||||
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) {
|
||||
bool blkmk_hash_transactions(blktemplate_t * const tmpl)
|
||||
{
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i)
|
||||
{
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
if (txn->hash_)
|
||||
continue;
|
||||
txn->hash_ = malloc(sizeof(*txn->hash_));
|
||||
if (!dblsha256(txn->hash_, txn->data, txn->datasz))
|
||||
{
|
||||
free(txn->hash_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool blkmk_build_merkle_branches(blktemplate_t * const tmpl)
|
||||
{
|
||||
int branchcount, i;
|
||||
libblkmaker_hash_t *branches;
|
||||
|
||||
if (tmpl->_mrklbranch)
|
||||
return true;
|
||||
|
||||
if (!blkmk_hash_transactions(tmpl))
|
||||
return false;
|
||||
|
||||
branchcount = blkmk_flsl(tmpl->txncount);
|
||||
if (!branchcount)
|
||||
{
|
||||
tmpl->_mrklbranchcount = 0;
|
||||
tmpl->_mrklbranch = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
branches = malloc(branchcount * sizeof(*branches));
|
||||
if (!branches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hashcount = tmpl->txncount + 1;
|
||||
unsigned char hashes[(hashcount + 1) * 32];
|
||||
libblkmaker_hash_t * const hashes = malloc((hashcount + 1) * sizeof(*hashes)); // +1 for when the last needs duplicating
|
||||
if (!hashes) {
|
||||
free(branches);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < tmpl->txncount; ++i)
|
||||
{
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
txnhash_t * const txid = txn->txid ? txn->txid : txn->hash_;
|
||||
memcpy(&hashes[i + 1], txid, sizeof(*hashes));
|
||||
}
|
||||
|
||||
for (i = 0; i < branchcount; ++i)
|
||||
{
|
||||
memcpy(&branches[i], &hashes[1], sizeof(*hashes));
|
||||
if (hashcount % 2)
|
||||
{
|
||||
memcpy(&hashes[hashcount], &hashes[hashcount - 1], sizeof(*hashes));
|
||||
++hashcount;
|
||||
}
|
||||
for (size_t i = 2; i < hashcount; i += 2)
|
||||
// This is where we overlap input and output, on the first pair
|
||||
if (!dblsha256(&hashes[i / 2], &hashes[i], sizeof(*hashes) * 2))
|
||||
{
|
||||
free(branches);
|
||||
free(hashes);
|
||||
return false;
|
||||
}
|
||||
hashcount /= 2;
|
||||
}
|
||||
|
||||
free(hashes);
|
||||
|
||||
tmpl->_mrklbranch = branches;
|
||||
tmpl->_mrklbranchcount = branchcount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) {
|
||||
int i;
|
||||
libblkmaker_hash_t hashes[0x40];
|
||||
|
||||
if (!blkmk_build_merkle_branches(tmpl))
|
||||
return false;
|
||||
|
||||
if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz))
|
||||
return false;
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i)
|
||||
if (!dblsha256(&hashes[32 * (i + 1)], tmpl->txns[i].data, tmpl->txns[i].datasz))
|
||||
return false;
|
||||
|
||||
while (hashcount > 1)
|
||||
for (i = 0; i < tmpl->_mrklbranchcount; ++i)
|
||||
{
|
||||
if (hashcount % 2)
|
||||
{
|
||||
memcpy(&hashes[32 * hashcount], &hashes[32 * (hashcount - 1)], 32);
|
||||
++hashcount;
|
||||
}
|
||||
for (size_t i = 0; i < hashcount; i += 2)
|
||||
// This is where we overlap input and output, on the first pair
|
||||
if (!dblsha256(&hashes[i / 2 * 32], &hashes[32 * i], 64))
|
||||
return false;
|
||||
hashcount /= 2;
|
||||
memcpy(&hashes[1], tmpl->_mrklbranch[i], 0x20);
|
||||
// This is where we overlap input and output, on the first pair
|
||||
if (!dblsha256(&hashes[0], &hashes[0], 0x40))
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(mrklroot_out, &hashes[0], 32);
|
||||
@ -135,18 +403,101 @@ bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigne
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool _blkmk_calculate_witness_mrklroot(blktemplate_t * const tmpl, libblkmaker_hash_t * const out, bool * const witness_needed) {
|
||||
if (!blkmk_hash_transactions(tmpl))
|
||||
return false;
|
||||
|
||||
// Step 1: Populate hashes with the witness hashes for all transactions
|
||||
size_t hashcount = tmpl->txncount + 1;
|
||||
libblkmaker_hash_t * const hashes = malloc((hashcount + 1) * sizeof(*hashes)); // +1 for when the last needs duplicating
|
||||
if (!hashes) {
|
||||
return false;
|
||||
}
|
||||
memset(&hashes[0], 0, sizeof(hashes[0])); // Gen tx gets a null entry
|
||||
*witness_needed = false;
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i) {
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
if (txn->txid && memcmp(txn->hash_, txn->txid, sizeof(*txn->txid))) {
|
||||
*witness_needed = true;
|
||||
}
|
||||
memcpy(&hashes[i + 1], txn->hash_, sizeof(*hashes));
|
||||
}
|
||||
if (!*witness_needed) {
|
||||
free(hashes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 2: Reduce it to a merkle root
|
||||
for ( ; hashcount > 1 ; hashcount /= 2) {
|
||||
if (hashcount % 2 == 1) {
|
||||
// Odd number, duplicate the last
|
||||
memcpy(&hashes[hashcount], &hashes[hashcount - 1], sizeof(*hashes));
|
||||
++hashcount;
|
||||
}
|
||||
for (size_t i = 0; i < hashcount; i += 2) {
|
||||
// We overlap input and output here, on the first pair
|
||||
if (!dblsha256(&hashes[i / 2], &hashes[i], sizeof(*hashes) * 2)) {
|
||||
free(hashes);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(out, hashes, sizeof(*out));
|
||||
free(hashes);
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool _blkmk_witness_mrklroot(blktemplate_t * const tmpl) {
|
||||
if (tmpl->_calculated_witness) {
|
||||
// Already calculated
|
||||
return true;
|
||||
}
|
||||
tmpl->_witnessmrklroot = malloc(sizeof(libblkmaker_hash_t));
|
||||
if (!tmpl->_witnessmrklroot) {
|
||||
return false;
|
||||
}
|
||||
bool witness_needed;
|
||||
if (!_blkmk_calculate_witness_mrklroot(tmpl, tmpl->_witnessmrklroot, &witness_needed)) {
|
||||
free(tmpl->_witnessmrklroot);
|
||||
tmpl->_witnessmrklroot = NULL;
|
||||
return false;
|
||||
}
|
||||
if (!witness_needed) {
|
||||
free(tmpl->_witnessmrklroot);
|
||||
tmpl->_witnessmrklroot = NULL;
|
||||
}
|
||||
tmpl->_calculated_witness = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const int cbScriptSigLen = 4 + 1 + 36;
|
||||
|
||||
static
|
||||
bool _blkmk_append_cb(blktemplate_t *tmpl, void *vout, const void *append, size_t appendsz) {
|
||||
bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void * const append, const size_t appendsz, size_t * const appended_at_offset, int16_t * const sigops_counted_p) {
|
||||
unsigned char *out = vout;
|
||||
unsigned char *in = tmpl->cbtxn->data;
|
||||
size_t insz = tmpl->cbtxn->datasz;
|
||||
|
||||
if (in[cbScriptSigLen] > 100 - appendsz)
|
||||
if (appendsz > libblkmaker_coinbase_size_limit || in[cbScriptSigLen] > libblkmaker_coinbase_size_limit - appendsz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount);
|
||||
if (pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz + appendsz > tmpl->sizelimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmpl->txns_weight >= 0 && (blktxn_set_gentx_weight(tmpl->cbtxn) + tmpl->txns_weight + (appendsz * 4) > tmpl->weightlimit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int16_t orig_scriptSig_sigops = blkmk_count_sigops(&in[cbScriptSigLen + 1], in[cbScriptSigLen], tmpl->_bip141_sigops);
|
||||
int cbPostScriptSig = cbScriptSigLen + 1 + in[cbScriptSigLen];
|
||||
if (appended_at_offset)
|
||||
*appended_at_offset = cbPostScriptSig;
|
||||
unsigned char *outPostScriptSig = &out[cbPostScriptSig];
|
||||
void *outExtranonce = (void*)outPostScriptSig;
|
||||
outPostScriptSig += appendsz;
|
||||
@ -162,15 +513,66 @@ bool _blkmk_append_cb(blktemplate_t *tmpl, void *vout, const void *append, size_
|
||||
out[cbScriptSigLen] += appendsz;
|
||||
memcpy(outExtranonce, append, appendsz);
|
||||
|
||||
const int16_t sigops_counted = tmpl->cbtxn->sigops_ + blkmk_count_sigops(&out[cbScriptSigLen + 1], out[cbScriptSigLen], tmpl->_bip141_sigops) - orig_scriptSig_sigops;
|
||||
if (tmpl->txns_sigops >= 0 && tmpl->txns_sigops + sigops_counted > tmpl->sigoplimit) {
|
||||
// Overflowed :(
|
||||
if (out == in) {
|
||||
// Revert it!
|
||||
out[cbScriptSigLen] -= appendsz;
|
||||
memmove(&out[cbPostScriptSig], outPostScriptSig, insz - cbPostScriptSig);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sigops_counted_p) {
|
||||
*sigops_counted_p = sigops_counted;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t blkmk_append_coinbase_safe(blktemplate_t *tmpl, const void *append, size_t appendsz) {
|
||||
ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * const append, const size_t appendsz, int extranoncesz, const bool merkle_only)
|
||||
{
|
||||
if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET)))
|
||||
return -1;
|
||||
|
||||
size_t datasz = tmpl->cbtxn->datasz;
|
||||
size_t availsz = 100 - sizeof(unsigned int) - tmpl->cbtxn->data[cbScriptSigLen];
|
||||
if (extranoncesz == sizeof(unsigned int)) {
|
||||
++extranoncesz;
|
||||
} else
|
||||
if (!merkle_only)
|
||||
{
|
||||
if (extranoncesz < sizeof(unsigned int))
|
||||
extranoncesz = sizeof(unsigned int);
|
||||
}
|
||||
if (tmpl->cbtxn->datasz <= cbScriptSigLen || tmpl->cbtxn->datasz <= cbScriptSigLen + tmpl->cbtxn->data[cbScriptSigLen]) {
|
||||
return -6;
|
||||
}
|
||||
if (extranoncesz > libblkmaker_coinbase_size_limit || tmpl->cbtxn->data[cbScriptSigLen] > libblkmaker_coinbase_size_limit || extranoncesz + tmpl->cbtxn->data[cbScriptSigLen] > libblkmaker_coinbase_size_limit) {
|
||||
return -5;
|
||||
}
|
||||
size_t availsz = libblkmaker_coinbase_size_limit - extranoncesz - tmpl->cbtxn->data[cbScriptSigLen];
|
||||
{
|
||||
const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount);
|
||||
const size_t current_blocksize = pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz;
|
||||
if (current_blocksize > tmpl->sizelimit) {
|
||||
return -4;
|
||||
}
|
||||
const size_t availsz2 = tmpl->sizelimit - current_blocksize;
|
||||
if (availsz2 < availsz) {
|
||||
availsz = availsz2;
|
||||
}
|
||||
}
|
||||
if (tmpl->txns_weight >= 0) {
|
||||
const size_t current_blockweight = blktxn_set_gentx_weight(tmpl->cbtxn) + tmpl->txns_weight;
|
||||
if (current_blockweight > tmpl->weightlimit) {
|
||||
return false;
|
||||
}
|
||||
const size_t availsz2 = (tmpl->weightlimit - current_blockweight) / 4;
|
||||
if (availsz2 < availsz) {
|
||||
availsz = availsz2;
|
||||
}
|
||||
}
|
||||
if (appendsz > availsz)
|
||||
return availsz;
|
||||
|
||||
@ -179,13 +581,18 @@ ssize_t blkmk_append_coinbase_safe(blktemplate_t *tmpl, const void *append, size
|
||||
return -2;
|
||||
|
||||
tmpl->cbtxn->data = newp;
|
||||
if (!_blkmk_append_cb(tmpl, newp, append, appendsz))
|
||||
if (!_blkmk_append_cb(tmpl, newp, append, appendsz, NULL, &tmpl->cbtxn->sigops_))
|
||||
return -3;
|
||||
tmpl->cbtxn->datasz += appendsz;
|
||||
tmpl->cbtxn->weight += appendsz * 4;
|
||||
|
||||
return availsz;
|
||||
}
|
||||
|
||||
ssize_t blkmk_append_coinbase_safe(blktemplate_t * const tmpl, const void * const append, const size_t appendsz) {
|
||||
return blkmk_append_coinbase_safe2(tmpl, append, appendsz, 0, false);
|
||||
}
|
||||
|
||||
bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs) {
|
||||
unsigned char *in = tmpl->cbtxn->data;
|
||||
size_t insz = tmpl->cbtxn->datasz;
|
||||
@ -197,7 +604,7 @@ bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, siz
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid)))
|
||||
if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid), NULL, NULL))
|
||||
return false;
|
||||
|
||||
*offs += insz + sizeof(workid);
|
||||
@ -205,36 +612,197 @@ bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, siz
|
||||
return true;
|
||||
}
|
||||
|
||||
static const unsigned char witness_magic[] = { 0x6a /* OP_RETURN */, 0x24, 0xaa, 0x21, 0xa9, 0xed };
|
||||
#define commitment_spk_size (sizeof(witness_magic) + sizeof(libblkmaker_hash_t) /* witness mrklroot */)
|
||||
#define commitment_txout_size (8 /* value */ + 1 /* scriptPubKey length */ + commitment_spk_size)
|
||||
static const size_t max_witness_commitment_insert = max_varint_size + commitment_txout_size - 1;
|
||||
static const libblkmaker_hash_t witness_nonce = { 0 };
|
||||
|
||||
static
|
||||
bool _blkmk_insert_witness_commitment(blktemplate_t * const tmpl, unsigned char * const gentxdata, size_t * const gentxsize) {
|
||||
if (!_blkmk_witness_mrklroot(tmpl)) {
|
||||
return false;
|
||||
}
|
||||
if (!tmpl->_witnessmrklroot) {
|
||||
// No commitment needed
|
||||
return true;
|
||||
}
|
||||
|
||||
libblkmaker_hash_t merkle_with_nonce[2];
|
||||
libblkmaker_hash_t commitment;
|
||||
memcpy(&merkle_with_nonce[0], tmpl->_witnessmrklroot, sizeof(*tmpl->_witnessmrklroot));
|
||||
memcpy(&merkle_with_nonce[1], &witness_nonce, sizeof(witness_nonce));
|
||||
if(!dblsha256(&commitment, &merkle_with_nonce[0], sizeof(merkle_with_nonce)))
|
||||
return false;
|
||||
|
||||
if (cbScriptSigLen >= *gentxsize) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t coinbasesz = gentxdata[cbScriptSigLen];
|
||||
const size_t offset_of_txout_count = cbScriptSigLen + coinbasesz + sizeof(coinbasesz) + 4 /* nSequence */;
|
||||
if (offset_of_txout_count >= *gentxsize) {
|
||||
return false;
|
||||
}
|
||||
uint64_t txout_count;
|
||||
const size_t in_txout_count_size = varintDecode(&gentxdata[offset_of_txout_count], *gentxsize - offset_of_txout_count, &txout_count);
|
||||
if (!in_txout_count_size) {
|
||||
return false;
|
||||
}
|
||||
++txout_count;
|
||||
unsigned char insertbuf[max_varint_size + commitment_txout_size];
|
||||
const size_t out_txout_count_size = varintEncode(insertbuf, txout_count);
|
||||
unsigned char * const commitment_txout = &insertbuf[out_txout_count_size];
|
||||
memset(commitment_txout, 0, 8); // value
|
||||
commitment_txout[8] = commitment_spk_size;
|
||||
memcpy(&commitment_txout[9], witness_magic, sizeof(witness_magic));
|
||||
memcpy(&commitment_txout[9 + sizeof(witness_magic)], &commitment, sizeof(commitment));
|
||||
|
||||
const size_t offset_of_txout_data = (offset_of_txout_count + in_txout_count_size);
|
||||
const size_t new_offset_of_preexisting_txout_data = (offset_of_txout_count + out_txout_count_size);
|
||||
const size_t length_of_txtail = 4;
|
||||
const size_t length_of_preexisting_txout_data = (*gentxsize - length_of_txtail) - offset_of_txout_data;
|
||||
const size_t offset_of_txtail_i = *gentxsize - length_of_txtail; // just the lock time
|
||||
const size_t offset_of_txtail_o = offset_of_txtail_i + (out_txout_count_size - in_txout_count_size) + commitment_txout_size;
|
||||
memmove(&gentxdata[offset_of_txtail_o], &gentxdata[offset_of_txtail_i], length_of_txtail);
|
||||
if (offset_of_txout_data != new_offset_of_preexisting_txout_data) {
|
||||
memmove(&gentxdata[new_offset_of_preexisting_txout_data], &gentxdata[offset_of_txout_data], length_of_preexisting_txout_data);
|
||||
}
|
||||
memcpy(&gentxdata[offset_of_txout_count], insertbuf, out_txout_count_size);
|
||||
const size_t offset_of_commitment_txout_o = new_offset_of_preexisting_txout_data + length_of_preexisting_txout_data;
|
||||
memcpy(&gentxdata[offset_of_commitment_txout_o], commitment_txout, commitment_txout_size);
|
||||
|
||||
*gentxsize = offset_of_txtail_o + length_of_txtail;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
void blkmk_set_times(blktemplate_t *tmpl, void * const out_hdrbuf, const time_t usetime, int16_t * const out_expire, const bool can_roll_ntime)
|
||||
{
|
||||
double time_passed = difftime(usetime, tmpl->_time_rcvd);
|
||||
blktime_t timehdr = tmpl->curtime + time_passed;
|
||||
if (timehdr > tmpl->maxtime)
|
||||
timehdr = tmpl->maxtime;
|
||||
my_htole32(out_hdrbuf, timehdr);
|
||||
if (out_expire)
|
||||
{
|
||||
*out_expire = tmpl->expires - time_passed - 1;
|
||||
|
||||
if (can_roll_ntime)
|
||||
{
|
||||
// If the caller can roll the time header, we need to expire before reaching the maxtime
|
||||
int16_t maxtime_expire_limit = (tmpl->maxtime - timehdr) + 1;
|
||||
if (*out_expire > maxtime_expire_limit)
|
||||
*out_expire = maxtime_expire_limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool blkmk_sample_data_(blktemplate_t * const tmpl, uint8_t * const cbuf, const unsigned int dataid) {
|
||||
my_htole32(&cbuf[0], tmpl->version);
|
||||
memcpy(&cbuf[4], &tmpl->prevblk, 32);
|
||||
|
||||
unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(dataid) + max_witness_commitment_insert];
|
||||
size_t cbtxndatasz = 0;
|
||||
if (!_blkmk_extranonce(tmpl, cbtxndata, dataid, &cbtxndatasz))
|
||||
return false;
|
||||
if (!_blkmk_insert_witness_commitment(tmpl, cbtxndata, &cbtxndatasz)) {
|
||||
return false;
|
||||
}
|
||||
if (!build_merkle_root(&cbuf[36], tmpl, cbtxndata, cbtxndatasz))
|
||||
return false;
|
||||
|
||||
my_htole32(&cbuf[0x44], tmpl->curtime);
|
||||
memcpy(&cbuf[72], &tmpl->diffbits, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid) {
|
||||
if (!(blkmk_time_left(tmpl, usetime) && blkmk_work_left(tmpl) && tmpl->cbtxn))
|
||||
return 0;
|
||||
if (bufsz < 76)
|
||||
return 76;
|
||||
|
||||
if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid) < libblkmaker_coinbase_size_minimum) {
|
||||
// Add some padding
|
||||
const size_t padding_required = libblkmaker_coinbase_size_minimum - (tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid));
|
||||
uint8_t padding[padding_required];
|
||||
static const uint8_t opcode_nop = '\x61';
|
||||
memset(padding, opcode_nop, padding_required);
|
||||
if (padding_required != blkmk_append_coinbase_safe2(tmpl, padding, padding_required, 0, false)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *cbuf = buf;
|
||||
|
||||
*out_dataid = tmpl->next_dataid++;
|
||||
if (!blkmk_sample_data_(tmpl, cbuf, *out_dataid))
|
||||
return 0;
|
||||
blkmk_set_times(tmpl, &cbuf[68], usetime, out_expire, false);
|
||||
|
||||
return 76;
|
||||
}
|
||||
|
||||
bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t bufsz, const time_t usetime, int16_t * const out_expire, void * const _out_cbtxn, size_t * const out_cbtxnsz, size_t * const cbextranonceoffset, int * const out_branchcount, void * const _out_branches, size_t extranoncesz, const bool can_roll_ntime)
|
||||
{
|
||||
if (!(true
|
||||
&& blkmk_time_left(tmpl, usetime)
|
||||
&& tmpl->cbtxn
|
||||
&& blkmk_build_merkle_branches(tmpl)
|
||||
&& bufsz >= 76
|
||||
&& (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))
|
||||
))
|
||||
return false;
|
||||
|
||||
if (extranoncesz == sizeof(unsigned int))
|
||||
// Avoid overlapping with blkmk_get_data use
|
||||
++extranoncesz;
|
||||
|
||||
if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + extranoncesz < libblkmaker_coinbase_size_minimum) {
|
||||
extranoncesz = libblkmaker_coinbase_size_minimum - tmpl->cbtxn->data[cbScriptSigLen];
|
||||
}
|
||||
|
||||
void ** const out_branches = _out_branches;
|
||||
void ** const out_cbtxn = _out_cbtxn;
|
||||
unsigned char *cbuf = buf;
|
||||
|
||||
my_htole32(&cbuf[0], tmpl->version);
|
||||
memcpy(&cbuf[4], &tmpl->prevblk, 32);
|
||||
|
||||
unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(*out_dataid)];
|
||||
size_t cbtxndatasz = 0;
|
||||
*out_dataid = tmpl->next_dataid++;
|
||||
if (!_blkmk_extranonce(tmpl, cbtxndata, *out_dataid, &cbtxndatasz))
|
||||
return 0;
|
||||
if (!build_merkle_root(&cbuf[36], tmpl, cbtxndata, cbtxndatasz))
|
||||
return 0;
|
||||
*out_cbtxnsz = tmpl->cbtxn->datasz + extranoncesz;
|
||||
*out_cbtxn = malloc(*out_cbtxnsz + max_witness_commitment_insert);
|
||||
if (!*out_cbtxn)
|
||||
return false;
|
||||
unsigned char dummy[extranoncesz];
|
||||
memset(dummy, 0, extranoncesz);
|
||||
if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset, NULL))
|
||||
{
|
||||
free(*out_cbtxn);
|
||||
return false;
|
||||
}
|
||||
if (!_blkmk_insert_witness_commitment(tmpl, *out_cbtxn, out_cbtxnsz)) {
|
||||
free(*out_cbtxn);
|
||||
return false;
|
||||
}
|
||||
|
||||
blktime_t timehdr = tmpl->curtime + difftime(usetime, tmpl->_time_rcvd);
|
||||
if (timehdr > tmpl->maxtime)
|
||||
timehdr = tmpl->maxtime;
|
||||
my_htole32(&cbuf[68], timehdr);
|
||||
blkmk_set_times(tmpl, &cbuf[68], usetime, out_expire, can_roll_ntime);
|
||||
memcpy(&cbuf[72], &tmpl->diffbits, 4);
|
||||
// TODO: set *out_expire if provided
|
||||
|
||||
// TEMPORARY HACK:
|
||||
memcpy(tmpl->_mrklroot, &cbuf[36], 32);
|
||||
*out_branchcount = tmpl->_mrklbranchcount;
|
||||
const size_t branches_bytesz = (sizeof(libblkmaker_hash_t) * tmpl->_mrklbranchcount);
|
||||
*out_branches = malloc(branches_bytesz);
|
||||
if (!*out_branches)
|
||||
{
|
||||
free(*out_cbtxn);
|
||||
return false;
|
||||
}
|
||||
if (branches_bytesz) {
|
||||
memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz);
|
||||
}
|
||||
|
||||
return 76;
|
||||
return true;
|
||||
}
|
||||
|
||||
blktime_diff_t blkmk_time_left(const blktemplate_t *tmpl, time_t nowtime) {
|
||||
@ -248,7 +816,87 @@ unsigned long blkmk_work_left(const blktemplate_t *tmpl) {
|
||||
if (!tmpl->version)
|
||||
return 0;
|
||||
if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET)))
|
||||
return 1;
|
||||
return (tmpl->next_dataid) ? 0 : 1;
|
||||
return UINT_MAX - tmpl->next_dataid;
|
||||
return BLKMK_UNLIMITED_WORK_COUNT;
|
||||
}
|
||||
|
||||
static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, const unsigned char * const data, const void * const extranonce, const size_t extranoncesz, blknonce_t nonce, const bool foreign)
|
||||
{
|
||||
const bool incl_gentxn = (foreign || (!(tmpl->mutations & BMAb_TRUNCATE && !extranoncesz)));
|
||||
const bool incl_alltxn = (foreign || !(tmpl->mutations & BMAb_COINBASE));
|
||||
|
||||
size_t blkbuf_sz = libblkmaker_blkheader_size;
|
||||
if (incl_gentxn) {
|
||||
blkbuf_sz += max_varint_size /* tx count */;
|
||||
blkbuf_sz += tmpl->cbtxn->datasz + extranoncesz + (max_varint_size - 1) /* possible enlargement to txout count when adding commitment output */ + commitment_txout_size;
|
||||
if (incl_alltxn) {
|
||||
blkbuf_sz += tmpl->txns_datasz;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char * const blk = malloc(blkbuf_sz);
|
||||
if (!blk) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t header_before_nonce_sz = libblkmaker_blkheader_size - sizeof(nonce);
|
||||
memcpy(blk, data, header_before_nonce_sz);
|
||||
nonce = htonl(nonce);
|
||||
memcpy(&blk[header_before_nonce_sz], &nonce, sizeof(nonce));
|
||||
size_t offs = libblkmaker_blkheader_size;
|
||||
|
||||
if (incl_gentxn) {
|
||||
offs += varintEncode(&blk[offs], 1 + tmpl->txncount);
|
||||
|
||||
size_t cbtxnlen = 0;
|
||||
// Essentially _blkmk_extranonce
|
||||
if (extranoncesz) {
|
||||
if (!_blkmk_append_cb(tmpl, &blk[offs], extranonce, extranoncesz, NULL, NULL)) {
|
||||
free(blk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cbtxnlen += tmpl->cbtxn->datasz + extranoncesz;
|
||||
} else {
|
||||
memcpy(&blk[offs], tmpl->cbtxn->data, tmpl->cbtxn->datasz);
|
||||
cbtxnlen += tmpl->cbtxn->datasz;
|
||||
}
|
||||
if (!_blkmk_insert_witness_commitment(tmpl, &blk[offs], &cbtxnlen)) {
|
||||
return NULL;
|
||||
}
|
||||
offs += cbtxnlen;
|
||||
|
||||
if (incl_alltxn) {
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i)
|
||||
{
|
||||
memcpy(&blk[offs], tmpl->txns[i].data, tmpl->txns[i].datasz);
|
||||
offs += tmpl->txns[i].datasz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *blkhex = malloc((offs * 2) + 1);
|
||||
_blkmk_bin2hex(blkhex, blk, offs);
|
||||
free(blk);
|
||||
|
||||
return blkhex;
|
||||
}
|
||||
|
||||
char *blkmk_assemble_submission2_(blktemplate_t * const tmpl, const unsigned char * const data, const void *extranonce, size_t extranoncesz, const unsigned int dataid, const blknonce_t nonce, const bool foreign)
|
||||
{
|
||||
if (dataid) {
|
||||
if (extranoncesz) {
|
||||
// Cannot specify both!
|
||||
return NULL;
|
||||
}
|
||||
extranonce = &dataid;
|
||||
extranoncesz = sizeof(dataid);
|
||||
} else if (extranoncesz == sizeof(unsigned int)) {
|
||||
// Avoid overlapping with blkmk_get_data use
|
||||
unsigned char extended_extranonce[extranoncesz + 1];
|
||||
memcpy(extended_extranonce, extranonce, extranoncesz);
|
||||
extended_extranonce[extranoncesz] = 0;
|
||||
return blkmk_assemble_submission2_internal(tmpl, data, extended_extranonce, extranoncesz + 1, nonce, foreign);
|
||||
}
|
||||
return blkmk_assemble_submission2_internal(tmpl, data, extranonce, extranoncesz, nonce, foreign);
|
||||
}
|
||||
|
||||
19
blkmaker.h
19
blkmaker.h
@ -7,20 +7,35 @@
|
||||
|
||||
#include <blktemplate.h>
|
||||
|
||||
#define BLKMAKER_VERSION (3L)
|
||||
#define BLKMAKER_MAX_BLOCK_VERSION (2)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLKMAKER_VERSION (8L)
|
||||
#define BLKMAKER_MAX_BLOCK_VERSION (0x3fffffff)
|
||||
#define BLKMAKER_MAX_PRERULES_BLOCK_VERSION (4)
|
||||
|
||||
extern const char *blkmk_supported_rules[];
|
||||
extern bool blkmk_supports_rule(const char *rulename);
|
||||
|
||||
extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz);
|
||||
|
||||
extern uint64_t blkmk_init_generation(blktemplate_t *, void *script, size_t scriptsz);
|
||||
extern uint64_t blkmk_init_generation2(blktemplate_t *, void *script, size_t scriptsz, bool *out_newcb);
|
||||
extern uint64_t blkmk_init_generation3(blktemplate_t *, const void *script, size_t scriptsz, bool *inout_newcb);
|
||||
extern ssize_t blkmk_append_coinbase_safe(blktemplate_t *, const void *append, size_t appendsz);
|
||||
extern ssize_t blkmk_append_coinbase_safe2(blktemplate_t *, const void *append, size_t appendsz, int extranoncesz, bool merkle_only);
|
||||
extern bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs);
|
||||
extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid);
|
||||
extern bool blkmk_get_mdata(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, void *out_cbtxn, size_t *out_cbtxnsz, size_t *cbextranonceoffset, int *out_branchcount, void *out_branches, size_t extranoncesz, bool can_roll_ntime);
|
||||
extern blktime_diff_t blkmk_time_left(const blktemplate_t *, time_t nowtime);
|
||||
extern unsigned long blkmk_work_left(const blktemplate_t *);
|
||||
#define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX
|
||||
|
||||
extern size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
#define _BSD_SOURCE
|
||||
/*
|
||||
* Copyright 2012-2016 Luke Dashjr
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the standard MIT license. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#define _BSD_SOURCE
|
||||
#define _DEFAULT_SOURCE
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
#include <blkmaker.h>
|
||||
@ -20,7 +24,7 @@
|
||||
# error "Jansson 2.0 with long long support required!"
|
||||
#endif
|
||||
|
||||
json_t *blktmpl_request_jansson(gbt_capabilities_t caps, const char *lpid) {
|
||||
json_t *blktmpl_request_jansson2(const uint32_t caps, const char * const lpid, const char * const * const rulelist) {
|
||||
json_t *req, *jcaps, *jstr, *reqf, *reqa;
|
||||
if (!(req = json_object()))
|
||||
return NULL;
|
||||
@ -59,6 +63,26 @@ json_t *blktmpl_request_jansson(gbt_capabilities_t caps, const char *lpid) {
|
||||
if (json_object_set_new(req, "longpollid", jstr))
|
||||
goto err;
|
||||
}
|
||||
jstr = NULL;
|
||||
|
||||
// Add rules list
|
||||
if (!(jcaps = json_array())) {
|
||||
goto err;
|
||||
}
|
||||
for (const char * const *currule = rulelist; *currule; ++currule) {
|
||||
if (!(jstr = json_string(*currule))) {
|
||||
goto err;
|
||||
}
|
||||
if (json_array_append_new(jcaps, jstr)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
jstr = NULL;
|
||||
if (json_object_set_new(req, "rules", jcaps))
|
||||
goto err;
|
||||
jcaps = NULL;
|
||||
|
||||
// Put together main JSON-RPC request Object
|
||||
if (!(jstr = json_string("getblocktemplate")))
|
||||
goto err;
|
||||
if (json_object_set_new(reqf, "method", jstr))
|
||||
@ -81,6 +105,10 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) {
|
||||
return blktmpl_request_jansson2(caps, lpid, blkmk_supported_rules);
|
||||
}
|
||||
|
||||
|
||||
#define my_hex2bin _blkmk_hex2bin
|
||||
|
||||
@ -97,17 +125,49 @@ err:
|
||||
return "Error decoding '" #key "'"; \
|
||||
} while(0)
|
||||
|
||||
#define GETNUM(key) do { \
|
||||
#define GETNUM(key, type) do { \
|
||||
GET(key, number); \
|
||||
tmpl->key = json_integer_value(v); \
|
||||
const double tmpd = json_number_value(v); \
|
||||
const type tmp = tmpd; \
|
||||
if (tmpd != tmp) { \
|
||||
return "Invalid number value for '" #key "'"; \
|
||||
} \
|
||||
tmpl->key = tmp; \
|
||||
} while(0)
|
||||
|
||||
#define GETNUM_O2(key, skey) do { \
|
||||
if ((v = json_object_get(json, #skey)) && json_is_number(v)) \
|
||||
tmpl->key = json_integer_value(v); \
|
||||
#define GETNUM_T(key, type) do { \
|
||||
GET(key, number); \
|
||||
const double tmpd = json_number_value(v); \
|
||||
const type tmp = tmpd; \
|
||||
/* This checks if it's merely being truncated, and tolerates it */ \
|
||||
if (tmpd != tmp && !((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \
|
||||
return "Invalid number value for '" #key "'"; \
|
||||
} \
|
||||
tmpl->key = tmp; \
|
||||
} while(0)
|
||||
|
||||
#define GETNUM_O(key) GETNUM_O2(key, key)
|
||||
#define GETNUM_O2(key, skey, type) do { \
|
||||
if ((v = json_object_get(json, #skey)) && json_is_number(v)) { \
|
||||
const double tmpd = json_number_value(v); \
|
||||
const type tmp = tmpd; \
|
||||
if (tmpd == tmp) { \
|
||||
tmpl->key = tmp; \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define GETNUM_O(key, type) GETNUM_O2(key, key, type)
|
||||
|
||||
#define GETNUM_OT(key, type) do { \
|
||||
if ((v = json_object_get(json, #key)) && json_is_number(v)) { \
|
||||
const double tmpd = json_number_value(v); \
|
||||
const type tmp = tmpd; \
|
||||
/* This checks if it's merely being truncated, and tolerates it */ \
|
||||
if (tmpd == tmp || ((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \
|
||||
tmpl->key = tmp; \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define GETSTR(key, skey) do { \
|
||||
if ((v = json_object_get(json, #key)) && json_is_string(v)) \
|
||||
@ -123,10 +183,14 @@ err:
|
||||
tmpl->skey = true; \
|
||||
} while(0)
|
||||
|
||||
static void my_flip(void *, size_t);
|
||||
|
||||
static
|
||||
const char *parse_txn(struct blktxn_t *txn, json_t *txnj) {
|
||||
const char *parse_txn(struct blktxn_t *txn, json_t *txnj, size_t my_tx_index) {
|
||||
json_t *vv;
|
||||
|
||||
blktxn_init(txn);
|
||||
|
||||
if (!((vv = json_object_get(txnj, "data")) && json_is_string(vv)))
|
||||
return "Missing or invalid type for transaction data";
|
||||
const char *hexdata = json_string_value(vv);
|
||||
@ -139,15 +203,90 @@ const char *parse_txn(struct blktxn_t *txn, json_t *txnj) {
|
||||
if ((vv = json_object_get(txnj, "hash")) && json_is_string(vv))
|
||||
{
|
||||
hexdata = json_string_value(vv);
|
||||
txn->hash = malloc(sizeof(*txn->hash));
|
||||
if (!my_hex2bin(*txn->hash, hexdata, sizeof(*txn->hash)))
|
||||
txn->hash_ = malloc(sizeof(*txn->hash_));
|
||||
if (!my_hex2bin(*txn->hash_, hexdata, sizeof(*txn->hash_)))
|
||||
{
|
||||
free(txn->hash);
|
||||
txn->hash = NULL;
|
||||
free(txn->hash_);
|
||||
txn->hash_ = NULL;
|
||||
}
|
||||
else
|
||||
my_flip(*txn->hash_, sizeof(*txn->hash_));
|
||||
}
|
||||
|
||||
if ((vv = json_object_get(txnj, "txid")) && json_is_string(vv)) {
|
||||
hexdata = json_string_value(vv);
|
||||
txn->txid = malloc(sizeof(*txn->txid));
|
||||
if (!my_hex2bin(*txn->txid, hexdata, sizeof(*txn->txid))) {
|
||||
return "Error decoding txid field";
|
||||
} else {
|
||||
my_flip(*txn->txid, sizeof(*txn->txid));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: dependcount/depends, fee, required, sigops
|
||||
txn->weight = -1;
|
||||
if ((vv = json_object_get(txnj, "weight")) && json_is_number(vv)) {
|
||||
const double f = json_number_value(txnj);
|
||||
const int32_t i32 = f;
|
||||
if (f == i32) {
|
||||
txn->weight = i32;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vv = json_object_get(txnj, "depends")) && json_is_array(vv)) {
|
||||
size_t depcount = json_array_size(vv);
|
||||
if (depcount <= LONG_MAX) {
|
||||
json_t *v;
|
||||
long i;
|
||||
double f;
|
||||
unsigned long ul;
|
||||
|
||||
txn->depends = malloc(sizeof(*txn->depends) * depcount);
|
||||
for (i = 0; i < depcount; ++i) {
|
||||
v = json_array_get(vv, i);
|
||||
if (!json_is_number(v)) {
|
||||
break;
|
||||
}
|
||||
f = json_number_value(v);
|
||||
ul = f;
|
||||
if (f != ul || ul >= my_tx_index) {
|
||||
// Out of range for storage type, fractional number, forward dependency, etc
|
||||
break;
|
||||
}
|
||||
txn->depends[i] = ul;
|
||||
}
|
||||
if (i != depcount) {
|
||||
// We failed somewhere
|
||||
free(txn->depends);
|
||||
txn->depends = NULL;
|
||||
} else {
|
||||
// Success, finish up with storing the count
|
||||
txn->dependscount = depcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((vv = json_object_get(txnj, "fee")) && json_is_number(vv)) {
|
||||
double f;
|
||||
int64_t i64;
|
||||
|
||||
f = json_number_value(vv);
|
||||
i64 = f;
|
||||
if (i64 == f && i64 >= 0) {
|
||||
txn->fee_ = i64;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vv = json_object_get(txnj, "required")) && json_is_true(vv)) {
|
||||
txn->required = true;
|
||||
}
|
||||
|
||||
if ((vv = json_object_get(txnj, "sigops")) && json_is_number(vv)) {
|
||||
const double f = json_number_value(vv);
|
||||
int16_t i16 = f;
|
||||
if (i16 == f && i16 >= 0) {
|
||||
txn->sigops_ = i16;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -168,7 +307,7 @@ void my_flip(void *data, size_t datasz) {
|
||||
|
||||
const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t time_rcvd) {
|
||||
if (tmpl->version)
|
||||
return false;
|
||||
return "Template already populated (combining not supported)";
|
||||
|
||||
json_t *v, *v2;
|
||||
const char *s;
|
||||
@ -183,39 +322,14 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t
|
||||
|
||||
GETHEX(bits, diffbits);
|
||||
my_flip(tmpl->diffbits, 4);
|
||||
GETNUM(curtime);
|
||||
GETNUM(height);
|
||||
GETNUM_T(curtime, blktime_t);
|
||||
GETNUM(height, blkheight_t);
|
||||
GETHEX(previousblockhash, prevblk);
|
||||
my_flip(tmpl->prevblk, 32);
|
||||
GETNUM_O(sigoplimit);
|
||||
GETNUM_O(sizelimit);
|
||||
GETNUM(version);
|
||||
|
||||
GETNUM_O2(cbvalue, coinbasevalue);
|
||||
|
||||
GETSTR(workid, workid);
|
||||
|
||||
GETNUM_O(expires);
|
||||
|
||||
GETSTR(longpollid, lp.id);
|
||||
GETSTR(longpolluri, lp.uri);
|
||||
GETBOOL(submitold, submitold, true);
|
||||
|
||||
v = json_object_get(json, "transactions");
|
||||
size_t txns = tmpl->txncount = json_array_size(v);
|
||||
tmpl->txns = calloc(txns, sizeof(*tmpl->txns));
|
||||
for (size_t i = 0; i < txns; ++i)
|
||||
if ((s = parse_txn(&tmpl->txns[i], json_array_get(v, i))))
|
||||
return s;
|
||||
|
||||
if ((v = json_object_get(json, "coinbasetxn")) && json_is_object(v))
|
||||
{
|
||||
tmpl->cbtxn = calloc(1, sizeof(*tmpl->cbtxn));
|
||||
if ((s = parse_txn(tmpl->cbtxn, v)))
|
||||
return s;
|
||||
}
|
||||
|
||||
// TODO: coinbaseaux
|
||||
GETNUM_O(sigoplimit, unsigned short);
|
||||
GETNUM_O(sizelimit, unsigned long);
|
||||
GETNUM_O(weightlimit, int64_t);
|
||||
GETNUM(version, uint32_t);
|
||||
|
||||
if ((v = json_object_get(json, "mutable")) && json_is_array(v))
|
||||
{
|
||||
@ -228,84 +342,236 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpl->version > 2 || (tmpl->version == 2 && !tmpl->height))
|
||||
if ((tmpl->version & 0xe0000000) == 0x20000000 && (v = json_object_get(json, "vbavailable")) && json_is_object(v) && (v = json_object_get(json, "rules")) && json_is_array(v)) {
|
||||
// calloc so that a failure doesn't result in freeing a random pointer
|
||||
size_t n = json_array_size(v);
|
||||
tmpl->rules = calloc(n + 1, sizeof(*tmpl->rules));
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
v2 = json_array_get(v, i);
|
||||
if (!json_is_string(v2)) {
|
||||
return "Non-String data in template rules list";
|
||||
}
|
||||
s = json_string_value(v2);
|
||||
if (s[0] == '!') {
|
||||
++s;
|
||||
if (!blkmk_supports_rule(s)) {
|
||||
return "Unsupported rule strictly required by template";
|
||||
}
|
||||
} else {
|
||||
if (!blkmk_supports_rule(s)) {
|
||||
tmpl->unsupported_rule = true;
|
||||
}
|
||||
}
|
||||
tmpl->rules[i] = strdup(s);
|
||||
if (!tmpl->rules[i]) {
|
||||
return "Memory allocation error parsing rules";
|
||||
}
|
||||
if (!strcmp(s, "segwit")) {
|
||||
tmpl->_bip141_sigops = true;
|
||||
}
|
||||
}
|
||||
|
||||
v = json_object_get(json, "vbavailable");
|
||||
n = json_object_size(v);
|
||||
tmpl->vbavailable = calloc(n + 1, sizeof(*tmpl->vbavailable));
|
||||
struct blktmpl_vbassoc **cur_vbassoc = tmpl->vbavailable;
|
||||
for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++cur_vbassoc) {
|
||||
v2 = json_object_iter_value(iter);
|
||||
if (!json_is_number(v2)) {
|
||||
return "Invalid type for vbavailable bit";
|
||||
}
|
||||
double bitnum = json_number_value(v2);
|
||||
if (bitnum < 0 || bitnum > 28 || (unsigned)bitnum != bitnum) {
|
||||
return "Invalid bit number in vbavailable";
|
||||
}
|
||||
*cur_vbassoc = malloc(sizeof(**cur_vbassoc));
|
||||
if (!*cur_vbassoc) {
|
||||
return "Memory allocation error for struct blktmpl_vbassoc";
|
||||
}
|
||||
**cur_vbassoc = (struct blktmpl_vbassoc){
|
||||
.name = strdup(json_object_iter_key(iter)),
|
||||
.bitnum = bitnum,
|
||||
};
|
||||
if (!(*cur_vbassoc)->name) {
|
||||
return "Memory allocation error for vbavailable name";
|
||||
}
|
||||
}
|
||||
|
||||
v = json_object_get(json, "vbrequired");
|
||||
if (v && json_is_number(v)) {
|
||||
double tmpd = json_number_value(v);
|
||||
tmpl->vbrequired = tmpd;
|
||||
if (tmpl->vbrequired != tmpd) {
|
||||
return "Unparsable vbrequired";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (tmpl->version > BLKMAKER_MAX_PRERULES_BLOCK_VERSION || (tmpl->version >= 2 && !tmpl->height))
|
||||
{
|
||||
if (tmpl->mutations & BMM_VERDROP)
|
||||
tmpl->version = tmpl->height ? 2 : 1;
|
||||
tmpl->version = tmpl->height ? BLKMAKER_MAX_PRERULES_BLOCK_VERSION : 1;
|
||||
else
|
||||
if (!(tmpl->mutations & BMM_VERFORCE))
|
||||
return "Unrecognized block version, and not allowed to reduce or force it";
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "coinbasevalue")) && json_is_number(v)) {
|
||||
const double tmpd = json_number_value(v);
|
||||
const uint64_t tmp = tmpd;
|
||||
if (tmpd == tmp) {
|
||||
tmpl->has_cbvalue = true;
|
||||
tmpl->cbvalue = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
GETSTR(workid, workid);
|
||||
|
||||
GETNUM_OT(expires, int16_t);
|
||||
GETNUM_OT(maxtime, blktime_t);
|
||||
GETNUM_OT(maxtimeoff, blktime_diff_t);
|
||||
GETNUM_OT(mintime, blktime_t);
|
||||
GETNUM_OT(mintimeoff, blktime_diff_t);
|
||||
|
||||
GETSTR(longpollid, lp.id);
|
||||
GETSTR(longpolluri, lp.uri);
|
||||
GETBOOL(submitold, submitold, true);
|
||||
|
||||
v = json_object_get(json, "transactions");
|
||||
size_t txns = tmpl->txncount = json_array_size(v);
|
||||
tmpl->txns = calloc(txns, sizeof(*tmpl->txns));
|
||||
tmpl->txns_datasz = 0;
|
||||
tmpl->txns_sigops = 0;
|
||||
tmpl->txns_weight = 0;
|
||||
for (size_t i = 0; i < txns; ++i)
|
||||
{
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
if ((s = parse_txn(txn, json_array_get(v, i), i + 1))) {
|
||||
return s;
|
||||
}
|
||||
tmpl->txns_datasz += txn->datasz;
|
||||
if (tmpl->txns_sigops == -1) {
|
||||
; // Impossible to tally the unknown
|
||||
} else if (txn->sigops_ == -1) {
|
||||
tmpl->txns_sigops = -1;
|
||||
} else {
|
||||
tmpl->txns_sigops += txn->sigops_;
|
||||
}
|
||||
if (tmpl->txns_weight == -1) {
|
||||
; // Impossible to tally the unknown
|
||||
} else if (txn->weight == -1) {
|
||||
tmpl->txns_weight = -1;
|
||||
} else {
|
||||
tmpl->txns_weight += txn->weight;
|
||||
}
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "coinbasetxn")) && json_is_object(v))
|
||||
{
|
||||
tmpl->cbtxn = calloc(1, sizeof(*tmpl->cbtxn));
|
||||
if ((s = parse_txn(tmpl->cbtxn, v, 0)))
|
||||
return s;
|
||||
} else if (!tmpl->has_cbvalue) {
|
||||
return "Missing either coinbasetxn or coinbasevalue";
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "coinbaseaux")) && json_is_object(v))
|
||||
{
|
||||
tmpl->aux_count = json_object_size(v);
|
||||
tmpl->auxs = calloc(tmpl->aux_count, sizeof(*tmpl->auxs));
|
||||
unsigned i = 0;
|
||||
for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++i)
|
||||
{
|
||||
v2 = json_object_iter_value(iter);
|
||||
s = json_string_value(v2);
|
||||
if (!s)
|
||||
continue;
|
||||
size_t sz = strlen(s) / 2;
|
||||
tmpl->auxs[i] = (struct blkaux_t){
|
||||
.auxname = strdup(json_object_iter_key(iter)),
|
||||
.data = malloc(sz),
|
||||
.datasz = sz,
|
||||
};
|
||||
if (!my_hex2bin(tmpl->auxs[i].data, s, sz)) {
|
||||
return "Error decoding 'coinbaseaux' data";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "target")) && json_is_string(v))
|
||||
{
|
||||
tmpl->target = malloc(sizeof(*tmpl->target));
|
||||
if (!my_hex2bin(tmpl->target, json_string_value(v), sizeof(*tmpl->target)))
|
||||
return "Error decoding 'target'";
|
||||
}
|
||||
|
||||
tmpl->_time_rcvd = time_rcvd;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
char varintEncode(unsigned char *out, uint64_t n) {
|
||||
if (n < 0xfd)
|
||||
json_t *blktmpl_propose_jansson(blktemplate_t * const tmpl, const uint32_t caps, const bool foreign) {
|
||||
json_t *jreq = blktmpl_request_jansson(caps, NULL), *ja = NULL, *jparams;
|
||||
if (!(jreq && json_is_object(jreq)))
|
||||
goto err;
|
||||
|
||||
jparams = json_array_get(json_object_get(jreq, "params"), 0);
|
||||
if (!(jparams && json_is_object(jparams)))
|
||||
goto err;
|
||||
|
||||
if (!(ja = json_string("proposal")))
|
||||
goto err;
|
||||
if (json_object_set_new(jparams, "mode", ja))
|
||||
goto err;
|
||||
|
||||
if (tmpl->workid && !foreign)
|
||||
{
|
||||
out[0] = n;
|
||||
return 1;
|
||||
if (!(ja = json_string(tmpl->workid)))
|
||||
goto err;
|
||||
if (json_object_set_new(jparams, "workid", ja))
|
||||
goto err;
|
||||
}
|
||||
char L;
|
||||
if (n <= 0xffff)
|
||||
{
|
||||
out[0] = '\xfd';
|
||||
L = 3;
|
||||
}
|
||||
else
|
||||
if (n <= 0xffffffff)
|
||||
{
|
||||
out[0] = '\xfe';
|
||||
L = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[0] = '\xff';
|
||||
L = 9;
|
||||
}
|
||||
for (unsigned char i = 1; i < L; ++i)
|
||||
out[i] = (n >> ((i - 1) * 8)) % 256;
|
||||
return L;
|
||||
ja = NULL;
|
||||
|
||||
unsigned int dataid = (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET) ? 1 : 0);
|
||||
|
||||
uint8_t sdata[0x4c];
|
||||
if (!blkmk_sample_data_(tmpl, sdata, dataid))
|
||||
goto err;
|
||||
char *blkhex = blkmk_assemble_submission2_(tmpl, sdata, NULL, 0, dataid, 0, foreign);
|
||||
if (!blkhex)
|
||||
goto err;
|
||||
if (!(ja = json_string(blkhex)))
|
||||
goto err;
|
||||
free(blkhex);
|
||||
if (json_object_set_new(jparams, "data", ja))
|
||||
goto err;
|
||||
|
||||
return jreq;
|
||||
|
||||
err:
|
||||
if (jreq) json_decref(jreq);
|
||||
if (ja) json_decref(ja);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define my_bin2hex _blkmk_bin2hex
|
||||
|
||||
json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) {
|
||||
unsigned char blk[80 + 8 + 1000000];
|
||||
memcpy(blk, data, 76);
|
||||
*(uint32_t*)(&blk[76]) = htonl(nonce);
|
||||
size_t offs = 80;
|
||||
|
||||
if (!(tmpl->mutations & BMAb_TRUNCATE && !dataid))
|
||||
{
|
||||
offs += varintEncode(&blk[offs], 1 + tmpl->txncount);
|
||||
|
||||
if (!_blkmk_extranonce(tmpl, &blk[offs], dataid, &offs))
|
||||
return NULL;
|
||||
|
||||
if (!(tmpl->mutations & BMAb_COINBASE))
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i)
|
||||
{
|
||||
memcpy(&blk[offs], tmpl->txns[i].data, tmpl->txns[i].datasz);
|
||||
offs += tmpl->txns[i].datasz;
|
||||
}
|
||||
}
|
||||
|
||||
char blkhex[(offs * 2) + 1];
|
||||
my_bin2hex(blkhex, blk, offs);
|
||||
static
|
||||
json_t *_blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, const void * const extranonce, const size_t extranoncesz, unsigned int dataid, blknonce_t nonce, bool foreign) {
|
||||
char *blkhex = blkmk_assemble_submission2_(tmpl, data, extranonce, extranoncesz, dataid, nonce, foreign);
|
||||
if (!blkhex)
|
||||
return NULL;
|
||||
|
||||
json_t *rv = json_array(), *ja, *jb;
|
||||
jb = NULL;
|
||||
if (!(ja = json_string(blkhex)))
|
||||
ja = json_string(blkhex);
|
||||
free(blkhex);
|
||||
if (!ja)
|
||||
goto err;
|
||||
if (json_array_append_new(rv, ja))
|
||||
goto err;
|
||||
if (!(ja = json_object()))
|
||||
goto err;
|
||||
if (tmpl->workid)
|
||||
if (tmpl->workid && !foreign)
|
||||
{
|
||||
if (!(jb = json_string(tmpl->workid)))
|
||||
goto err;
|
||||
@ -338,3 +604,15 @@ err:
|
||||
if (jb) json_decref(jb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) {
|
||||
return _blkmk_submit_jansson(tmpl, data, NULL, 0, dataid, nonce, false);
|
||||
}
|
||||
|
||||
json_t *blkmk_submit_foreign_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) {
|
||||
return _blkmk_submit_jansson(tmpl, data, NULL, 0, dataid, nonce, true);
|
||||
}
|
||||
|
||||
json_t *blkmk_submitm_jansson(blktemplate_t * const tmpl, const unsigned char *data, const void * const extranonce, const size_t extranoncesz, const blknonce_t nonce, const bool foreign) {
|
||||
return _blkmk_submit_jansson(tmpl, data, extranonce, extranoncesz, 0, nonce, foreign);
|
||||
}
|
||||
|
||||
@ -5,8 +5,20 @@
|
||||
|
||||
#include <blktemplate.h>
|
||||
|
||||
extern json_t *blktmpl_request_jansson(gbt_capabilities_t extracaps, const char *lpid);
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern json_t *blktmpl_request_jansson(uint32_t extracaps, const char *lpid);
|
||||
extern json_t *blktmpl_request_jansson2(uint32_t extracaps, const char *lpid, const char * const *rulelist);
|
||||
extern const char *blktmpl_add_jansson(blktemplate_t *, const json_t *, time_t time_rcvd);
|
||||
extern json_t *blktmpl_propose_jansson(blktemplate_t *, uint32_t caps, bool foreign);
|
||||
extern json_t *blkmk_submit_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t);
|
||||
extern json_t *blkmk_submit_foreign_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t);
|
||||
extern json_t *blkmk_submitm_jansson(blktemplate_t *, const unsigned char *data, const void *extranonce, size_t extranoncesz, blknonce_t, bool foreign);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,9 +1,16 @@
|
||||
#define _BSD_SOURCE
|
||||
/*
|
||||
* Copyright 2012-2016 Luke Dashjr
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the standard MIT license. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <blktemplate.h>
|
||||
|
||||
@ -20,7 +27,7 @@ static const char *capnames[] = {
|
||||
|
||||
"coinbase/append",
|
||||
"coinbase",
|
||||
"generate",
|
||||
"generation",
|
||||
"time/increment",
|
||||
"time/decrement",
|
||||
"transactions/add",
|
||||
@ -43,13 +50,35 @@ const char *blktmpl_capabilityname(gbt_capabilities_t caps) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gbt_capabilities_t blktmpl_getcapability(const char *n) {
|
||||
uint32_t blktmpl_getcapability(const char *n) {
|
||||
for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i)
|
||||
if (capnames[i] && !strcasecmp(n, capnames[i]))
|
||||
return 1 << i;
|
||||
return ((uint32_t)1) << i;
|
||||
if (!strcasecmp(n, "time")) {
|
||||
// multi-capability
|
||||
return BMM_TIMEINC | BMM_TIMEDEC;
|
||||
}
|
||||
if (!strcasecmp(n, "transactions"))
|
||||
return BMM_TXNADD; // Odd one as it's overloaded w/"transactions/add" per spec
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blktxn_init(struct blktxn_t * const txn) {
|
||||
txn->data = NULL;
|
||||
txn->datasz = 0;
|
||||
txn->hash = NULL;
|
||||
txn->hash_ = NULL;
|
||||
txn->txid = NULL;
|
||||
|
||||
txn->dependscount = -1;
|
||||
txn->depends = NULL;
|
||||
|
||||
txn->fee_ = -1;
|
||||
txn->required = false;
|
||||
txn->sigops_ = -1;
|
||||
txn->weight = -1;
|
||||
}
|
||||
|
||||
blktemplate_t *blktmpl_create() {
|
||||
blktemplate_t *tmpl;
|
||||
tmpl = calloc(1, sizeof(*tmpl));
|
||||
@ -58,22 +87,22 @@ blktemplate_t *blktmpl_create() {
|
||||
|
||||
tmpl->sigoplimit = USHRT_MAX;
|
||||
tmpl->sizelimit = ULONG_MAX;
|
||||
tmpl->weightlimit = INT64_MAX;
|
||||
|
||||
tmpl->maxtime = 0xffffffff;
|
||||
tmpl->maxtimeoff = 0x7fff;
|
||||
tmpl->mintimeoff = -0x7fff;
|
||||
tmpl->maxnonce = 0xffffffff;
|
||||
tmpl->expires = 0x7fff;
|
||||
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
gbt_capabilities_t blktmpl_addcaps(const blktemplate_t *tmpl) {
|
||||
uint32_t blktmpl_addcaps(const blktemplate_t *tmpl) {
|
||||
// TODO: make this a lot more flexible for merging
|
||||
// For now, it's a simple "filled" vs "not filled"
|
||||
if (tmpl->version)
|
||||
return 0;
|
||||
return GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND;
|
||||
return GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND | BMM_VERFORCE | BMM_VERDROP | BMAb_COINBASE | BMAb_TRUNCATE;
|
||||
}
|
||||
|
||||
const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *tmpl) {
|
||||
@ -86,27 +115,52 @@ bool blktmpl_get_submitold(blktemplate_t *tmpl) {
|
||||
return tmpl->submitold;
|
||||
}
|
||||
|
||||
static
|
||||
void blktxn_free(struct blktxn_t *bt) {
|
||||
void blktxn_clean(struct blktxn_t * const bt) {
|
||||
free(bt->data);
|
||||
free(bt->hash);
|
||||
free(bt->hash_);
|
||||
free(bt->depends);
|
||||
free(bt->txid);
|
||||
}
|
||||
|
||||
static
|
||||
void blkaux_clean(struct blkaux_t * const aux) {
|
||||
free(aux->auxname);
|
||||
free(aux->data);
|
||||
}
|
||||
|
||||
void blktmpl_free(blktemplate_t *tmpl) {
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i)
|
||||
blktxn_free(&tmpl->txns[i]);
|
||||
blktxn_clean(&tmpl->txns[i]);
|
||||
free(tmpl->txns);
|
||||
if (tmpl->cbtxn)
|
||||
{
|
||||
blktxn_free(tmpl->cbtxn);
|
||||
blktxn_clean(tmpl->cbtxn);
|
||||
free(tmpl->cbtxn);
|
||||
}
|
||||
// TODO: maybe free auxnames[0..n]? auxdata too
|
||||
free(tmpl->auxnames);
|
||||
free(tmpl->auxdata);
|
||||
free(tmpl->_mrklbranch);
|
||||
free(tmpl->_witnessmrklroot);
|
||||
for (unsigned i = 0; i < tmpl->aux_count; ++i)
|
||||
blkaux_clean(&tmpl->auxs[i]);
|
||||
free(tmpl->auxs);
|
||||
free(tmpl->workid);
|
||||
free(tmpl->target);
|
||||
free(tmpl->lp.id);
|
||||
free(tmpl->lp.uri);
|
||||
|
||||
if (tmpl->rules) {
|
||||
for (char **currule = tmpl->rules; *currule; ++currule) {
|
||||
free(*currule);
|
||||
}
|
||||
free(tmpl->rules);
|
||||
}
|
||||
if (tmpl->vbavailable) {
|
||||
for (struct blktmpl_vbassoc **curvb = tmpl->vbavailable; *curvb; ++curvb) {
|
||||
free((*curvb)->name);
|
||||
free(*curvb);
|
||||
}
|
||||
free(tmpl->vbavailable);
|
||||
}
|
||||
|
||||
free(tmpl);
|
||||
}
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright 2012-2016 Luke Dashjr
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the standard MIT license. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef BLKTEMPLATE_H
|
||||
#define BLKTEMPLATE_H
|
||||
|
||||
@ -5,6 +12,10 @@
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint32_t blkheight_t;
|
||||
typedef uint32_t libblkmaker_hash_t[8];
|
||||
typedef libblkmaker_hash_t blkhash_t;
|
||||
@ -13,17 +24,32 @@ typedef uint32_t blktime_t;
|
||||
typedef int16_t blktime_diff_t;
|
||||
typedef uint32_t blknonce_t;
|
||||
|
||||
#define libblkmaker_blkheader_size (80)
|
||||
#define libblkmaker_coinbase_size_minimum (4)
|
||||
#define libblkmaker_coinbase_size_limit (100)
|
||||
|
||||
struct blktxn_t {
|
||||
unsigned char *data;
|
||||
size_t datasz;
|
||||
// NOTE: The byte order of hash is backward; use hash_ instead
|
||||
txnhash_t *hash;
|
||||
|
||||
signed long dependcount;
|
||||
signed long dependscount;
|
||||
unsigned long *depends;
|
||||
|
||||
uint64_t fee;
|
||||
int64_t fee_;
|
||||
bool required;
|
||||
int16_t sigops;
|
||||
int16_t sigops_;
|
||||
int32_t weight;
|
||||
|
||||
txnhash_t *hash_;
|
||||
txnhash_t *txid;
|
||||
};
|
||||
|
||||
struct blkaux_t {
|
||||
char *auxname;
|
||||
unsigned char *data;
|
||||
uint8_t datasz;
|
||||
};
|
||||
|
||||
// BIP 23: Long Polling
|
||||
@ -65,11 +91,18 @@ typedef enum {
|
||||
|
||||
extern const char *blktmpl_capabilityname(gbt_capabilities_t);
|
||||
#define BLKTMPL_LONGEST_CAPABILITY_NAME (16)
|
||||
extern gbt_capabilities_t blktmpl_getcapability(const char *);
|
||||
// NOTE: blktmpl_getcapability("time") yields a combination of gbt_capabilities_t
|
||||
extern uint32_t blktmpl_getcapability(const char *);
|
||||
|
||||
|
||||
typedef gbt_capabilities_t blkmutations_t;
|
||||
|
||||
struct blktmpl_vbassoc {
|
||||
char *name;
|
||||
uint8_t bitnum;
|
||||
};
|
||||
|
||||
// WARNING: Do not allocate this (ABI is not guaranteed to remain fixed-size)
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
unsigned char diffbits[4];
|
||||
@ -86,9 +119,6 @@ typedef struct {
|
||||
|
||||
time_t _time_rcvd;
|
||||
blktime_t curtime;
|
||||
char auxcount;
|
||||
char **auxnames;
|
||||
unsigned char **auxdata;
|
||||
|
||||
char *workid;
|
||||
|
||||
@ -98,26 +128,51 @@ typedef struct {
|
||||
|
||||
// BIP 23: Basic Pool Extensions
|
||||
int16_t expires;
|
||||
blkhash_t target;
|
||||
blkhash_t *target;
|
||||
|
||||
// BIP 23: Mutations
|
||||
blkmutations_t mutations;
|
||||
uint32_t mutations;
|
||||
blktime_t maxtime;
|
||||
blktime_diff_t maxtimeoff;
|
||||
blktime_t mintime;
|
||||
blktime_diff_t mintimeoff;
|
||||
blknonce_t minnonce;
|
||||
blknonce_t maxnonce;
|
||||
|
||||
// TEMPORARY HACK
|
||||
libblkmaker_hash_t _mrklroot;
|
||||
libblkmaker_hash_t *_mrklbranch;
|
||||
int _mrklbranchcount;
|
||||
unsigned int next_dataid;
|
||||
|
||||
unsigned aux_count;
|
||||
struct blkaux_t *auxs;
|
||||
|
||||
unsigned long txns_datasz;
|
||||
signed long txns_sigops;
|
||||
|
||||
char **rules;
|
||||
bool unsupported_rule;
|
||||
struct blktmpl_vbassoc **vbavailable;
|
||||
uint32_t vbrequired;
|
||||
|
||||
bool _bip141_sigops;
|
||||
bool _calculated_witness;
|
||||
libblkmaker_hash_t *_witnessmrklroot;
|
||||
int64_t weightlimit;
|
||||
int64_t txns_weight;
|
||||
|
||||
bool has_cbvalue;
|
||||
} blktemplate_t;
|
||||
|
||||
extern void blktxn_init(struct blktxn_t *);
|
||||
extern void blktxn_clean(struct blktxn_t *);
|
||||
|
||||
extern blktemplate_t *blktmpl_create();
|
||||
extern gbt_capabilities_t blktmpl_addcaps(const blktemplate_t *);
|
||||
extern uint32_t blktmpl_addcaps(const blktemplate_t *);
|
||||
extern const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *);
|
||||
extern bool blktmpl_get_submitold(blktemplate_t *tmpl);
|
||||
extern void blktmpl_free(blktemplate_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
49
configure.ac
49
configure.ac
@ -1,25 +1,68 @@
|
||||
dnl * Copyright 2012-2014 Luke Dashjr
|
||||
dnl *
|
||||
dnl * This program is free software; you can redistribute it and/or modify it
|
||||
dnl * under the terms of the standard MIT license. See COPYING for more details.
|
||||
|
||||
AC_INIT(
|
||||
[libblkmaker],
|
||||
[0.1],
|
||||
[0.6.0],
|
||||
[luke_libblkmaker@dashjr.org],
|
||||
[libblkmaker],
|
||||
[http://gitorious.org/bitcoin/libblkmaker])
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
AC_PREREQ([2.59])
|
||||
AM_INIT_AUTOMAKE([1.10 -Wall dist-bzip2])
|
||||
AM_INIT_AUTOMAKE([1.11 -Wall dist-xz foreign])
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
AC_PROG_CC_C99
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
LT_INIT([disable-static])
|
||||
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST([LIBBLKMAKER_SO_VERSION], [3:1:3])
|
||||
AC_SUBST([LIBBLKMAKER_SO_VERSION], [8:0:0])
|
||||
AC_SUBST([LIBBLKMAKER_API_VERSION], [0.1])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
libblkmaker_jansson-${LIBBLKMAKER_API_VERSION}.pc:libblkmaker_jansson.pc.in
|
||||
])
|
||||
|
||||
PKG_CHECK_MODULES([JANSSON],[jansson],[
|
||||
true
|
||||
],[
|
||||
AC_MSG_CHECKING([for jansson in system-default locations])
|
||||
LIBS="$LIBS -ljansson"
|
||||
AC_TRY_LINK([
|
||||
#include <jansson.h>
|
||||
],[
|
||||
json_object();
|
||||
],[
|
||||
AC_MSG_RESULT([found])
|
||||
JANSSON_LIBS=-ljansson
|
||||
],[
|
||||
AC_MSG_RESULT([not found])
|
||||
AC_MSG_ERROR([Could not find jansson library])
|
||||
])
|
||||
LIBS="${save_LIBS}"
|
||||
])
|
||||
AC_SUBST(JANSSON_CFLAGS)
|
||||
AC_SUBST(JANSSON_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES([libbase58],[libbase58])
|
||||
|
||||
AC_CHECK_LIB([ws2_32], [strchr])
|
||||
|
||||
dnl libgcrypt necessary to build tests and example
|
||||
dnl check for libgcrypt:
|
||||
m4_ifdef([AM_PATH_LIBGCRYPT], [
|
||||
AM_PATH_LIBGCRYPT([],
|
||||
[
|
||||
have_libgcrypt=yes
|
||||
],[
|
||||
have_libgcrypt=no
|
||||
])
|
||||
],[
|
||||
m4_warn([syntax], [AM_PATH_LIBGCRYPT missing; example and tests will not be available])
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_LIBGCRYPT], [test x$have_libgcrypt = xyes])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
25
example.c
25
example.c
@ -1,10 +1,22 @@
|
||||
/*
|
||||
* Copyright 2012 Luke Dashjr
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the standard MIT license. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <libbase58.h>
|
||||
|
||||
#include <blkmaker.h>
|
||||
#include <blkmaker_jansson.h>
|
||||
@ -16,20 +28,23 @@ void testb58() {
|
||||
int rv;
|
||||
const char *iaddr = "11Baf75Ferj6A7AoN565gCQj9kGWbDMHfN9";
|
||||
const char *addr = &iaddr[1];
|
||||
const size_t addrlen = strlen(addr);
|
||||
size_t actuallen;
|
||||
char bufx[26] = {'\xff'};
|
||||
char *buf = &bufx[1];
|
||||
if (!_blkmk_b58tobin(buf, 25, addr, 0))
|
||||
actuallen = 25;
|
||||
if (!b58tobin(buf, &actuallen, addr, addrlen))
|
||||
exit(1);
|
||||
if (bufx[0] != '\xff')
|
||||
exit(2);
|
||||
char cbuf[51];
|
||||
_blkmk_bin2hex(cbuf, buf, 25);
|
||||
printf("Base58 raw data: %s\n", cbuf);
|
||||
assert((rv = _blkmk_b58check(buf, 25, addr)) == 0);
|
||||
assert((rv = b58check(buf, 25, addr, addrlen)) == 0);
|
||||
printf("Base58 check: %d\n", rv);
|
||||
assert((rv = _blkmk_b58check(buf, 25, &addr[1])) < 0);
|
||||
assert((rv = b58check(buf, 25, &addr[1], addrlen)) < 0);
|
||||
printf("Base58 check (invalid/ unpadded): %d\n", rv);
|
||||
assert((rv = _blkmk_b58check(buf, 25, iaddr)) < 0);
|
||||
assert((rv = b58check(buf, 25, iaddr, addrlen + 1)) < 0);
|
||||
printf("Base58 check (invalid/extra padded): %d\n", rv);
|
||||
}
|
||||
|
||||
@ -52,6 +67,7 @@ int main(int argc, char**argv) {
|
||||
json_error_t jsone;
|
||||
const char *err;
|
||||
|
||||
b58_sha256_impl = my_sha256;
|
||||
blkmk_sha256_impl = my_sha256;
|
||||
|
||||
testb58();
|
||||
@ -115,4 +131,5 @@ int main(int argc, char**argv) {
|
||||
send_json(req);
|
||||
}
|
||||
blktmpl_free(tmpl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
7
hex.c
7
hex.c
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright 2012 Luke Dashjr
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the standard MIT license. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -7,5 +7,7 @@ Name: @PACKAGE_NAME@_jansson
|
||||
Description: Bitcoin block maker library.
|
||||
Version: @PACKAGE_VERSION@
|
||||
URL: @PACKAGE_URL@
|
||||
Libs: -L${libdir} -lblkmaker-@LIBBLKMAKER_API_VERSION@ -lblkmaker_jansson-@LIBBLKMAKER_API_VERSION@
|
||||
Libs: -L${libdir} -lblkmaker_jansson-@LIBBLKMAKER_API_VERSION@ -lblkmaker-@LIBBLKMAKER_API_VERSION@
|
||||
Cflags: -I${includedir}/libblkmaker-@LIBBLKMAKER_API_VERSION@
|
||||
Requires: jansson
|
||||
Requires.private: libbase58
|
||||
|
||||
50
private.h
50
private.h
@ -4,15 +4,59 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <blktemplate.h>
|
||||
|
||||
// blkmaker.c
|
||||
extern bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz);
|
||||
extern bool blkmk_sample_data_(blktemplate_t *, uint8_t *, unsigned int dataid);
|
||||
extern char *blkmk_assemble_submission2_(blktemplate_t *, const unsigned char *data, const void *extranonce, size_t extranoncesz, unsigned int dataid, blknonce_t nonce, bool foreign);
|
||||
|
||||
// hex.c
|
||||
extern void _blkmk_bin2hex(char *out, const void *data, size_t datasz);
|
||||
extern bool _blkmk_hex2bin(void *o, const char *x, size_t len);
|
||||
|
||||
// base58.c
|
||||
extern bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz);
|
||||
extern int _blkmk_b58check(void *bin, size_t binsz, const char *b58);
|
||||
// inline
|
||||
|
||||
// NOTE: This must return 0 for 0
|
||||
static inline
|
||||
int blkmk_flsl(unsigned long n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; n; ++i)
|
||||
n >>= 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline
|
||||
uint16_t upk_u16le(const void * const bufp, const int offset)
|
||||
{
|
||||
const uint8_t * const buf = bufp;
|
||||
return (((uint16_t)buf[offset+0]) << 0)
|
||||
| (((uint16_t)buf[offset+1]) << 8);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint32_t upk_u32le(const void * const bufp, const int offset)
|
||||
{
|
||||
const uint8_t * const buf = bufp;
|
||||
return (((uint32_t)buf[offset+0]) << 0)
|
||||
| (((uint32_t)buf[offset+1]) << 8)
|
||||
| (((uint32_t)buf[offset+2]) << 0x10)
|
||||
| (((uint32_t)buf[offset+3]) << 0x18);
|
||||
}
|
||||
|
||||
static inline
|
||||
uint64_t upk_u64le(const void * const bufp, const int offset)
|
||||
{
|
||||
const uint8_t * const buf = bufp;
|
||||
return (((uint64_t)buf[offset+0]) << 0)
|
||||
| (((uint64_t)buf[offset+1]) << 8)
|
||||
| (((uint64_t)buf[offset+2]) << 0x10)
|
||||
| (((uint64_t)buf[offset+3]) << 0x18)
|
||||
| (((uint64_t)buf[offset+4]) << 0x20)
|
||||
| (((uint64_t)buf[offset+5]) << 0x28)
|
||||
| (((uint64_t)buf[offset+6]) << 0x30)
|
||||
| (((uint64_t)buf[offset+7]) << 0x38);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
3
test.sh
Executable file
3
test.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
# To avoid exit codes other than 0 or 1
|
||||
./test || exit 1
|
||||
@ -1,3 +1,9 @@
|
||||
/*
|
||||
* Written by Luke Dashjr in 2012
|
||||
*
|
||||
* This data is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver.
|
||||
*/
|
||||
|
||||
const char *blkmaker_test_input =
|
||||
"{"
|
||||
"\"result\": {"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user