From 55fc3a1f44abcf774b170bcbb3435789c272d5e2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 5 Mar 2016 12:17:24 -0300 Subject: [PATCH] losslec codecness debugging --- crypto777/OS_portable.c | 37 ++ crypto777/OS_portable.h | 1 + deprecated/obsolete.h | 46 +- iguana/Readme.md | 193 +++++++ iguana/SuperNET.c | 3 +- iguana/exchanges/bitcoin.c | 764 +------------------------- iguana/exchanges/bitcoin.h | 23 +- iguana/iguana.sources | 2 +- iguana/iguana777.c | 7 +- iguana/iguana777.h | 57 +- iguana/iguana_blocks.c | 2 +- iguana/iguana_init.c | 19 +- iguana/iguana_json.c | 6 +- iguana/iguana_msg.c | 4 +- iguana/iguana_pubkeys.c | 9 +- iguana/iguana_ramchain.c | 986 ++++++++++++++++++++++------------ iguana/iguana_recv.c | 83 +-- iguana/iguana_rpc.c | 144 ++--- iguana/iguana_scripts.c | 942 ++++++++++++++++++++++++++++++++ iguana/iguana_tx.c | 5 +- iguana/iguana_unspents.c | 320 +++++++++++ iguana/iguana_wallet.c | 44 ++ iguana/main.c | 29 +- iguana/peggy_tx.c | 2 +- iguana/ramchain_api.c | 143 ++--- includes/iguana_apideclares.h | 137 ++--- 26 files changed, 2652 insertions(+), 1356 deletions(-) create mode 100755 iguana/Readme.md create mode 100755 iguana/iguana_scripts.c create mode 100755 iguana/iguana_unspents.c diff --git a/crypto777/OS_portable.c b/crypto777/OS_portable.c index 5c3d879bc..14154fa83 100755 --- a/crypto777/OS_portable.c +++ b/crypto777/OS_portable.c @@ -109,6 +109,43 @@ int32_t OS_portable_removefile(char *fname) #else return(remove(fname)); #endif + return(-1); +} + +int32_t OS_portable_rmdir(char *dirname,int32_t diralso) +{ + char cmdstr[1024],tmp[512]; int32_t i; + strcpy(tmp,dirname); + OS_portable_path(tmp); +#ifdef _WIN32 + sprintf(cmdstr,"del %s\*.*",tmp); + if ( system(cmdstr) != 0 ) + printf("error deleting dir.(%s)\n",cmdstr); + else return(1); +#else + if ( diralso != 0 ) + { + sprintf(cmdstr,"rm -rf %s",tmp); + if ( system(cmdstr) != 0 ) + printf("error deleting dir.(%s)\n",cmdstr); + sprintf(cmdstr,"mkdir %s",tmp); + if ( system(cmdstr) != 0 ) + printf("error deleting dir.(%s)\n",cmdstr); + } + else + { + for (i=0; i<=16; i++) + { + if ( i < 16 ) + sprintf(cmdstr,"rm %s/%c*",tmp,i<10?'0'+i:'a'-10+i); + else sprintf(cmdstr,"rm %s/*",tmp); + if ( system(cmdstr) != 0 ) + printf("error deleting dir.(%s)\n",cmdstr); + } + } + return(0); +#endif + return(-1); } void *OS_portable_mapfile(char *fname,long *filesizep,int32_t enablewrite) diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index e7861dc15..dd18e29f9 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -358,6 +358,7 @@ bits256 bits256_from_compact(uint32_t c); bits256 bits256_conv(char *hexstr); int32_t btc_priv2pub(uint8_t pubkey[33],uint8_t privkey[32]); void calc_shares(unsigned char *shares,unsigned char *secret,int32_t size,int32_t width,int32_t M,int32_t N,unsigned char *sharenrs); +int32_t OS_portable_rmdir(char *dirname,int32_t diralso); extern char *Iguana_validcommands[]; extern bits256 GENESIS_PUBKEY,GENESIS_PRIVKEY; diff --git a/deprecated/obsolete.h b/deprecated/obsolete.h index d87be369c..bc842c567 100755 --- a/deprecated/obsolete.h +++ b/deprecated/obsolete.h @@ -13899,5 +13899,49 @@ len = 0; return(instantdex_sendcmd(myinfo,&ap->offer,newjson,"BTCoffer",GENESIS_PUBKEY,INSTANTDEX_HOPS,swap->deck,sizeof(swap->deck))); } }*/ - + /*ptr = (void *)bp->scriptsmap; + ind = unspentind << 1; + for (i=0; inumscriptsmaps; i++,ptr+=2) + { + if ( ind == ptr[0] ) + { + printf("bp.[%d] ind.%d offset.%d vs %ld\n",bp->hdrsi,ind,ptr[1],coin->scriptsfilesize); + if ( ptr[1] + sizeof(struct scriptdata) <= coin->scriptsfilesize ) + { + if ( memcmp((void *)((long)coin->scriptsptr + ptr[1] + sizeof(struct scriptdata)),spendscript,spendlen) == 0 ) + { + printf("matched against existing scriptsptr[%d] %d\n",ptr[1],spendlen); + return(ptr[1]); + } + printf("mismatch against existing scriptsptr[%d] %d\n",ptr[1],spendlen); + } + else + { + if ( (fp= fopen(coin->scriptsfname,"rb")) != 0 ) + { + fseek(fp,ptr[1] + sizeof(struct scriptdata),SEEK_SET); + for (i=0; ihdrsi,unspentind,i,ftell(fp),ptr[1],ptr[1]+sizeof(struct scriptdata)+spendlen,c,spendscript[i]); + for (; i #TL;DR# +> +> ```sudo apt-get update; sudo apt-get install libcurl4-gnutls-dev libssl-dev; git clone https://github.com/jl777/SuperNET; cd SuperNET; ./m_onetime m_unix; ./m_unix; agents/iguana``` +> +> The above one line gets SuperNET installed, built and launched for unix. +> +> After that ```./m_unix``` updates to latest. +> *Continue below at "Running".* + +**iguana is easy to build. Start by cloning (or downloading) this repository.** + +#DEPENDENCIES# +##for native (unix, osx)## +Just make sure you have the dev versions of openssl and curl installed: + +```sudo apt-get install libcurl4-gnutls-dev libssl-dev``` + +##For native (win32, win64)## +TOOL_DIR := /usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/bin +MINGW := i586-mingw32 +The above two definitions need to be changed to match the mingw install on your system. m_win32 and m_win64 just invokes the makefile in mingw32 and mingw64 + +##For chrome app## +You need to make sure the nacl sdk is properly installed and you are able to build the examples. +Now you will need to get the external libs, which can be built from scratch using naclports or there use the reference builds of libssl.a, libcrypto.a, libcurl.a and libz.a in the SuperNET/crypto777/pnacl_libs. You can just copy those over into $(NACL_SDK_ROOT)//lib/pnacl. + + +#ONETIME# +Now you are ready to build. +I try to make the build process as simple as possible, so there are no `autoconf`, `autoreconf`, `configure`, `cmake`, `make`, to get properly installed and running and run, etc. You do need a C compiler, like gcc. + +The **first time** you need to build libcrypto777.a and to do that you need to run: + +For unix: ```./m_onetime m_unix``` + +For osx: ```./m_onetime m_osx``` + +For win32: ```./m_onetime m_win32``` + +For win64: ```./m_onetime m_win64``` + +#(RE)BUILD + +Once libcrypto777.a is built, you can build the agents. + +For pnacl: ```cd crypto777; make clean; make; cd ../iguana; make clean; make``` + +For unix: ```./m_unix``` + +For osx: ```./m_osx``` + +For win32: ```./m_win32``` + +For win64: ```./m_win64``` + + +The m_(OS) is a standard I follow and should be self explanatory. within each is usually just a few lines, ie compile all the .c files and link with the standard libs. + +To build just iguana, you can ```cd``` into SuperNET/iguana and do ```./m_unix``` (or ```./m_osx```, ...). + +```./m_clean``` will remove the files created from the building + +#RUNNING# + +The native versions are command line applications: agents/iguana {JSON} +The chrome app pexe requires that the chrome is launched with a command line parameter (tools/chrome.localhost) and then browse to *http://127.0.0.1:7777* to see the pexe + +#SUPERUGLYGUI# + +Once iguana is running, you can see the superuglyGUI at *http://127.0.0.1:7778/?method* +by submitting API calls using the forms, you will see it go to some specific URL. You can also do a programmatic GET request to ```http://127.0.0.1:7778/api/``` + +*http://127.0.0.1:7778/ramchain/block/height/0* -> full webpage + +*http://127.0.0.1:7778/json/ramchain/block/height/0* -> JSON only + +```curl --url "http://127.0.0.1:7778/ramchain/BTCD/block/height/0"``` --> full webpage returned (probably not what you want) +```curl --url "http://127.0.0.1:7778/api/ramchain/BTCD/block/height/0"``` --> returns just the json object from the api call + +Internally, all paths convert the request into a standard SuperNET JSON request. you can use a POST command to directly submit such JSON requests: +```curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"ramchain\",\"method\":\"block\",\"coin\":\"BTCD\",\"height\":0}"``` + +Another approach is to use the bitcoin RPC syntax via: + curl --url "http://127.0.0.1:7778" --data "{\"coin\":\"BTCD\",\"method\":\"getinfo\",\"params\":[]}" +the params:[] array is where the standard bitcoin parameters go, the only change that is needed is to specify the coin +alternatively {"agent":"SuperNET","method":"bitcoinrpc","coin":"BTCD"} will set the coin +to use for bitcoin RPC calls. this will suffice in single coin environments + +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"iguana",\"method\":\"test\"}" +curl --url "http://127.0.0.1:7778/iguana/test" -> html page with results +curl --url "http://127.0.0.1:7778/api/iguana/test" -> just json text +http://127.0.0.1:7778 -> superugly GUI +http://127.0.0.1:7778/iguana/test +http://127.0.0.1:7778/api/iguana/test +postCall('{"agent":"iguana","method":"test"}'} +iguana_JSON("{\"agent\":\"iguana",\"method\":\"test\"}"); -> direct C function call + + +iguana can be invoked with a command line argument. if it is a name of a file, it will load it and check to see if it is valid JSON and if it is, it will use it. Otherwise the command line argument needs to be valid JSON to be used and it will process the JSON to initialize account passphrases, exchange apikeys, etc. A few special keys: + +"wallet" -> passphrase used for the persistent privkey +"2fafile" -> secondary part (optional) for the persistent privkey +"numhelpers" -> number of helper threads (need at least 1) +"exchanges" -> { "name":"", ... } + "apikey", "apisecret", "userid", "tradepassword" these are as expected + "pollgap" -> gap between each access to exchange for getting prices + +###### +The goal for iguana is to create a scalable bitcoin core implementation that is backward compatible and a drop in replacement, so all the RPC needs to be implemented in addition to peer messaging, blockchain, scripts, wallet, etc. + +The first thing you notice when looking at the raw blockchain is that there is a LOT of redundancy, so by mapping the high entropy hashes to a 32bit integer, you get a 28 byte savings for each use. For a txid with N outputs, that is up to N*28 bytes that would be saved as each vin refers to the txid. + +Since the blockchain has an implicit ordering, it is possible to create a canonical numbering for the txid, vouts, vins, and this will allow syncing the iguana files to save gobs of bandwidth. However both endian formats need to be put into the bittorrent network as the iguana files are designed to be directly memory mapped. This allows skipping of serialization/deserialization of each and every multibyte field. Since the files are less than half the size, even with the doubling due to both endian forms, it is still less overall data than the raw blockchain. + +bitfields are used, so that means a standard way of allocating the bits needs to be used by each compiler. gcc and clang use the same method, so as long as it is compiled with those or one with compatible bitfield allocation, the memory mapped files should work. + +The most space is used by the vout, vin, pkhash structures, as there are a lot more vouts than txids. The txid structure has not been fully optimized, but since it is less than 1% of overall space, I felt it was not worth making it more complicated to save few bytes. The pkhash is the pubkey hash rmd160(sha256(pubkey)) and this is the most efficient way to index the blockchain as all vout scripts generate a rmd160[20] either implicitly for the scripts with pubkey, pay to pubkey hash standard script and all the new p2sh scripts. Another reason to use rmd160 is that it makes it easy to convert to the equivalent addresses for other coins, ie. all coins have the same rmd160 even if the coin addresses are different due to the address type byte added to the base58 conversion. + +The following are the second pass data structures that are created from a batch of raw structures in groups of 2000 (the size of the getheaders). The design needs to meet many constraints, primarily to be as small as possible without sacrificing speed and to be able to work in a parallel sync. That means that each block or bundle needs to be as self-contained as possible, but have external references that can be resolved. This is similar to object files and linkers. The main thing that has these external references are the vins. + +I tried quite a few variations before settling on this. Earlier versions combined everything into a single dataset, which is good for making searches via hashtable really fast, but with the ever growing size of the blockchain not very scalable. The maximum size of 2000 blocks is 2GB right now and at that size there is no danger of overflowing any 32bit offset, but for the most part, the 32bit indexes are of the item, so it can represent much larger than 4GB. + +iguana doesnt use any DB as that is what causes most of the bottlenecks and since the data doesnt change (after 20 blocks), a DB is just overkill. Using the memory mapped file approach, it takes no time to initialize the data structures, but certain operations take linear time relative to the number of bundles. Achieving this performance requires constant time performance for all operations within a bundle. Since most bundles will not have the hash that is being searched for, I used a bloom filter to quickly determine which bundles need to be searched deeper. For the deeper searches, there is a open hashtable that always has good performance as it is sized so it is one third empty. Since the total number of items is known and never changes, both the bloom filters and hashtable never change after initial creation. + +What this means is that on initialization, you memory map the 200 bundles and in the time it takes to do that (less than 1sec), you are ready to query the dataset. Operations like adding a privkey takes a few milliseconds, since all the addresses are already indexed, but caching all the transactions for an address is probably not even necessary for a single user wallet use case. However for dealing with thousands of addresses, it would make sense to cache the lists of transactions to save the few milliseconds per address. + +You might be wondering how is it even possible to have an append only dataset that allows traversing the entire blockchain and searching for all transactions from a specific address. Note that by indexing at the rmd160 level, there is no difference between a multisig address and a normal address and so all the operations work equally for any address, be it pubkey, pubkeyhash, multisig or p2sh. + +With 200 bundles and millions of unspents per bundle recently, it would be easy to have things take a long time to iterate through and find all references to a specific address. What I realized was that during a single pass I can update an arbitrary number of linked lists, one for each rmd160. However it needs to work backwards so you never need to change any previous entry. As soon as an unspent is created, it is final and never changes. It does require a single dynamic data structure for the account which keeps track of the balance (just the sum of outputs) and the last unspentind. As new unspents are made to the same address, it links back to the prior one and updates the total balance. + +To get the list of all transactions, all bundles need to be queried. For each bundle, constant time hash lookups find the last access and then iterating backwards to the first occurance finds all unspents in the bundle. So it is linear time relative to the total number of unspents that an address has with a small 200 constant time operations overhead. As the number of bundles grows, this will continue to increase, but it is always possible to make a single lookup table that spans the entire set of bundles, so I am not worried about scaling things up. Note that the parallel nature of all the bundles makes using multiple cores for all the searches relatively easy, so speedups of N using N cores is not much work. + +I could probably get rid of the firstunspentind in the pkhash struct, but it is there to provide an error check when iterating backwards on the linked list. the pubkeyoffset is also optional, but I find it handy to be able to know what pubkey maps to the rmd160 for a variety of use cases and I am on the fence as to whether to make it purgeable or not. + +I had to make the signatures from the vinscripts purgeable as I dont seem much use for them after a node has validated an input other than relaying the raw block to other nodes. Without the sigs, a node can still be totally self-sufficient when creating new transactions and the sigs are high entropy and unique and is approx equal to the uncompressed size of everything else! The pubkeys are much smaller, especially due to address reuse within a bundle, which only takes up 4 bytes. It is probably worth adding a way to purge the pubkeys at some point, but the method I used to enable signature pruning was to create a stack that grows down to put the signatures into during processing the each block. There is also a forward growing data store where all the things that cant be encoded in the baseline structures are put into. + +It is necessary to used an upfront memory allocation as doing hundreds of millions of malloc/free is a good way to slow things down, especially when there are many threads. Using the onetime allocation, cleanup is guaranteed to not leave any stragglers as a single free releases all memory. After all the blocks in the bundle are processed, there will be a gap between the end of the forward growing data called Kspace and the reverse growing stack for the sigs, so before saving to disk, the sigs are moved to remove the gap. At this point it becomes clear why it had to be a reverse growing stack. I dont want to have to make another pass through the data after moving the signatures and by using negative offsets relative to the top of the stack, there is no need to change any of the offsets used for the signatures. + +Most of the unspents use standard scripts so usually the script offset is zero. However this doesnt take up much room at all as all this data is destined to be put into a compressed filesystem, like squashfs, which cuts the size in about half. Not sure what the compressed size will be with the final iteration, but last time with most of the data it was around 12GB, so I think it will end up around 15GB compressed and 25GB uncompressed. + +Each bundle file will have the following order: +[ ][nonstandard scripts and other data] ... gap ... [signatures] +after saving it the gap goes away. Since the signatures are at the end, it is possible to truncate each bundle file to dramatically reduce its size. It would save a lot of time compressing the files without the signatures as they are high entropy and dont compress, but having them in a different file would really complicate the code. Not that it isnt already quite complicated. + +I realize totally replace all the DB is rather radical, but it was the only way possible to achieve a parallel sync that streams data in at bandwidth saturation speeds. In order to validate the dataset, which is clearly required before any production use of a DB replacement, I decided to put in the extra effort to make iguana able to act as a lossless codec. This would allow verification at the rawtx bytes level with a simple loop that iterates across all blocks and all tx within a block to verify that all txbytes match against what bitcoind returns. + +Of course, since bitcoind wont be able to even calculate balances for all addresses without enabling watching all addresses, I dont know a practical way to verify that all the balance calculations are correct. + +Here are the fundamental data structures and the total size for each is not a typo, it really is 64 bytes for txid, 28 bytes per unspent, 12 bytes per spend and 32 bytes per pkhash and 12 bytes for account balance and end of linked list. But things are even smaller! Each unspent has a unique unspentind within each bundle, so you can have a list of all the unspents that takes up 4 bytes per unspent + 4bytes per bundle it appears in. + +I havent optimized the utxo handling yet, but the plan is to calculate an overlay vector of all unspents that are spent for each bundle. This too is a static dataset, but it cant be calculated until all prior bundles are present due to all external references needing to be resolved. This final step would happen as the mainchain is validated linearly as the parallel sync is proceeding. For simplicity I will also verify all the signatures during this last pass. + +At that point, to create the current utxo at any bundle boundary, it is a matter to OR all the spend vectors. That brings all the data current to the most recent bundle, which might be 1 or 1999 blocks in the past. So the final block will need to be special cased to allow it to be searched before it is in final form. + +I think that covers most of the basics. + +struct iguana_txid // 64 bytes +{ + bits256 txid; + uint32_t txidind,firstvout,firstvin,locktime,version,timestamp,extraoffset; + uint16_t numvouts,numvins; +} __attribute__((packed)); + +struct iguana_unspent // 28 bytes +{ + uint64_t value; + uint32_t txidind,pkind,prevunspentind,scriptoffset; + uint16_t hdrsi:12,type:4,vout; + } __attribute__((packed)); + +struct iguana_spend // 12 bytes +{ + uint32_t spendtxidind,scriptoffset; + int16_t prevout; + uint16_t numsigs:4,numpubkeys:4,p2sh:1,sighash:4,external:1,sequenceid:2; + } __attribute__((packed)); + +struct iguana_pkhash // 32 bytes +{ + uint8_t rmd160[20]; + uint32_t pkind,firstunspentind,pubkeyoffset; +} __attribute__((packed)); + +// dynamic during bundle creation +struct iguana_account // 12 bytes +{ + uint64_t balance; uint32_t lastunspentind; +} __attribute__((packed)); // pkind + diff --git a/iguana/SuperNET.c b/iguana/SuperNET.c index f45209195..6ea723627 100755 --- a/iguana/SuperNET.c +++ b/iguana/SuperNET.c @@ -647,7 +647,8 @@ char *SuperNET_JSON(struct supernet_info *myinfo,cJSON *json,char *remoteaddr) //printf("SuperNET_JSON.(%s)\n",jprint(json,0)); if ( remoteaddr != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 ) remoteaddr = 0; - agent = jstr(json,"agent"); + if ( (agent = jstr(json,"agent")) == 0 ) + agent = "bitcoinrpc"; method = jstr(json,"method"); if ( agent != 0 && strcmp(agent,"pangea") == 0 && jobj(json,"categoryhash") == 0 ) { diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index ee5fdff65..fecea1d61 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -14,307 +14,10 @@ ******************************************************************************/ #include "bitcoin.h" +cJSON *instantdex_statemachinejson(struct bitcoin_swapinfo *swap); static const char base58_chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; -#define IGUANA_SCRIPT_NULL 0 -#define IGUANA_SCRIPT_76AC 1 -#define IGUANA_SCRIPT_76A988AC 2 -#define IGUANA_SCRIPT_P2SH 3 -#define IGUANA_SCRIPT_OPRETURN 4 -#define IGUANA_SCRIPT_3of3 5 -#define IGUANA_SCRIPT_2of3 6 -#define IGUANA_SCRIPT_1of3 7 -#define IGUANA_SCRIPT_2of2 8 -#define IGUANA_SCRIPT_1of2 9 -#define IGUANA_SCRIPT_MSIG 10 -#define IGUANA_SCRIPT_DATA 11 -#define IGUANA_SCRIPT_STRANGE 15 - -enum opcodetype -{ - // push value - OP_0 = 0x00, - OP_FALSE = OP_0, - OP_PUSHDATA1 = 0x4c, - OP_PUSHDATA2 = 0x4d, - OP_PUSHDATA4 = 0x4e, - OP_1NEGATE = 0x4f, - OP_RESERVED = 0x50, - OP_1 = 0x51, - OP_TRUE=OP_1, - OP_2 = 0x52, - OP_3 = 0x53, - OP_4 = 0x54, - OP_5 = 0x55, - OP_6 = 0x56, - OP_7 = 0x57, - OP_8 = 0x58, - OP_9 = 0x59, - OP_10 = 0x5a, - OP_11 = 0x5b, - OP_12 = 0x5c, - OP_13 = 0x5d, - OP_14 = 0x5e, - OP_15 = 0x5f, - OP_16 = 0x60, - - // control - OP_NOP = 0x61, - OP_VER = 0x62, - OP_IF = 0x63, - OP_NOTIF = 0x64, - OP_VERIF = 0x65, - OP_VERNOTIF = 0x66, - OP_ELSE = 0x67, - OP_ENDIF = 0x68, - OP_VERIFY = 0x69, - OP_RETURN = 0x6a, - - // stack ops - OP_TOALTSTACK = 0x6b, - OP_FROMALTSTACK = 0x6c, - OP_2DROP = 0x6d, - OP_2DUP = 0x6e, - OP_3DUP = 0x6f, - OP_2OVER = 0x70, - OP_2ROT = 0x71, - OP_2SWAP = 0x72, - OP_IFDUP = 0x73, - OP_DEPTH = 0x74, - OP_DROP = 0x75, - OP_DUP = 0x76, - OP_NIP = 0x77, - OP_OVER = 0x78, - OP_PICK = 0x79, - OP_ROLL = 0x7a, - OP_ROT = 0x7b, - OP_SWAP = 0x7c, - OP_TUCK = 0x7d, - - // splice ops - OP_CAT = 0x7e, - OP_SUBSTR = 0x7f, - OP_LEFT = 0x80, - OP_RIGHT = 0x81, - OP_SIZE = 0x82, - - // bit logic - OP_INVERT = 0x83, - OP_AND = 0x84, - OP_OR = 0x85, - OP_XOR = 0x86, - OP_EQUAL = 0x87, - OP_EQUALVERIFY = 0x88, - OP_RESERVED1 = 0x89, - OP_RESERVED2 = 0x8a, - - // numeric - OP_1ADD = 0x8b, - OP_1SUB = 0x8c, - OP_2MUL = 0x8d, - OP_2DIV = 0x8e, - OP_NEGATE = 0x8f, - OP_ABS = 0x90, - OP_NOT = 0x91, - OP_0NOTEQUAL = 0x92, - - OP_ADD = 0x93, - OP_SUB = 0x94, - OP_MUL = 0x95, - OP_DIV = 0x96, - OP_MOD = 0x97, - OP_LSHIFT = 0x98, - OP_RSHIFT = 0x99, - - OP_BOOLAND = 0x9a, - OP_BOOLOR = 0x9b, - OP_NUMEQUAL = 0x9c, - OP_NUMEQUALVERIFY = 0x9d, - OP_NUMNOTEQUAL = 0x9e, - OP_LESSTHAN = 0x9f, - OP_GREATERTHAN = 0xa0, - OP_LESSTHANOREQUAL = 0xa1, - OP_GREATERTHANOREQUAL = 0xa2, - OP_MIN = 0xa3, - OP_MAX = 0xa4, - - OP_WITHIN = 0xa5, - - // crypto - OP_RIPEMD160 = 0xa6, - OP_SHA1 = 0xa7, - OP_SHA256 = 0xa8, - OP_HASH160 = 0xa9, - OP_HASH256 = 0xaa, - OP_CODESEPARATOR = 0xab, - OP_CHECKSIG = 0xac, - OP_CHECKSIGVERIFY = 0xad, - OP_CHECKMULTISIG = 0xae, - OP_CHECKMULTISIGVERIFY = 0xaf, - - // expansion - OP_NOP1 = 0xb0, - OP_NOP2 = 0xb1, - OP_NOP3 = 0xb2, - OP_NOP4 = 0xb3, - OP_NOP5 = 0xb4, - OP_NOP6 = 0xb5, - OP_NOP7 = 0xb6, - OP_NOP8 = 0xb7, - OP_NOP9 = 0xb8, - OP_NOP10 = 0xb9, - - // template matching params - OP_SMALLINTEGER = 0xfa, - OP_PUBKEYS = 0xfb, - OP_PUBKEYHASH = 0xfd, - OP_PUBKEY = 0xfe, - - OP_INVALIDOPCODE = 0xff, -}; - -const char *get_opname(int32_t *extralenp,enum opcodetype opcode) -{ - *extralenp = 0; - switch (opcode) - { - // push value - case OP_0 : return "0"; - case OP_PUSHDATA1 : *extralenp = 1; return "OP_PUSHDATA1"; - case OP_PUSHDATA2 : *extralenp = 2; return "OP_PUSHDATA2"; - case OP_PUSHDATA4 : *extralenp = 4; return "OP_PUSHDATA4"; - case OP_1NEGATE : return "-1"; - case OP_RESERVED : return "OP_RESERVED"; - case OP_1 : return "1"; - case OP_2 : return "2"; - case OP_3 : return "3"; - case OP_4 : return "4"; - case OP_5 : return "5"; - case OP_6 : return "6"; - case OP_7 : return "7"; - case OP_8 : return "8"; - case OP_9 : return "9"; - case OP_10 : return "10"; - case OP_11 : return "11"; - case OP_12 : return "12"; - case OP_13 : return "13"; - case OP_14 : return "14"; - case OP_15 : return "15"; - case OP_16 : return "16"; - - // control - case OP_NOP : return "OP_NOP"; - case OP_VER : return "OP_VER"; - case OP_IF : return "OP_IF"; - case OP_NOTIF : return "OP_NOTIF"; - case OP_VERIF : return "OP_VERIF"; - case OP_VERNOTIF : return "OP_VERNOTIF"; - case OP_ELSE : return "OP_ELSE"; - case OP_ENDIF : return "OP_ENDIF"; - case OP_VERIFY : return "OP_VERIFY"; - case OP_RETURN : return "OP_RETURN"; - - // stack ops - case OP_TOALTSTACK : return "OP_TOALTSTACK"; - case OP_FROMALTSTACK : return "OP_FROMALTSTACK"; - case OP_2DROP : return "OP_2DROP"; - case OP_2DUP : return "OP_2DUP"; - case OP_3DUP : return "OP_3DUP"; - case OP_2OVER : return "OP_2OVER"; - case OP_2ROT : return "OP_2ROT"; - case OP_2SWAP : return "OP_2SWAP"; - case OP_IFDUP : return "OP_IFDUP"; - case OP_DEPTH : return "OP_DEPTH"; - case OP_DROP : return "OP_DROP"; - case OP_DUP : return "OP_DUP"; - case OP_NIP : return "OP_NIP"; - case OP_OVER : return "OP_OVER"; - case OP_PICK : return "OP_PICK"; - case OP_ROLL : return "OP_ROLL"; - case OP_ROT : return "OP_ROT"; - case OP_SWAP : return "OP_SWAP"; - case OP_TUCK : return "OP_TUCK"; - - // splice ops - case OP_CAT : return "OP_CAT"; - case OP_SUBSTR : return "OP_SUBSTR"; - case OP_LEFT : return "OP_LEFT"; - case OP_RIGHT : return "OP_RIGHT"; - case OP_SIZE : return "OP_SIZE"; - - // bit logic - case OP_INVERT : return "OP_INVERT"; - case OP_AND : return "OP_AND"; - case OP_OR : return "OP_OR"; - case OP_XOR : return "OP_XOR"; - case OP_EQUAL : return "OP_EQUAL"; - case OP_EQUALVERIFY : return "OP_EQUALVERIFY"; - case OP_RESERVED1 : return "OP_RESERVED1"; - case OP_RESERVED2 : return "OP_RESERVED2"; - - // numeric - case OP_1ADD : return "OP_1ADD"; - case OP_1SUB : return "OP_1SUB"; - case OP_2MUL : return "OP_2MUL"; - case OP_2DIV : return "OP_2DIV"; - case OP_NEGATE : return "OP_NEGATE"; - case OP_ABS : return "OP_ABS"; - case OP_NOT : return "OP_NOT"; - case OP_0NOTEQUAL : return "OP_0NOTEQUAL"; - case OP_ADD : return "OP_ADD"; - case OP_SUB : return "OP_SUB"; - case OP_MUL : return "OP_MUL"; - case OP_DIV : return "OP_DIV"; - case OP_MOD : return "OP_MOD"; - case OP_LSHIFT : return "OP_LSHIFT"; - case OP_RSHIFT : return "OP_RSHIFT"; - case OP_BOOLAND : return "OP_BOOLAND"; - case OP_BOOLOR : return "OP_BOOLOR"; - case OP_NUMEQUAL : return "OP_NUMEQUAL"; - case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY"; - case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL"; - case OP_LESSTHAN : return "OP_LESSTHAN"; - case OP_GREATERTHAN : return "OP_GREATERTHAN"; - case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL"; - case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL"; - case OP_MIN : return "OP_MIN"; - case OP_MAX : return "OP_MAX"; - case OP_WITHIN : return "OP_WITHIN"; - - // crypto - case OP_RIPEMD160 : return "OP_RIPEMD160"; - case OP_SHA1 : return "OP_SHA1"; - case OP_SHA256 : return "OP_SHA256"; - case OP_HASH160 : return "OP_HASH160"; - case OP_HASH256 : return "OP_HASH256"; - case OP_CODESEPARATOR : return "OP_CODESEPARATOR"; - case OP_CHECKSIG : return "OP_CHECKSIG"; - case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY"; - case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG"; - case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; - - // expanson - case OP_NOP1 : return "OP_NOP1"; - case OP_NOP2 : return "OP_NOP2"; - case OP_NOP3 : return "OP_NOP3"; - case OP_NOP4 : return "OP_NOP4"; - case OP_NOP5 : return "OP_NOP5"; - case OP_NOP6 : return "OP_NOP6"; - case OP_NOP7 : return "OP_NOP7"; - case OP_NOP8 : return "OP_NOP8"; - case OP_NOP9 : return "OP_NOP9"; - case OP_NOP10 : return "OP_NOP10"; - - case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; - // Note: - // The template matching params OP_SMALLDATA/etc are defined in opcodetype enum - // as kind of implementation hack, they are *NOT* real opcodes. If found in real - // Script, just let the default: case deal with them. - default: return "OP_UNKNOWN"; - } -} - char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params) { return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params)); @@ -481,11 +184,11 @@ void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen) char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey,int32_t len) { - int32_t i; uint8_t data[25]; bits256 hash; char checkaddr[65]; + int32_t i; uint8_t data[25]; bits256 hash;// char checkaddr[65]; if ( len != 20 ) calc_rmd160_sha256(data+1,pubkey,len); else memcpy(data+1,pubkey,20); - btc_convrmd160(checkaddr,addrtype,data+1); + //btc_convrmd160(checkaddr,addrtype,data+1); //for (i=0; i<20; i++) // printf("%02x",data[i+1]); //printf(" RMD160 len.%d\n",len); @@ -495,10 +198,10 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey,int32_t le data[21+i] = hash.bytes[31-i]; if ( (coinaddr= bitcoin_base58encode(coinaddr,data,25)) != 0 ) { - uint8_t checktype,rmd160[20]; - bitcoin_addr2rmd160(&checktype,rmd160,coinaddr); - if ( strcmp(checkaddr,coinaddr) != 0 ) - printf("checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20)); + //uint8_t checktype,rmd160[20]; + //bitcoin_addr2rmd160(&checktype,rmd160,coinaddr); + //if ( strcmp(checkaddr,coinaddr) != 0 ) + // printf("checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20)); } return(coinaddr); } @@ -649,385 +352,6 @@ int32_t bitcoin_verify(uint8_t *sig,int32_t siglen,uint8_t *data,int32_t datalen return(retval); } -int32_t bitcoin_pubkeyspend(uint8_t *script,int32_t n,uint8_t pubkey[66]) -{ - int32_t scriptlen = bitcoin_pubkeylen(pubkey); - script[n++] = scriptlen; - memcpy(&script[n],pubkey,scriptlen); - n += scriptlen; - script[n++] = SCRIPT_OP_CHECKSIG; - return(n); -} - -int32_t bitcoin_p2shspend(uint8_t *script,int32_t n,uint8_t rmd160[20]) -{ - script[n++] = SCRIPT_OP_HASH160; - script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14; - script[n++] = SCRIPT_OP_EQUAL; - return(n); -} - -int32_t bitcoin_revealsecret160(uint8_t *script,int32_t n,uint8_t secret160[20]) -{ - script[n++] = SCRIPT_OP_HASH160; - script[n++] = 0x14; memcpy(&script[n],secret160,0x14); n += 0x14; - script[n++] = SCRIPT_OP_EQUALVERIFY; - return(n); -} - -int32_t bitcoin_standardspend(uint8_t *script,int32_t n,uint8_t rmd160[20]) -{ - script[n++] = SCRIPT_OP_DUP; - script[n++] = SCRIPT_OP_HASH160; - script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14; - script[n++] = SCRIPT_OP_EQUALVERIFY; - script[n++] = SCRIPT_OP_CHECKSIG; - return(n); -} - -int32_t bitcoin_checklocktimeverify(uint8_t *script,int32_t n,uint32_t locktime) -{ - script[n++] = (locktime >> 24), script[n++] = (locktime >> 16), script[n++] = (locktime >> 8), script[n++] = locktime; - script[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY; - script[n++] = SCRIPT_OP_DROP; - return(n); -} - -int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp) -{ - int32_t i,plen; - script[n++] = 0x50 + vp->M; - for (i=0; iN; i++) - { - if ( (plen= bitcoin_pubkeylen(vp->signers[i].pubkey)) < 0 ) - return(-1); - script[n++] = plen; - memcpy(&script[n],vp->signers[i].pubkey,plen); - n += plen; - } - script[n++] = 0x50 + vp->N; - script[n++] = SCRIPT_OP_CHECKMULTISIG; - calc_rmd160_sha256(p2sh_rmd160,script,n); - return(n); -} - -int32_t bitcoin_p2shscript(uint8_t *script,int32_t n,const uint8_t *p2shscript,const int32_t p2shlen) -{ - if ( p2shlen >= 0xfd ) - { - script[n++] = 0x4d; - script[n++] = (p2shlen & 0xff); - script[n++] = ((p2shlen >> 8) & 0xff); - } - else - { - script[n++] = 0x4c; - script[n++] = p2shlen; - } - memcpy(&script[n],p2shscript,p2shlen), n += p2shlen; - return(n); -} - -int32_t bitcoin_changescript(struct iguana_info *coin,uint8_t *changescript,int32_t n,uint64_t *changep,char *changeaddr,uint64_t inputsatoshis,uint64_t satoshis,uint64_t txfee) -{ - uint8_t addrtype,rmd160[20]; int32_t len; - *changep = 0; - if ( inputsatoshis >= (satoshis + txfee) ) - { - *changep = inputsatoshis - (satoshis + txfee); - if ( changeaddr != 0 && changeaddr[0] != 0 ) - { - bitcoin_addr2rmd160(&addrtype,rmd160,changeaddr); - if ( addrtype == coin->chain->pubtype ) - len = bitcoin_standardspend(changescript,0,rmd160); - else if ( addrtype == coin->chain->p2shtype ) - len = bitcoin_standardspend(changescript,0,rmd160); - else - { - printf("error with mismatched addrtype.%02x vs (%02x %02x)\n",addrtype,coin->chain->pubtype,coin->chain->p2shtype); - return(-1); - } - return(len); - } - else printf("error no change address when there is change\n"); - } - return(-1); -} - -int32_t bitcoin_scriptsig(struct iguana_info *coin,uint8_t *script,int32_t n,const struct vin_info *vp,struct iguana_msgtx *msgtx) -{ - int32_t i,siglen; - if ( vp->N > 1 ) - script[n++] = SCRIPT_OP_NOP; - for (i=0; iN; i++) - { - if ( (siglen= vp->signers[i].siglen) != 0 ) - { - script[n++] = siglen; - memcpy(&script[n],vp->signers[i].sig,siglen), n += siglen; - } - } - if ( vp->type == IGUANA_SCRIPT_P2SH ) - { - printf("add p2sh script to sig\n"); - n = bitcoin_p2shscript(script,n,vp->p2shscript,vp->p2shlen); - } - return(n); -} - -int32_t bitcoin_cltvscript(uint8_t p2shtype,char *ps2h_coinaddr,uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,char *senderaddr,char *otheraddr,uint8_t secret160[20],uint32_t locktime) -{ - // OP_IF - // OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG - // OP_ELSE - // OP_HASH160 secret160 OP_EQUALVERIFY OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG // standard spend - // OP_ENDIF - uint8_t rmd160A[20],rmd160B[20],addrtypeA,addrtypeB; - bitcoin_addr2rmd160(&addrtypeA,rmd160A,senderaddr); - bitcoin_addr2rmd160(&addrtypeB,rmd160B,otheraddr); - script[n++] = SCRIPT_OP_IF; - n = bitcoin_checklocktimeverify(script,n,locktime); - n = bitcoin_standardspend(script,n,rmd160A); - script[n++] = SCRIPT_OP_ELSE; - n = bitcoin_revealsecret160(script,n,secret160); - n = bitcoin_standardspend(script,n,rmd160B); - script[n++] = SCRIPT_OP_ENDIF; - calc_rmd160_sha256(p2sh_rmd160,script,n); - bitcoin_address(ps2h_coinaddr,p2shtype,p2sh_rmd160,20); - return(n); -} - -int32_t iguana_scriptgen(struct iguana_info *coin,int32_t *Mp,int32_t *nump,char *coinaddr,uint8_t *script,char *asmstr,uint8_t rmd160[20],uint8_t type,const struct vin_info *vp,int32_t txi) -{ - uint8_t addrtype; char rmd160str[41],pubkeystr[256]; int32_t plen,i,m,n,flag = 0,scriptlen = 0; - m = n = 1; - asmstr[0] = 0; - if ( type == IGUANA_SCRIPT_76A988AC || type == IGUANA_SCRIPT_76AC || type == IGUANA_SCRIPT_P2SH ) - { - if ( type == IGUANA_SCRIPT_P2SH ) - addrtype = coin->chain->p2shtype; - else addrtype = coin->chain->pubtype; - init_hexbytes_noT(rmd160str,rmd160,20); - btc_convrmd160(coinaddr,addrtype,rmd160); - } - switch ( type ) - { - case IGUANA_SCRIPT_NULL: - strcpy(asmstr,txi == 0 ? "coinbase " : "PoSbase "); - flag++; - coinaddr[0] = 0; - break; - case IGUANA_SCRIPT_76AC: - if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) < 0 ) - return(0); - init_hexbytes_noT(pubkeystr,(uint8_t *)vp->signers[0].pubkey,plen); - sprintf(asmstr,"OP_DUP %s OP_CHECKSIG // %s",pubkeystr,coinaddr); - scriptlen = bitcoin_pubkeyspend(script,0,(uint8_t *)vp->signers[0].pubkey); - //printf("[%02x] scriptlen.%d (%s)\n",vp->signers[0].pubkey[0],scriptlen,asmstr); - break; - case IGUANA_SCRIPT_76A988AC: - sprintf(asmstr,"OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG // %s",rmd160str,coinaddr); - scriptlen = bitcoin_standardspend(script,0,rmd160); - break; - case IGUANA_SCRIPT_P2SH: - sprintf(asmstr,"OP_HASH160 %s OP_EQUAL // %s",rmd160str,coinaddr); - scriptlen = bitcoin_p2shspend(script,0,rmd160); - break; - case IGUANA_SCRIPT_OPRETURN: - strcpy(asmstr,"OP_RETURN "); - flag++; - break; - case IGUANA_SCRIPT_3of3: m = 3, n = 3; break; - case IGUANA_SCRIPT_2of3: m = 2, n = 3; break; - case IGUANA_SCRIPT_1of3: m = 1, n = 3; break; - case IGUANA_SCRIPT_2of2: m = 2, n = 2; break; - case IGUANA_SCRIPT_1of2: m = 1, n = 2; break; - case IGUANA_SCRIPT_MSIG: m = vp->M, n = vp->N; break; - case IGUANA_SCRIPT_DATA: - strcpy(asmstr,"DATA ONLY"); - flag++; - break; - case IGUANA_SCRIPT_STRANGE: - strcpy(asmstr,"STRANGE SCRIPT "); - flag++; - break; - default: printf("unexpected script type\n"); break; - } - if ( n > 1 ) - { - scriptlen = bitcoin_MofNspendscript(rmd160,script,0,vp); - sprintf(asmstr,"%d ",m); - for (i=0; isigners[i].pubkey)) > 0 ) - { - init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->signers[i].pubkey,plen); - strcat(asmstr," "); - } else strcat(asmstr,"NOPUBKEY "); - } - sprintf(asmstr + strlen(asmstr),"%d // M.%d of N.%d [",n,m,n); - for (i=0; isigners[i].coinaddr,ispendlen > 0 ) - init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->spendscript,vp->spendlen); - *Mp = m, *nump = n; - return(scriptlen); -} - -int32_t iguana_expandscript(struct iguana_info *coin,char *asmstr,int32_t maxlen,uint8_t *script,int32_t scriptlen) -{ - asmstr[0] = 0; - return(0); -} - -int32_t _iguana_calcrmd160(struct iguana_info *coin,struct vin_info *vp) -{ - static uint8_t zero_rmd160[20]; - char hexstr[8192]; uint8_t sha256[32],*script,type; int32_t i,n,m,plen; - vp->N = 1; - vp->M = 1; - type = IGUANA_SCRIPT_STRANGE; - if ( vp->spendlen == 0 ) - { - if ( zero_rmd160[0] == 0 ) - { - calc_rmd160_sha256(zero_rmd160,vp->spendscript,vp->spendlen); - //vcalc_sha256(0,sha256,vp->spendscript,vp->spendlen); // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - //calc_rmd160(0,zero_rmd160,sha256,sizeof(sha256)); // b472a266d0bd89c13706a4132ccfb16f7c3b9fcb - init_hexbytes_noT(hexstr,zero_rmd160,20); - char str[65]; printf("iguana_calcrmd160 zero len %s -> %s\n",bits256_str(str,*(bits256 *)sha256),hexstr); - } - memcpy(vp->rmd160,zero_rmd160,sizeof(zero_rmd160)); - return(IGUANA_SCRIPT_NULL); - } - else if ( vp->spendscript[0] == SCRIPT_OP_RETURN ) - type = IGUANA_SCRIPT_OPRETURN; - else if ( vp->spendscript[0] == SCRIPT_OP_DUP && vp->spendscript[1] == SCRIPT_OP_HASH160 && vp->spendscript[2] == 20 && vp->spendscript[vp->spendscript[2]+3] == SCRIPT_OP_EQUALVERIFY && vp->spendscript[vp->spendscript[2]+4] == SCRIPT_OP_CHECKSIG ) - { - //printf("IGUANA_SCRIPT_76A988AC plen.%d vs %d vp->spendlen\n",vp->spendscript[2]+4,vp->spendlen); - // 76a9145f69cb73016264270dae9f65c51f60d0e4d6fd4488ac - //vcalc_sha256(0,sha256,&vp->spendscript[3],vp->spendscript[2]); - //calc_rmd160(0,vp->rmd160,sha256,sizeof(sha256)); - memcpy(vp->rmd160,&vp->spendscript[3],20); - if ( (plen= vp->spendscript[2]+5) < vp->spendlen ) - { - while ( plen < vp->spendlen ) - if ( vp->spendscript[plen++] != 0x61 ) // nop - return(IGUANA_SCRIPT_STRANGE); - } - return(IGUANA_SCRIPT_76A988AC); - } - // 21035f1321ed17d387e4433b2fa229c53616057964af065f98bfcae2233c5108055eac - else if ( vp->spendscript[0] > 0 && vp->spendscript[0] < 76 && vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKSIG && vp->spendscript[0] == vp->spendlen-2 ) - { - memcpy(vp->signers[0].pubkey,&vp->spendscript[1],vp->spendscript[0]); - calc_rmd160_sha256(vp->rmd160,vp->signers[0].pubkey,vp->spendscript[0]); - return(IGUANA_SCRIPT_76AC); - } - else if ( vp->spendscript[0] == SCRIPT_OP_HASH160 && vp->spendscript[1] == 0x14 && vp->spendlen == 23 && vp->spendscript[22] == SCRIPT_OP_EQUAL ) - { - memcpy(vp->rmd160,vp->spendscript+2,20); - return(IGUANA_SCRIPT_P2SH); - } - else if ( vp->spendlen > 34 && vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKMULTISIG && (n= vp->spendscript[vp->spendlen-2]) >= 0x51 && n <= 0x60 && (m= vp->spendscript[0]) >= 0x51 && m <= n ) // m of n multisig - { - m -= 0x50, n -= 0x50; - script = vp->spendscript+1; - for (i=0; isigners[i].pubkey,script,plen); - calc_rmd160_sha256(vp->signers[i].rmd160,vp->signers[i].pubkey,plen); - bitcoin_address(vp->signers[i].coinaddr,coin->chain->pubtype,vp->signers[i].pubkey,plen); - } - if ( (int32_t)((long)script - (long)vp->spendscript) == vp->spendlen-2 ) - { - vp->N = n; - vp->M = m; - //printf("M.%d N.%d\n",m,n); - } - calc_rmd160_sha256(vp->rmd160,vp->spendscript,vp->spendlen); - if ( n == 3 ) - { - if ( m == 3 ) - return(IGUANA_SCRIPT_3of3); - else if ( m == 2 ) - return(IGUANA_SCRIPT_2of3); - else if ( m == 1 ) - return(IGUANA_SCRIPT_1of3); - } - else if ( n == 2 ) - { - if ( m == 2 ) - return(IGUANA_SCRIPT_2of2); - else if ( m == 1 ) - return(IGUANA_SCRIPT_1of2); - } - printf("strange msig M.%d of N.%d\n",m,n); - return(IGUANA_SCRIPT_MSIG); - } - else if ( vp->spendlen == vp->spendscript[0]+1 ) - { - //printf("just data.%d\n",vp->spendlen); - memcpy(vp->rmd160,zero_rmd160,sizeof(zero_rmd160)); - return(IGUANA_SCRIPT_DATA); - } - if ( type != IGUANA_SCRIPT_OPRETURN && type != IGUANA_SCRIPT_DATA ) - { - if ( vp->spendlen > 0 && vp->spendlen < sizeof(hexstr)/2-1 ) - { - static FILE *fp; - init_hexbytes_noT(hexstr,vp->spendscript,vp->spendlen); - //char str[65]; printf("unparsed script.(%s).%d in %s len.%d\n",hexstr,vp->spendlen,bits256_str(str,vp->vin.prev_hash),vp->spendlen); - if ( 1 && fp == 0 ) - fp = fopen("unparsed.txt","w"); - if ( fp != 0 ) - fprintf(fp,"%s\n",hexstr), fflush(fp); - } else sprintf(hexstr,"pkscript overflowed %ld\n",(long)sizeof(hexstr)); - } - calc_rmd160_sha256(vp->rmd160,vp->spendscript,vp->spendlen); - return(type); -} - -int32_t iguana_calcrmd160(struct iguana_info *coin,struct vin_info *vp,uint8_t *pk_script,int32_t pk_scriptlen,bits256 debugtxid,int32_t vout,uint32_t sequence) -{ - int32_t scriptlen; uint8_t script[IGUANA_MAXSCRIPTSIZE]; char asmstr[IGUANA_MAXSCRIPTSIZE*3]; - memset(vp,0,sizeof(*vp)); - vp->vin.prev_hash = debugtxid, vp->vin.prev_vout = vout; - vp->spendlen = pk_scriptlen; - vp->vin.sequence = sequence; - memcpy(vp->spendscript,pk_script,pk_scriptlen); - if ( (vp->type= _iguana_calcrmd160(coin,vp)) >= 0 && 0 ) - { - scriptlen = iguana_scriptgen(coin,&vp->M,&vp->N,vp->coinaddr,script,asmstr,vp->rmd160,vp->type,(const struct vin_info *)vp,vout); - if ( scriptlen != pk_scriptlen || (scriptlen != 0 && memcmp(script,pk_script,scriptlen) != 0) ) - { - if ( vp->type != IGUANA_SCRIPT_OPRETURN && vp->type != IGUANA_SCRIPT_DATA && vp->type != IGUANA_SCRIPT_STRANGE ) - { - int32_t i; - printf("\n--------------------\n"); - for (i=0; itype,scriptlen,pk_scriptlen); - } - } - } - return(vp->type); -} - int32_t iguana_parsevoutobj(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvout *vout,cJSON *voutobj) { int32_t len = 0; cJSON *skey; char *hexstr; @@ -1065,7 +389,7 @@ int32_t iguana_parsevinobj(struct iguana_info *coin,uint8_t *serialized,int32_t { len = (int32_t)strlen(hexstr) >> 1; decode_hex(serialized,len,hexstr); - vin->sigscript = serialized; + vin->vinscript = serialized; vin->scriptlen = len; serialized = &serialized[len]; } //else printf("iguana_parsevinobj: hex script missing (%s)\n",jprint(vinobj,0)); @@ -1156,13 +480,13 @@ cJSON *iguana_vinjson(struct iguana_info *coin,struct iguana_msgvin *vin) vout = vin->prev_vout; jaddnum(json,"sequence",vin->sequence); if ( vout < 0 && bits256_nonz(vin->prev_hash) == 0 ) - iguana_addscript(coin,json,vin->sigscript,vin->scriptlen,"coinbase"); + iguana_addscript(coin,json,vin->vinscript,vin->scriptlen,"coinbase"); else { jaddstr(json,"txid",bits256_str(str,vin->prev_hash)); jaddnum(json,"vout",vout); if ( vin->scriptlen > 0 ) - iguana_addscript(coin,json,vin->sigscript,vin->scriptlen,"scriptSig"); + iguana_addscript(coin,json,vin->vinscript,vin->scriptlen,"scriptSig"); if ( vin->spendlen > 0 ) iguana_addscript(coin,json,vin->spendscript,vin->spendlen,"scriptPub"); } @@ -1177,14 +501,14 @@ int32_t iguana_vinparse(struct iguana_info *coin,int32_t rwflag,uint8_t *seriali len += iguana_rwvarint32(rwflag,&serialized[len],&msg->scriptlen); if ( rwflag == 0 ) { - msg->sigscript = &serialized[len]; + msg->vinscript = &serialized[len]; len += msg->scriptlen; } else { if ( msg->scriptlen > 0 ) { - memcpy(&serialized[len],msg->sigscript,msg->scriptlen); + memcpy(&serialized[len],msg->vinscript,msg->scriptlen); len += msg->scriptlen; } } @@ -1193,8 +517,8 @@ int32_t iguana_vinparse(struct iguana_info *coin,int32_t rwflag,uint8_t *seriali { int32_t i; char str[65]; for (i=0; iscriptlen; i++) - printf("%02x",msg->sigscript[i]); - printf(" prev_hash.(%s) vout.%d [%p] scriptlen.%d rwflag.%d\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->sigscript,msg->scriptlen,rwflag); + printf("%02x",msg->vinscript[i]); + printf(" prev_hash.(%s) vout.%d [%p] scriptlen.%d rwflag.%d\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->vinscript,msg->scriptlen,rwflag); } return(len); } @@ -1396,57 +720,11 @@ char *iguana_rawtxbytes(struct iguana_info *coin,cJSON *json,struct iguana_msgtx return(txbytes); } -int32_t bitcoin_scriptget(struct iguana_info *coin,int32_t *hashtypep,struct vin_info *vp,uint8_t *scriptsig,int32_t len,int32_t type) -{ - char asmstr[IGUANA_MAXSCRIPTSIZE*3]; int32_t j,n,siglen,plen; - j = n = 0; - *hashtypep = SIGHASH_ALL; - while ( (siglen= scriptsig[n]) >= 70 && siglen <= 73 && n+siglen+1 < len && j < 16 ) - { - vp->signers[j].siglen = siglen; - memcpy(vp->signers[j].sig,&scriptsig[n+1],siglen); - if ( j == 0 ) - *hashtypep = vp->signers[j].sig[siglen-1]; - n += (siglen + 1); - j++; - if ( type == 0 && j > 1 ) - type = IGUANA_SCRIPT_MSIG; - } - vp->type = type; - j = 0; - while ( ((plen= scriptsig[n]) == 33 || plen == 65 ) && j < 16 ) - { - memcpy(vp->signers[j].pubkey,&scriptsig[n+1],plen); - calc_rmd160_sha256(vp->signers[j].rmd160,vp->signers[j].pubkey,plen); - if ( j == 0 ) - memcpy(vp->rmd160,vp->signers[j].rmd160,20); - n += (plen + 1); - j++; - } - if ( n < len && (scriptsig[n] == 0x4c || scriptsig[n] == 0x4d) ) - { - if ( scriptsig[n] == 0x4c ) - vp->p2shlen = scriptsig[n+1], n += 2; - else vp->p2shlen = ((uint32_t)scriptsig[n+1] + ((uint32_t)scriptsig[n+2] << 8)), n += 3; - memcpy(vp->p2shscript,&scriptsig[n],vp->p2shlen); - vp->type = IGUANA_SCRIPT_P2SH; - } - /*if ( len == 0 ) - { - // txid.(eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2).v1 - decode_hex(vp->rmd160,20,"010966776006953d5567439e5e39f86a0d273bee");//3564a74f9ddb4372301c49154605573d7d1a88fe"); - vp->type = IGUANA_SCRIPT_76A988AC; - }*/ - vp->spendlen = iguana_scriptgen(coin,&vp->M,&vp->N,vp->coinaddr,vp->spendscript,asmstr,vp->rmd160,vp->type,(const struct vin_info *)vp,vp->vin.prev_vout); - //printf("type.%d asmstr.(%s) spendlen.%d\n",vp->type,asmstr,vp->spendlen); - return(vp->spendlen); -} - int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighashsingle) { bits256 txid,sigtxid,revsigtxid; uint8_t *sig,*pubkey; struct vin_info *vp; char txidstr[128],bigstr[2560],coinaddr[64],vpnstr[64],str[65]; - int32_t n2,i,j,k,plen,vini=0,flag,numvins,hashtype,retval,siglen,asmtype,numvouts; + int32_t n2,i,j,k,plen,suffixlen,sigsize,pubkeysize,vini=0,flag,numvins,hashtype,retval,siglen,asmtype,numvouts; numvouts = msgtx->tx_out; vpnstr[0] = 0; *signedtx = 0; @@ -1455,16 +733,16 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** retval = -numvins; for (vini=0; vinivins[vini].sigscript; + //saveinput = msgtx->vins[vini].vinscript; vp = &V[vini]; - sig = &msgtx->vins[vini].sigscript[1]; - siglen = msgtx->vins[vini].sigscript[0]; + sig = &msgtx->vins[vini].vinscript[1]; + siglen = msgtx->vins[vini].vinscript[0]; vp->vin = msgtx->vins[vini]; flag = 0; for (k=0; k<2; k++) { asmtype = (k == 0) ? IGUANA_SCRIPT_76A988AC : IGUANA_SCRIPT_76AC; - if ( bitcoin_scriptget(coin,&hashtype,vp,msgtx->vins[vini].sigscript,msgtx->vins[vini].scriptlen,asmtype) < 0 ) + if ( bitcoin_scriptget(coin,&hashtype,&sigsize,&pubkeysize,&suffixlen,vp,msgtx->vins[vini].vinscript,msgtx->vins[vini].scriptlen,asmtype) < 0 ) { printf("cant get script for (%s).v%d\n",bits256_str(str,vp->vin.prev_hash),vp->vin.prev_vout); continue; @@ -1509,8 +787,8 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** sig = vp->signers[j].sig; sig[siglen++] = hashtype; vp->signers[j].siglen = siglen; - msgtx->vins[vini].sigscript = calloc(1,siglen*2+256); // fix this memleak! - msgtx->vins[vini].scriptlen = bitcoin_scriptsig(coin,msgtx->vins[vini].sigscript,0,(const struct vin_info *)vp,msgtx); + msgtx->vins[vini].vinscript = calloc(1,siglen*2+256); // fix this memleak! + msgtx->vins[vini].scriptlen = bitcoin_scriptsig(coin,msgtx->vins[vini].vinscript,0,(const struct vin_info *)vp,msgtx); //for (i=0; iname,symbol); } coin->chain = iguana_chainfind((char *)symbol,argjson,1); - iguana_initcoin(coin,argjson); strcpy(coin->symbol,symbol); + iguana_initcoin(coin,argjson); } return(coin); } @@ -422,7 +422,6 @@ void iguana_coinloop(void *arg) //printf("metrics\n"); coin->peers.lastmetrics = iguana_updatemetrics(coin); // ranks peers } - //printf("process\n"); iguana_bundlestats(coin,str); flag += iguana_processrecv(coin); } @@ -458,9 +457,9 @@ struct iguana_info *iguana_setcoin(char *symbol,void *launched,int32_t maxpeers, if ( (coin->MAXRECVCACHE= maxrecvcache) == 0 ) coin->MAXRECVCACHE = IGUANA_MAXRECVCACHE; if ( (coin->MAXPENDING= maxpending) <= 0 ) - coin->MAXPENDING = (strcmp(symbol,"BTC") == 0) ? _IGUANA_MAXPENDING : _IGUANA_MAXPENDING*32; + coin->MAXPENDING = (strcmp(symbol,"BTC") == 0) ? _IGUANA_MAXPENDING : _IGUANA_MAXPENDING; if ( (coin->MAXBUNDLES= maxbundles) <= 0 ) - coin->MAXBUNDLES = (strcmp(symbol,"BTC") == 0) ? _IGUANA_MAXBUNDLES : _IGUANA_MAXBUNDLES*64; + coin->MAXBUNDLES = (strcmp(symbol,"BTC") == 0) ? _IGUANA_MAXBUNDLES : _IGUANA_MAXBUNDLES; coin->myservices = services; sprintf(dirname,"DB/%s",symbol); OS_ensure_directory(dirname); diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 05c84f667..9f2bc4610 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -20,7 +20,7 @@ typedef int32_t (*blockhashfunc)(uint8_t *blockhashp,uint8_t *serialized,int32_t len); -#define IGUANA_MAXSCRIPTSIZE 8192 +#define IGUANA_MAXSCRIPTSIZE 2048 //#define IGUANA_DISABLEPEERS #define IGUANA_MAXCOINS 64 @@ -33,9 +33,9 @@ typedef int32_t (*blockhashfunc)(uint8_t *blockhashp,uint8_t *serialized,int32_t #define IGUANA_HEIGHT 200 #define IGUANA_MAXPENDHDRS 1 -#define _IGUANA_MAXPENDING 64 //64 +#define _IGUANA_MAXPENDING 1024 //64 #define _IGUANA_MAXBUNDLES 8 -#define IGUANA_BUNDLELOOP 1000 +#define IGUANA_BUNDLELOOP 10 #define IGUANA_RPCPORT 7778 #define IGUANA_MAXRAMCHAINSIZE ((uint64_t)1024L * 1024L * 1024L * 16) @@ -230,7 +230,7 @@ struct iguana_msgblock uint32_t txn_count; } __attribute__((packed)); -struct iguana_msgvin { bits256 prev_hash; uint8_t *sigscript,*spendscript; uint32_t prev_vout,scriptlen,spendlen,sequence; } __attribute__((packed)); +struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*spendscript; uint32_t prev_vout,scriptlen,spendlen,sequence; } __attribute__((packed)); struct iguana_msgvout { uint64_t value; uint32_t pk_scriptlen; uint8_t *pk_script; } __attribute__((packed)); @@ -288,8 +288,9 @@ struct iguana_block //#define IGUANA_LHASH_FIRSTSPENDS 5 // #define IGUANA_LHASH_ACCOUNTS 5 // #define IGUANA_LHASH_EXTERNALS 6 // -#define IGUANA_LHASH_TXBITS 7 // -#define IGUANA_LHASH_PKBITS 8 // +#define IGUANA_LHASH_KSPACE 7 // +#define IGUANA_LHASH_TXBITS 8 // +#define IGUANA_LHASH_PKBITS 9 // #define IGUANA_NUMLHASHES (IGUANA_LHASH_PKBITS + 1) struct iguana_counts @@ -319,15 +320,18 @@ struct iguana_ledger } __attribute__((packed)); // ramchain append only structs -> canonical 32bit inds and ledgerhashes -struct iguana_txid { bits256 txid; uint32_t txidind,firstvout,firstvin,locktime,version,timestamp; uint16_t numvouts,numvins; } __attribute__((packed)); +struct iguana_unspent20 { uint64_t value; uint32_t scriptfpos,txidind:28,type:4; uint16_t scriptlen; uint8_t rmd160[20],script[68]; } __attribute__((packed)); +struct iguana_spend256 { bits256 prevhash2; uint8_t vinscript[108]; uint32_t sequenceid,scriptfpos; int16_t prevout; uint16_t vinscriptlen,spendind; } __attribute__((packed)); -struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; uint16_t hdrsi:12,type:4,vout; } __attribute__((packed)); -struct iguana_unspent20 { uint64_t value; uint32_t txidind:28,type:4; uint8_t rmd160[20]; } __attribute__((packed)); +struct iguana_txid { bits256 txid; uint32_t txidind,firstvout,firstvin,locktime,version,timestamp,extraoffset; uint16_t numvouts,numvins; } __attribute__((packed)); -struct iguana_spend256 { bits256 prevhash2; int16_t prevout; uint16_t spendind:15,diffsequence:1; } __attribute__((packed)); -struct iguana_spend { uint32_t spendtxidind; int16_t prevout; uint16_t tbd:14,external:1,diffsequence:1; } __attribute__((packed)); +struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind,scriptoffset; uint16_t hdrsi:14,type:4,vout:14; } __attribute__((packed)); -struct iguana_pkhash { uint8_t rmd160[20]; uint32_t pkind,firstunspentind,flags:23,type:8,ps2h:1; } __attribute__((packed)); +struct iguana_spend { uint32_t spendtxidind,scriptoffset:31,coinbase:1; int16_t prevout; uint16_t numsigs:4,numpubkeys:4,p2sh:1,sighash:4,external:1,sequenceid:2; } __attribute__((packed)); + +struct iguana_pkhash { uint8_t rmd160[20]; uint32_t pkind,firstunspentind,pubkeyoffset; } __attribute__((packed)); + +struct scriptdata { uint32_t ind:31,spendflag:1; uint16_t hdrsi,scriptlen; }__attribute__((packed)); // dynamic struct iguana_account { uint64_t balance; uint32_t lastunspentind; } __attribute__((packed)); // pkind @@ -349,22 +353,22 @@ struct iguana_ramchaindata { bits256 sha256; bits256 lhashes[IGUANA_NUMLHASHES],firsthash2,lasthash2; - int64_t allocsize,Boffset,Toffset,Uoffset,Soffset,Poffset,Aoffset,Xoffset,TXoffset,PKoffset; + int64_t allocsize,Boffset,Toffset,Uoffset,Soffset,Poffset,Aoffset,Xoffset,TXoffset,PKoffset,Koffset; int32_t numblocks,height,firsti,hdrsi,txsparsebits,pksparsebits; - uint32_t numtxids,numunspents,numspends,numpkinds,numexternaltxids,numtxsparse,numpksparse; + uint32_t numtxids,numunspents,numspends,numpkinds,numexternaltxids,numtxsparse,numpksparse,scriptspace,stacksize; uint8_t rdata[]; }; struct iguana_ramchain_hdr { - uint32_t txidind,unspentind,spendind; uint16_t hdrsi,bundlei:15,ROflag:1; + uint32_t txidind,unspentind,spendind,scriptoffset,stacksize; uint16_t hdrsi,bundlei:15,ROflag:1; struct iguana_ramchaindata *data; }; struct iguana_ramchain { struct iguana_ramchain_hdr H; bits256 lasthash2; uint64_t datasize; - uint32_t numblocks:31,expanded:1,pkind,externalind,height; + uint32_t numblocks:31,expanded:1,pkind,externalind,scriptoffset,height; struct iguana_kvitem *txids,*pkhashes; struct OS_memspace *hashmem; long filesize; void *fileptr; struct iguana_account *A,*roA; struct iguana_Uextra *spents; @@ -409,7 +413,7 @@ struct iguana_bloom16 { uint8_t hash2bits[65536 / 8]; }; struct iguana_bundle { struct queueitem DL; struct iguana_info *coin; struct iguana_bundle *nextbp; - struct iguana_bloom16 bloom; + struct iguana_bloom16 bloom; uint32_t rawscriptspace; uint32_t issuetime,hdrtime,emitfinish,mergefinish,purgetime,queued; int32_t numhashes,numrecv,numsaved,numcached; int32_t minrequests,n,hdrsi,bundleheight,numtxids,numspends,numunspents,numspec; @@ -435,9 +439,11 @@ struct iguana_waddress { UT_hash_handle hh; uint8_t rmd160[20],type,pubkey[33],w struct iguana_waccount { UT_hash_handle hh; char account[128]; struct iguana_waddress *waddrs; }; struct iguana_wallet { UT_hash_handle hh; struct iguana_waccount *waccts; }; +struct scriptinfo { UT_hash_handle hh; uint32_t fpos; uint16_t scriptlen; uint8_t script[]; }; + struct iguana_info { - char name[64],symbol[8],statusstr[512]; + char name[64],symbol[8],statusstr[512],scriptsfname[2][512]; struct iguana_peers peers; uint64_t instance_nonce,myservices,totalsize,totalrecv,totalpackets,sleeptime; int64_t mining,totalfees,TMPallocated,MAXRECVCACHE,MAXMEM,estsize,activebundles; @@ -460,6 +466,8 @@ struct iguana_info queue_t acceptQ,bundlesQ,hdrsQ,blocksQ,priorityQ,possibleQ,TerminateQ,cacheQ; double parsemillis,avetime; uint32_t Launched[8],Terminated[8]; portable_mutex_t peers_mutex,blocks_mutex; + portable_mutex_t scripts_mutex[2]; FILE *scriptsfp[2]; void *scriptsptr[2]; long scriptsfilesize[2]; + struct scriptinfo *scriptstable[2]; struct iguana_bundle *bundles[IGUANA_MAXBUNDLES]; int32_t numremain,numpendings,zcount,recvcount,bcount,pcount,lastbundle; uint32_t recvtime,hdrstime,backstoptime,lastbundletime,numreqsent,numbundlesQ,lastbundleitime; @@ -681,7 +689,7 @@ struct iguana_agent int32_t iguana_txbytes(struct iguana_info *coin,uint8_t *serialized,int32_t maxlen,bits256 *txidp,struct iguana_txid *tx,int32_t height,struct iguana_msgvin *vins,struct iguana_msgvout *vouts); void iguana_vinset(struct iguana_info *coin,int32_t height,struct iguana_msgvin *vin,struct iguana_txid *tx,int32_t i); int32_t iguana_voutset(struct iguana_info *coin,uint8_t *scriptspace,char *asmstr,int32_t height,struct iguana_msgvout *vout,struct iguana_txid *tx,int32_t i); -int32_t btc_convrmd160(char *coinaddr,uint8_t addrtype,uint8_t rmd160[20]); +//int32_t btc_convrmd160(char *coinaddr,uint8_t addrtype,uint8_t rmd160[20]); struct iguana_txid *iguana_bundletx(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei,struct iguana_txid *tx,int32_t txidind); int32_t iguana_txidreq(struct iguana_info *coin,char **retstrp,bits256 txid); void iguana_bundleiclear(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei); @@ -763,8 +771,17 @@ char *issue_startForging(struct supernet_info *myinfo,char *secret); struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,char **retstrp,double *balancep,int32_t *numunspentsp,double minconfirms,char *account); void iguana_chainparms(struct iguana_chain *chain,cJSON *argjson); void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON *txobj,uint32_t sequence); -int32_t iguana_pkhasharray(struct iguana_info *coin,int64_t *totalp,struct iguana_pkhash *P,int32_t max,uint8_t rmd160[20]); +int32_t iguana_pkhasharray(struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,int64_t *totalp,struct iguana_pkhash *P,int32_t max,uint8_t rmd160[20],char *coinaddr,uint8_t *pubkey33); long iguana_spentsfile(struct iguana_info *coin,int32_t n); +uint8_t *iguana_rmdarray(struct iguana_info *coin,int32_t *numrmdsp,cJSON *array,int32_t firsti); +void iguana_unspents(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,uint8_t *rmdarray,int32_t numrmds); +uint8_t *iguana_walletrmds(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *numrmdsp); +char *iguana_bundleaddrs(struct iguana_info *coin,int32_t hdrsi); +long iguana_scriptadd(struct iguana_info *coin,struct iguana_bundle *bp,uint32_t unspentind,int32_t type,uint8_t *spendscript,int32_t spendlen,uint8_t rmd160[20],int32_t vout); +uint32_t iguana_sparseaddpk(uint8_t *bits,int32_t width,uint32_t tablesize,uint8_t rmd160[20],struct iguana_pkhash *P,uint32_t pkind); +long iguana_initscripts(struct iguana_info *coin); +uint32_t iguana_scriptsave(struct iguana_info *coin,struct iguana_bundle *bp,uint32_t ind,int32_t spendflag,uint8_t *script,int32_t scriptlen); +int32_t iguana_vinscriptparse(struct iguana_info *coin,struct vin_info *vp,int32_t *sigsizep,int32_t *pubkeysizep,int32_t *p2shsizep,int32_t *suffixp,uint8_t *vinscript,int32_t scriptlen); extern queue_t bundlesQ; diff --git a/iguana/iguana_blocks.c b/iguana/iguana_blocks.c index 30feeb0cd..2cd45dacf 100755 --- a/iguana/iguana_blocks.c +++ b/iguana/iguana_blocks.c @@ -289,7 +289,7 @@ struct iguana_block *_iguana_chainlink(struct iguana_info *coin,struct iguana_bl } else { - char str[65]; printf("(%s) notready v.%d m.%d h.%d\n",bits256_str(str,prev->RO.hash2),prev->valid,prev->mainchain,prev->height); + //char str[65]; printf("(%s) notready v.%d m.%d h.%d\n",bits256_str(str,prev->RO.hash2),prev->valid,prev->mainchain,prev->height); return(0); } } diff --git a/iguana/iguana_init.c b/iguana/iguana_init.c index 8e8116ecd..7be09ee41 100755 --- a/iguana/iguana_init.c +++ b/iguana/iguana_init.c @@ -52,9 +52,13 @@ void iguana_initpeer(struct iguana_info *coin,struct iguana_peer *addr,uint64_t void iguana_initcoin(struct iguana_info *coin,cJSON *argjson) { - int32_t i; + int32_t i; char dirname[512]; + sprintf(dirname,"tmp/%s",coin->symbol), OS_portable_path(dirname); + OS_portable_rmdir(dirname,0); portable_mutex_init(&coin->peers_mutex); portable_mutex_init(&coin->blocks_mutex); + portable_mutex_init(&coin->scripts_mutex[0]); + portable_mutex_init(&coin->scripts_mutex[1]); iguana_meminit(&coin->blockMEM,"blockMEM",coin->blockspace,sizeof(coin->blockspace),0); iguana_initQs(coin); coin->bindsock = -1; @@ -183,7 +187,7 @@ int32_t iguana_savehdrs(struct iguana_info *coin) void iguana_parseline(struct iguana_info *coin,int32_t iter,FILE *fp) { - int32_t j,k,m,c,height,flag,bundlei; char checkstr[1024],line[1024]; + int32_t i,j,k,m,c,height,flag,bundlei; char checkstr[1024],line[1024]; struct iguana_peer *addr; struct iguana_bundle *bp; bits256 allhash,hash2,zero,lastbundle; struct iguana_block *block; memset(&zero,0,sizeof(zero)); @@ -291,6 +295,17 @@ void iguana_parseline(struct iguana_info *coin,int32_t iter,FILE *fp) printf("req lastbundle.(%s)\n",hashstr); queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1); } + if ( iter == 1 ) + { + for (i=0; ibundlescount; i++) + if ( coin->bundles[i] == 0 ) + break; + if ( i > 0 ) + { + iguana_spentsfile(coin,i); + iguana_initscripts(coin); + } + } } struct iguana_info *iguana_coinstart(struct iguana_info *coin,int32_t initialheight,int32_t mapflags) diff --git a/iguana/iguana_json.c b/iguana/iguana_json.c index 2d7a2bfe6..e6e973bff 100755 --- a/iguana/iguana_json.c +++ b/iguana/iguana_json.c @@ -861,8 +861,8 @@ char *SuperNET_parser(struct supernet_info *myinfo,char *agentstr,char *method,c coinstr = myinfo->rpcsymbol; if ( coinstr != 0 && coinstr[0] != 0 ) coin = iguana_coinfind(coinstr); - if ( strcmp(agentstr,"ramchain") == 0 && coin == 0 ) - return(clonestr("{\"error\":\"ramchain needs coin\"}")); + if ( strcmp(agentstr,"bitcoinrpc") == 0 && coin == 0 ) + return(clonestr("{\"error\":\"bitcoinrpc needs coin\"}")); #define IGUANA_ARGS myinfo,coin,json,remoteaddr #define IGUANA_DISPATCH0(agent,name) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS)) #define IGUANA_DISPATCH_S(agent,name,str) else if ( strcmp(#agent,agentstr) == 0 && strcmp(method,#name) == 0 ) return(agent ## _ ## name(IGUANA_ARGS,jstr(json,#str))) @@ -964,7 +964,7 @@ char *SuperNET_parser(struct supernet_info *myinfo,char *agentstr,char *method,c #include "../includes/iguana_apiundefs.h" - return(clonestr("{\"error\":\"illegal ramchain method or missing coin\"}")); + return(clonestr("{\"error\":\"illegal bitcoinrpc method or missing coin\"}")); } diff --git a/iguana/iguana_msg.c b/iguana/iguana_msg.c index ea8b4898d..ecf40538c 100755 --- a/iguana/iguana_msg.c +++ b/iguana/iguana_msg.c @@ -320,8 +320,8 @@ int32_t iguana_rwvin(int32_t rwflag,struct OS_memspace *mem,uint8_t *serialized, len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout); len += iguana_rwvarint32(rwflag,&serialized[len],&msg->scriptlen); if ( rwflag == 0 ) - msg->sigscript = iguana_memalloc(mem,msg->scriptlen,1); - len += iguana_rwmem(rwflag,&serialized[len],msg->scriptlen,msg->sigscript); + msg->vinscript = iguana_memalloc(mem,msg->scriptlen,1); + len += iguana_rwmem(rwflag,&serialized[len],msg->scriptlen,msg->vinscript); len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence); //char str[65]; printf("MSGvin.(%s/v%d) script[%d]\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->scriptlen); //int i; for (i=0; iscriptlen; i++) diff --git a/iguana/iguana_pubkeys.c b/iguana/iguana_pubkeys.c index 693c63999..cb9742e7e 100755 --- a/iguana/iguana_pubkeys.c +++ b/iguana/iguana_pubkeys.c @@ -604,7 +604,7 @@ int32_t btc_getpubkey(char pubkeystr[67],uint8_t pubkeybuf[33],struct bp_key *ke return((int32_t)len); } -int32_t btc_convrmd160(char *coinaddr,uint8_t addrtype,uint8_t rmd160[20]) +/*int32_t btc_convrmd160(char *coinaddr,uint8_t addrtype,uint8_t rmd160[20]) { cstring *btc_addr; if ( (btc_addr= base58_encode_check(addrtype,true,rmd160,20)) != 0 ) @@ -614,13 +614,14 @@ int32_t btc_convrmd160(char *coinaddr,uint8_t addrtype,uint8_t rmd160[20]) return(0); } return(-1); -} +}*/ int32_t btc_coinaddr(char *coinaddr,uint8_t addrtype,char *pubkeystr) { uint8_t rmd160[20]; char hashstr[41]; calc_OP_HASH160(hashstr,rmd160,pubkeystr); - return(btc_convrmd160(coinaddr,addrtype,rmd160)); + return(bitcoin_address(coinaddr,addrtype,rmd160,20) != 0); + //return(btc_convrmd160(coinaddr,addrtype,rmd160)); } int32_t btc_convaddr(char *hexaddr,char *addr58) @@ -809,7 +810,7 @@ struct iguana_waddress *iguana_waddresscalc(uint8_t pubtype,uint8_t wiftype,stru { memset(addr,0,sizeof(*addr)); addr->privkey = privkey; - if ( btc_priv2pub(addr->pubkey,addr->privkey.bytes) == 0 && btc_priv2wif(addr->wifstr,addr->privkey.bytes,wiftype) == 0 && btc_pub2rmd(addr->rmd160,addr->pubkey) == 0 && btc_convrmd160(addr->coinaddr,pubtype,addr->rmd160) == 0 ) + if ( btc_priv2pub(addr->pubkey,addr->privkey.bytes) == 0 && btc_priv2wif(addr->wifstr,addr->privkey.bytes,wiftype) == 0 && btc_pub2rmd(addr->rmd160,addr->pubkey) == 0 && bitcoin_address(addr->coinaddr,pubtype,addr->rmd160,10) != 0 ) { addr->wiftype = wiftype; addr->type = pubtype; diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index 6e7a84a6d..d5d6d5323 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -21,6 +21,7 @@ //#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 #include "iguana777.h" +#include "exchanges/bitcoin.h" //void iguana_stub(void *ptr,int size) { }//printf("uthash_free ptr.%p %d\n",ptr,size); } #define iguana_hashfind(ramchain,selector,key) iguana_hashsetPT(ramchain,selector,key,0) @@ -225,189 +226,6 @@ struct iguana_txid *iguana_txidfind(struct iguana_info *coin,int32_t *heightp,st return(0); } -struct iguana_pkhash *iguana_pkhashfind(struct iguana_info *coin,struct iguana_ramchain **ramchainp,int64_t *balancep,uint32_t *lastunspentindp,struct iguana_pkhash *p,uint8_t rmd160[20],int32_t firsti,int32_t endi) -{ - uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind,i; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; struct iguana_account *ACCTS; - *balancep = 0; - *ramchainp = 0; - *lastunspentindp = 0; - for (i=firsti; ibundlescount&&i<=endi; i++) - { - if ( (bp= coin->bundles[i]) != 0 ) - { - ramchain = &bp->ramchain; - PKbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->PKoffset); - P = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Poffset); - ACCTS = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Aoffset); - if ( (pkind= iguana_sparseaddpk(PKbits,ramchain->H.data->pksparsebits,ramchain->H.data->numpksparse,rmd160,P,0)) > 0 && pkind < ramchain->H.data->numpkinds ) - { - *ramchainp = ramchain; - *balancep = ACCTS[pkind].balance; - *lastunspentindp = ACCTS[pkind].lastunspentind; - *p = P[pkind]; - return(p); - } - } - } - return(0); -} - -int32_t iguana_spentsinit(struct iguana_info *coin,struct iguana_Uextra *spents,struct iguana_bundle *bp,struct iguana_ramchain *ramchain) -{ - //struct iguana_Uextra { uint32_t spendind; uint16_t hdrsi; } __attribute__((packed)); // unspentind - //struct iguana_spend { uint32_t spendtxidind; int16_t prevout; uint16_t tbd:14,external:1,diffsequence:1; } __attribute__((packed)); - //struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; uint16_t hdrsi:12,type:4,vout; } __attribute__((packed)); - int32_t spendind,n,max,m,prev_vout,height,hdrsi,errs,flag; uint32_t sequenceid,unspentind; - struct iguana_bundle *spentbp; char str[65]; - struct iguana_spend *S,*s; struct iguana_txid *T,TX,*tp,*nextT; bits256 *X; bits256 prev_hash; - S = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Soffset); - X = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Xoffset); - T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); - max = ramchain->H.data->numunspents; - n = ramchain->H.data->numspends; - nextT = &T[1]; - for (spendind=1,errs=m=0; spendindhdrsi; - s = &S[spendind]; - if ( s->diffsequence == 0 ) - sequenceid = 0xffffffff; - if ( s->prevout < 0 ) - { - //printf("n.%d coinbase at spendind.%d firstvin.%d -> firstvout.%d -> unspentind\n",m,spendind,nextT->firstvin,nextT->firstvout); - nextT++; - m++; - continue; - unspentind = nextT->firstvout; - prev_vout = -1; - } - else - { - prev_vout = s->prevout; - iguana_ramchain_spendtxid(coin,&unspentind,&prev_hash,T,ramchain->H.data->numtxids,X,ramchain->H.data->numexternaltxids,s); - if ( unspentind == 0 ) - { - if ( (tp= iguana_txidfind(coin,&height,&TX,prev_hash)) != 0 ) - { - unspentind = TX.firstvout + ((prev_vout > 0) ? prev_vout : 0); - hdrsi = height / coin->chain->bundlesize; - //printf("height.%d firstvout.%d prev.%d ->U%d\n",height,TX.firstvout,prev_vout,unspentind); - } - else - { - printf("cant find prev_hash.(%s) for bp.[%d] spendind.%d\n",bits256_str(str,prev_hash),bp->hdrsi,spendind); - } - } else hdrsi = bp->hdrsi; - } - if ( hdrsi > bp->hdrsi || (spentbp= coin->bundles[hdrsi]) == 0 ) - printf("illegal hdrsi.%d when [%d] spentbp.%p\n",hdrsi,bp->hdrsi,spentbp), getchar(); - else if ( spentbp->ramchain.spents[unspentind].spendind != 0 || hdrsi < 0 ) - printf("DOUBLE SPEND? U%d %p bp.[%d] unspentind.%u already has %u, no room for %u\n",unspentind,&spentbp->ramchain.spents[unspentind],hdrsi,unspentind,spentbp->ramchain.spents[unspentind].spendind,spendind), getchar(); - else if ( unspentind == 0 || unspentind >= spentbp->ramchain.H.data->numunspents ) - printf("illegal unspentind.%d vs max.%d spentbp.%p[%d]\n",unspentind,spentbp->ramchain.H.data->numunspents,spentbp,hdrsi), getchar(); - else - { - spentbp->ramchain.spents[unspentind].spendind = spendind; - spentbp->ramchain.spents[unspentind].hdrsi = bp->hdrsi; - //printf("%p bp.[%d] U%d <- S%d.[%d] [%p %p %p]\n",&spentbp->ramchain.spents[unspentind],hdrsi,unspentind,spendind,bp->hdrsi,coin->bundles[0],coin->bundles[1],coin->bundles[2]); - flag = 1; - } - if ( flag == 0 ) - errs++; - } - printf("processed %d spendinds for bp.[%d] -> errs.%d\n",spendind,bp->hdrsi,errs); - return(-errs); -} - -// if file exists and is valid, load and then process only the incremental -long iguana_spentsfile(struct iguana_info *coin,int32_t n) -{ - int32_t i,iter,allocated = 0; long filesize,total,count; struct iguana_Uextra *spents = 0; struct iguana_ramchain *ramchain; char fname[1024]; struct iguana_bundle *bp; FILE *fp; - fname[0] = 0; - for (total=iter=0; iter<2; iter++) - { - for (count=i=0; ibundles[i]) != 0 ) - { - ramchain = &bp->ramchain; - if ( iter == 1 ) - { - ramchain->spents = &spents[count]; - //printf("bp.[%d] count.%ld %p\n",i,count,ramchain->spents); - if ( allocated != 0 && iguana_spentsinit(coin,spents,bp,ramchain) < 0 ) - { - printf("error initializing spents bp.%d\n",i); - exit(-1); - } - } - count += ramchain->H.data->numunspents; - } else return(-1); - } - sprintf(fname,"DB/%s/spents_%d.%ld",coin->symbol,n,count); - printf("%s total unspents.%ld\n",fname,count); - if ( iter == 0 ) - { - total = count; - if ( (spents= OS_filestr(&filesize,fname)) == 0 ) - spents = calloc(total,sizeof(*spents)), allocated = 1; - } - else if ( total != count ) - printf("%s total.%ld != count.%ld\n",fname,total,count); - } - if ( allocated != 0 && fname[0] != 0 && (fp= fopen(fname,"wb")) != 0 ) - { - fwrite(spents,total,sizeof(*spents),fp); - fclose(fp); - } - return(total); -} - -int64_t iguana_pkhashbalance(struct iguana_info *coin,int64_t *spentp,int32_t *nump,struct iguana_ramchain *ramchain,struct iguana_pkhash *p,uint32_t lastunspentind) -{ - struct iguana_unspent *U; struct iguana_txid *T; uint64_t unspentind; int64_t balance = 0; - *spentp = *nump = 0; - unspentind = lastunspentind; - U = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Uoffset); - T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); - while ( unspentind > 0 ) - { - (*nump)++; - if ( ramchain->spents[unspentind].spendind == 0 ) - balance += U[unspentind].value; - else (*spentp) += U[unspentind].value; - if ( unspentind == p->firstunspentind ) - break; - unspentind = U[unspentind].prevunspentind; - } - return(balance); -} - -int32_t iguana_pkhasharray(struct iguana_info *coin,int64_t *totalp,struct iguana_pkhash *P,int32_t max,uint8_t rmd160[20]) -{ - int32_t i,n,m; int64_t spent,balance,netbalance,total; uint32_t lastunspentind; struct iguana_ramchain *ramchain; - for (total=i=n=0; ibundlescount; i++) - { - if ( iguana_pkhashfind(coin,&ramchain,&balance,&lastunspentind,&P[n],rmd160,i,i) != 0 ) - { - if ( (netbalance= iguana_pkhashbalance(coin,&spent,&m,ramchain,&P[n],lastunspentind)) != balance-spent ) - { - printf("pkhash balance mismatch from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",m,dstr(netbalance),dstr(balance),dstr(spent),dstr(balance)-dstr(spent)); - } - else - { - P[n].firstunspentind = lastunspentind; - P[n].flags = m; - total += netbalance; - n++; - } - } - } - *totalp = total; - return(n); -} - int32_t iguana_peerfname(struct iguana_info *coin,int32_t *hdrsip,char *dirname,char *fname,uint32_t ipbits,bits256 hash2,bits256 prevhash2,int32_t numblocks) { struct iguana_bundle *bp = 0; int32_t bundlei = -2; char str[65]; @@ -441,18 +259,18 @@ int32_t iguana_peerfile_exists(struct iguana_info *coin,struct iguana_peer *addr return(bundlei); } -#define RAMCHAIN_FUNC struct iguana_ramchain *ramchain,struct iguana_blockRO *B,struct iguana_txid *T,struct iguana_unspent20 *U,struct iguana_spend256 *S,struct iguana_pkhash *P,struct iguana_account *A,bits256 *X,struct iguana_unspent *Ux,struct iguana_spend *Sx,uint8_t *TXbits,uint8_t *PKbits -#define RAMCHAIN_PTRPS struct iguana_ramchain *ramchain,struct iguana_blockRO **B,struct iguana_txid **T,struct iguana_unspent20 **U,struct iguana_spend256 **S,struct iguana_pkhash **P,struct iguana_account **A,bits256 **X,struct iguana_unspent **Ux,struct iguana_spend **Sx,uint8_t **TXbits,uint8_t **PKbits +#define RAMCHAIN_FUNC struct iguana_ramchain *ramchain,struct iguana_blockRO *B,struct iguana_txid *T,struct iguana_unspent20 *U,struct iguana_spend256 *S,struct iguana_pkhash *P,struct iguana_account *A,bits256 *X,struct iguana_unspent *Ux,struct iguana_spend *Sx,uint8_t *TXbits,uint8_t *PKbits,uint8_t *Kspace +#define RAMCHAIN_PTRPS struct iguana_ramchain *ramchain,struct iguana_blockRO **B,struct iguana_txid **T,struct iguana_unspent20 **U,struct iguana_spend256 **S,struct iguana_pkhash **P,struct iguana_account **A,bits256 **X,struct iguana_unspent **Ux,struct iguana_spend **Sx,uint8_t **TXbits,uint8_t **PKbits,uint8_t **Kspace -#define _RAMCHAIN_ARG B,T,U,S,P,A,X,Ux,Sx,TXbits,PKbits +#define _RAMCHAIN_ARG B,T,U,S,P,A,X,Ux,Sx,TXbits,PKbits,Kspace #define RAMCHAIN_ARG ramchain,_RAMCHAIN_ARG #define MAPCHAIN_ARG mapchain,_RAMCHAIN_ARG -#define RAMCHAIN_PTRS ramchain,&B,&T,&U,&S,&P,&A,&X,&Ux,&Sx,&TXbits,&PKbits -#define RAMCHAIN_DECLARE struct iguana_blockRO *B; struct iguana_txid *T; struct iguana_unspent20 *U; struct iguana_spend256 *S; struct iguana_pkhash *P; struct iguana_account *A; bits256 *X; struct iguana_unspent *Ux; struct iguana_spend *Sx; uint8_t *TXbits,*PKbits; +#define RAMCHAIN_PTRS ramchain,&B,&T,&U,&S,&P,&A,&X,&Ux,&Sx,&TXbits,&PKbits,&Kspace +#define RAMCHAIN_DECLARE struct iguana_blockRO *B; struct iguana_txid *T; struct iguana_unspent20 *U; struct iguana_spend256 *S; struct iguana_pkhash *P; struct iguana_account *A; bits256 *X; struct iguana_unspent *Ux; struct iguana_spend *Sx; uint8_t *TXbits,*PKbits,*Kspace; -#define RAMCHAIN_DESTARG dest,destB,destT,destU,destS,destP,destA,destX,destUx,destSx,destTXbits,destPKbits -#define RAMCHAIN_DESTPTRS dest,&destB,&destT,&destU,&destS,&destP,&destA,&destX,&destUx,&destSx,&destTXbits,&destPKbits -#define RAMCHAIN_DESTDECLARE struct iguana_blockRO *destB; struct iguana_txid *destT; struct iguana_unspent20 *destU; struct iguana_spend256 *destS; struct iguana_pkhash *destP; struct iguana_account *destA; bits256 *destX; struct iguana_unspent *destUx; struct iguana_spend *destSx; uint8_t *destTXbits,*destPKbits; +#define RAMCHAIN_DESTARG dest,destB,destT,destU,destS,destP,destA,destX,destUx,destSx,destTXbits,destPKbits,destKspace +#define RAMCHAIN_DESTPTRS dest,&destB,&destT,&destU,&destS,&destP,&destA,&destX,&destUx,&destSx,&destTXbits,&destPKbits,&destKspace +#define RAMCHAIN_DESTDECLARE struct iguana_blockRO *destB; struct iguana_txid *destT; struct iguana_unspent20 *destU; struct iguana_spend256 *destS; struct iguana_pkhash *destP; struct iguana_account *destA; bits256 *destX; struct iguana_unspent *destUx; struct iguana_spend *destSx; uint8_t *destTXbits,*destPKbits,*destKspace; uint32_t iguana_ramchain_addtxid(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 txid,int32_t numvouts,int32_t numvins,uint32_t locktime,uint32_t version,uint32_t timestamp) { @@ -464,14 +282,14 @@ uint32_t iguana_ramchain_addtxid(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 if ( t->txidind != txidind || memcmp(t->txid.bytes,txid.bytes,sizeof(bits256)) != 0 || t->numvouts != numvouts || t->numvins != numvins || t->firstvout != ramchain->H.unspentind || t->firstvin != ramchain->H.spendind || t->locktime != locktime || t->version != version || t->timestamp != timestamp ) { printf("iguana_ramchain_addtxid: addtxid mismatch (%d %d %d %d %d) vs. (%d %d %d %d %d)\n",t->txidind,t->numvouts,t->numvins,t->firstvout,t->firstvin,txidind,numvouts,numvins,ramchain->H.unspentind,ramchain->H.spendind); - exit(-1); + getchar(); return(0); } } else { - //if ( ramchain->expanded != 0 ) - // printf("T.%p txidind.%d numvouts.%d numvins.%d\n",T,txidind,numvouts,numvins); + if ( 0 && ramchain->expanded != 0 ) + printf("T.%p txidind.%d numvouts.%d numvins.%d\n",T,txidind,numvouts,numvins); t->txidind = txidind, t->txid = txid, t->numvouts = numvouts, t->numvins = numvins; t->firstvout = ramchain->H.unspentind, t->firstvin = ramchain->H.spendind; t->locktime = locktime, t->version = version, t->timestamp = timestamp; @@ -491,7 +309,7 @@ uint32_t iguana_ramchain_addtxid(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 return(txidind); } -uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_t rmd160[20],int32_t flags,uint32_t unspentind) +uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_t *rmd160,int32_t pubkeyind,uint32_t unspentind) { struct iguana_kvitem *ptr; uint32_t pkind = 0; if ( ramchain->expanded != 0 && (ptr= iguana_hashfind(ramchain,'P',rmd160)) == 0 ) @@ -499,9 +317,9 @@ uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_ pkind = ramchain->pkind++; if ( ramchain->H.ROflag != 0 ) { - if ( P[pkind].flags != flags || P[pkind].firstunspentind != unspentind || P[pkind].pkind != pkind ) + if ( unspentind != 0 && (P[pkind].firstunspentind != unspentind || P[pkind].pkind != pkind) ) //P[pkind].pubkeyind != pubkeyind || { - printf("iguana_ramchain_addpkhash pkind.%d vs %d error mismatched flags.(%x %x) firstunspentind.%x vs %x\n",pkind,P[pkind].pkind,P[pkind].flags,flags,P[pkind].firstunspentind,unspentind); + printf("iguana_ramchain_addpkhash error mismatched pubind.(%x %x) firstunspentind.%x vs %x\n",pkind,P[pkind].pkind,P[pkind].firstunspentind,unspentind); exit(-1); return(0); } @@ -513,7 +331,8 @@ uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_ } else { - P[pkind].flags = flags; + //struct iguana_pkhash { uint8_t rmd160[32]; uint32_t pkind,firstunspentind,flags:20,odd:1,pk33:1,type:8,ps2h:1; } __attribute__((packed)); + //P[pkind].pubkeyind = iguana_pubkeyind(pubkey); P[pkind].pkind = pkind; P[pkind].firstunspentind = unspentind; //printf("%p P[%d] <- firstunspent.%d\n",&P[pkind],pkind,unspentind); @@ -530,23 +349,39 @@ uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_ return(pkind); } -uint32_t iguana_ramchain_addunspent20(struct iguana_info *coin,RAMCHAIN_FUNC,uint64_t value,uint8_t *script,int32_t scriptlen,bits256 txid,int32_t vout,uint8_t type) +uint32_t iguana_ramchain_addunspent20(struct iguana_info *coin,RAMCHAIN_FUNC,uint64_t value,uint8_t *script,int32_t scriptlen,bits256 txid,int32_t vout,int8_t type,struct iguana_bundle *bp,uint8_t rmd160[20]) { - //struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; } __attribute__((packed)); uint32_t unspentind; struct iguana_unspent20 *u; struct vin_info V; unspentind = ramchain->H.unspentind++; u = &U[unspentind]; - if ( scriptlen == -20 ) - memcpy(V.rmd160,script,20); - else + if ( scriptlen > 0 ) { memset(&V,0,sizeof(V)); - type = iguana_calcrmd160(coin,&V,script,scriptlen,txid,vout,0xffffffff); + if ( type < 0 ) + { + type = iguana_calcrmd160(coin,&V,script,scriptlen,txid,vout,0xffffffff); + memcpy(rmd160,V.rmd160,sizeof(V.rmd160)); + } //else printf("iguana_ramchain_addunspent20: unexpected non-neg type.%d\n",type); } if ( ramchain->H.ROflag != 0 ) { //printf("%p U[%d] txidind.%d pkind.%d\n",u,unspentind,ramchain->txidind,pkind); - if ( u->txidind != ramchain->H.txidind || u->value != value || memcmp(u->rmd160,V.rmd160,sizeof(V.rmd160)) != 0 ) + if ( u->scriptlen > 0 && u->scriptlen <= sizeof(u->script) ) + { + if ( memcmp(script,u->script,u->scriptlen) != 0 ) + { + int32_t i; + for (i=0; iscriptlen; i++) + printf("%02x",u->script[i]); + printf(" u->script\n"); + for (i=0; iscriptlen; i++) + printf("%02x",script[i]); + printf(" script\n"); + printf("[%d] u%d script compare error.%d vs %d\n",bp->hdrsi,unspentind,scriptlen,u->scriptlen); + //return(0); + } //else printf("SCRIPT.%d MATCHED!\n",u->scriptlen); + } // else would need to get from HDD to verify + if ( u->txidind != ramchain->H.txidind || u->value != value || memcmp(u->rmd160,rmd160,sizeof(u->rmd160)) != 0 ) { printf("iguana_ramchain_addunspent20: mismatched values.(%.8f %d) vs (%.8f %d)\n",dstr(u->value),u->txidind,dstr(value),ramchain->H.txidind); return(0); @@ -556,15 +391,124 @@ uint32_t iguana_ramchain_addunspent20(struct iguana_info *coin,RAMCHAIN_FUNC,uin { u->value = value; u->type = type; + u->scriptfpos = 0; + if ( (u->scriptlen= scriptlen) != 0 ) + { + if ( scriptlen <= sizeof(u->script) ) + memcpy(u->script,script,scriptlen); + else + { + memset(&V,0,sizeof(V)); + if ( type != 0 ) // IGUANA_SCRIPT_NULL + { + u->scriptfpos = (uint32_t)iguana_scriptadd(coin,bp,unspentind,type,script,scriptlen,rmd160,vout); + } + } + } u->txidind = ramchain->H.txidind; - memcpy(u->rmd160,V.rmd160,sizeof(V.rmd160)); + memcpy(u->rmd160,rmd160,sizeof(u->rmd160)); } return(unspentind); } -uint32_t iguana_ramchain_addunspent(struct iguana_info *coin,RAMCHAIN_FUNC,uint64_t value,uint16_t hdrsi,uint8_t *rmd160,uint16_t vout,uint8_t type) +uint32_t iguana_ramchain_scriptencode(struct iguana_info *coin,int32_t *lenp,uint8_t *Kspace,uint32_t offset,int32_t type,uint8_t *script,int32_t scriptlen,uint32_t *pubkeyoffsetp) +{ + uint32_t i,uoffset,plen,pubkeyoffset = *pubkeyoffsetp; uint8_t script76AC[128]; + if ( type == IGUANA_SCRIPT_76AC ) + { + plen = bitcoin_pubkeylen(script+1); + if ( pubkeyoffset == 0 ) + { + if ( offset == 0 ) + offset = 1; + *pubkeyoffsetp = pubkeyoffset = offset; + memcpy(&Kspace[pubkeyoffset],script+1,plen); + offset += plen; + for (i=0; i pubkeyoffset.%d\n",pubkeyoffset); + } + if ( memcmp(script+1,&Kspace[pubkeyoffset],plen) != 0 ) + { + for (i=0; i> 8) & 0xff; + Kspace[offset+1] = scriptlen & 0xff; + Kspace[offset+2] = 0xfd; + offset += 3; + } + uoffset = offset; + memcpy(&Kspace[uoffset],script,scriptlen); + (*lenp) = (offset + scriptlen); + return(uoffset); +} + +uint8_t *iguana_ramchain_scriptdecode(struct iguana_info *coin,int32_t *scriptlenp,uint8_t *Kspace,int32_t type,uint8_t _script[IGUANA_MAXSCRIPTSIZE],uint32_t uoffset,uint32_t pubkeyoffset) +{ + uint32_t plen,len = 0; int32_t scriptlen; + if ( (scriptlen= Kspace[uoffset-1]) >= 0xfd ) + scriptlen = (Kspace[uoffset-3] + ((int32_t)Kspace[uoffset-2] << 8)), len = 3; + else len = 1; + if ( type == IGUANA_SCRIPT_76AC && pubkeyoffset != 0 ) + { + plen = bitcoin_pubkeylen(&Kspace[pubkeyoffset]); + _script[0] = 0x76; + memcpy(&_script[1],&Kspace[pubkeyoffset],plen); + _script[plen + 1] = 0xac; + *scriptlenp = plen + 2; + return(_script); + } + *scriptlenp = scriptlen; + return(&Kspace[uoffset]); +} + +uint32_t iguana_ramchain_pubkeyoffset(struct iguana_info *coin,RAMCHAIN_FUNC,int32_t createflag,uint32_t *scriptoffsetp,uint8_t *pubkey,uint8_t rmd160[20]) { - uint32_t unspentind; struct iguana_unspent *u; struct iguana_kvitem *ptr; int32_t pkind; + uint32_t pkind,plen; struct iguana_kvitem *ptr; + if ( (ptr= iguana_hashfind(ramchain,'P',rmd160)) == 0 ) + { + if ( createflag != 0 ) + pkind = iguana_ramchain_addpkhash(coin,RAMCHAIN_ARG,rmd160,0,0); + else return(0); + } + else pkind = ptr->hh.itemind; + if ( P[pkind].pubkeyoffset == 0 ) + { + if ( (plen= bitcoin_pubkeylen(pubkey)) > 0 ) + { + P[pkind].pubkeyoffset = *scriptoffsetp, *scriptoffsetp += plen; + printf("plen.%d -> new offse.%d\n",plen,*scriptoffsetp); + memcpy(&Kspace[P[pkind].pubkeyoffset],pubkey,plen); + } + else + { + printf("iguana_ramchain_pubkeyoffset: illegal pubkey?\n"); + return(0); + } + } + return(P[pkind].pubkeyoffset); +} + +uint32_t iguana_ramchain_addunspent(struct iguana_info *coin,RAMCHAIN_FUNC,uint64_t value,uint16_t hdrsi,uint8_t *rmd160,uint16_t vout,uint8_t type,uint8_t *script,int32_t scriptlen) +{ + uint32_t unspentind,pubkeyoffset; struct iguana_unspent *u; struct iguana_kvitem *ptr; int32_t len,pkind,checklen; uint8_t _script[IGUANA_MAXSCRIPTSIZE],*checkscript; unspentind = ramchain->H.unspentind++; u = &Ux[unspentind]; if ( (ptr= iguana_hashfind(ramchain,'P',rmd160)) == 0 ) @@ -574,7 +518,17 @@ uint32_t iguana_ramchain_addunspent(struct iguana_info *coin,RAMCHAIN_FUNC,uint6 return(0); if ( ramchain->H.ROflag != 0 ) { + //printf("RO [%d] u%d offset.%u len.%d\n",hdrsi,unspentind,u->scriptoffset,scriptlen); //printf("%p U[%d] txidind.%d pkind.%d\n",u,unspentind,ramchain->txidind,pkind); + if ( Kspace != 0 && u->scriptoffset != 0 && scriptlen > 0 ) + { + checkscript = iguana_ramchain_scriptdecode(coin,&checklen,Kspace,u->type,_script,u->scriptoffset,P[pkind].pubkeyoffset < ramchain->H.scriptoffset ? P[pkind].pubkeyoffset : 0); + if ( checklen != scriptlen || memcmp(checkscript,script,scriptlen) != 0 ) + { + printf("script mismatch len.%d vs %d or cmp error.%d\n",scriptlen,checklen,memcmp(checkscript,script,scriptlen)); + } else printf("RO spendscript match.%d\n",scriptlen); + ramchain->H.scriptoffset += scriptlen + 1 + (scriptlen >= 0xfd)*2; + } if ( u->value != value || u->pkind != pkind || u->value != value || u->txidind != ramchain->H.txidind || (pkind != 0 && u->prevunspentind != A[pkind].lastunspentind) || u->vout != vout || u->hdrsi != hdrsi ) { printf("iguana_ramchain_addunspent: mismatched values.(%d %.8f %d %d %d %d) vs (%d %.8f %d %d %d %d)\n",u->pkind,dstr(u->value),u->txidind,u->prevunspentind,u->vout,u->hdrsi,pkind,dstr(value),ramchain->H.txidind,A[pkind].lastunspentind,vout,hdrsi); @@ -585,10 +539,35 @@ uint32_t iguana_ramchain_addunspent(struct iguana_info *coin,RAMCHAIN_FUNC,uint6 else { u->value = value; - u->type = type; + if ( (u->type= type) == IGUANA_SCRIPT_76AC ) + pubkeyoffset = P[pkind].pubkeyoffset; + else pubkeyoffset = 0; u->vout = vout, u->hdrsi = hdrsi; u->txidind = ramchain->H.txidind, u->pkind = pkind; u->prevunspentind = A[pkind].lastunspentind; + printf("scriptoffset.%d\n",ramchain->H.scriptoffset); + if ( scriptlen > 0 && script != 0 ) + { + //int32_t i; for (i=0; iH.scriptoffset+scriptlen+3 <= ramchain->H.data->scriptspace ) + { + if ( (u->scriptoffset= iguana_ramchain_scriptencode(coin,&len,Kspace,ramchain->H.scriptoffset,type,script,scriptlen,&pubkeyoffset)) > 0 ) + { + ramchain->H.scriptoffset = len; + printf("new offset.%d from len.%d\n",ramchain->H.scriptoffset,len); + if ( type == IGUANA_SCRIPT_76AC ) + { + P[pkind].pubkeyoffset = pubkeyoffset; + int32_t i; for (i=0; i<33; i++) + printf("%02x",Kspace[P[pkind].pubkeyoffset+i]); + printf(" set pubkey.[%d] <- scriptoffset.%d\n",pkind,P[pkind].pubkeyoffset); + } + } + //printf("[%d] u%d offset.%u len.%d\n",hdrsi,unspentind,u->scriptoffset,scriptlen); + } else printf("[%d] u%d Kspace.%p scriptspace overflow! %d + %d vs space.%d\n",hdrsi,unspentind,Kspace,ramchain->H.scriptoffset,scriptlen,ramchain->H.data->scriptspace); + } } //printf("%p A[%d] last <- U%d\n",&A[pkind],pkind,unspentind); A[pkind].balance += value; @@ -596,34 +575,6 @@ uint32_t iguana_ramchain_addunspent(struct iguana_info *coin,RAMCHAIN_FUNC,uint6 return(unspentind); } -uint32_t iguana_ramchain_addspend256(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 prev_hash,int32_t prev_vout,uint8_t *script,int32_t scriptlen,uint32_t sequence)//,int32_t hdrsi,int32_t bundlei) -{ - struct iguana_spend256 *s; uint32_t spendind; - spendind = ramchain->H.spendind++; - s = &S[spendind]; - if ( ramchain->H.ROflag != 0 ) - { - if ( (s->diffsequence == 0 && sequence != 0xffffffff) || (s->diffsequence != 0 && sequence == 0xffffffff) || memcmp(s->prevhash2.bytes,prev_hash.bytes,sizeof(bits256)) != 0 || s->prevout != prev_vout ) //|| s->hdrsi != hdrsi - { - char str[65],str2[65]; printf("check addspend.%d v %d RO value mismatch diffseq.%d seq.%x prev_vout(%d vs %d) %s vs %s\n",spendind,s->spendind,s->diffsequence,sequence,s->prevout,prev_vout,bits256_str(str,s->prevhash2),bits256_str(str2,prev_hash)); - //printf("check addspend.%d vs %d RO value mismatch (%d %d:%d) vs (%d %d:%d)\n",spendind,s->spendind,s->prevout,s->hdrsi,s->bundlei,prev_vout,hdrsi,bundlei); - exit(-1); - return(0); - } - //printf(" READ.%p spendind.%d vs %d prevout.%d hdrsi.%d:%d\n",s,spendind,s->spendind,s->prevout,s->hdrsi,s->bundlei); - } - else - { - if ( sequence != 0xffffffff ) - s->diffsequence = 1; - s->prevhash2 = prev_hash, s->prevout = prev_vout; - //s->hdrsi = hdrsi, s->bundlei = bundlei; - s->spendind = spendind; - //char str[65]; printf("W.%p s.%d vout.%d/%d %d:%d %s\n",s,spendind,s->prevout,prev_vout,s->hdrsi,s->bundlei,bits256_str(str,prev_hash)); - } - return(spendind); -} - int32_t iguana_ramchain_spendtxid(struct iguana_info *coin,uint32_t *unspentindp,bits256 *txidp,struct iguana_txid *T,int32_t numtxids,bits256 *X,int32_t numexternaltxids,struct iguana_spend *s) { uint32_t ind,external; @@ -674,10 +625,139 @@ int32_t iguana_ramchain_txid(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 *txi return(-2); } -uint32_t iguana_ramchain_addspend(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 prev_hash,int32_t prev_vout,uint32_t sequence,int32_t hdrsi) +int32_t iguana_scriptvarlen(uint8_t *script,int32_t scriptlen,int32_t len) +{ + if ( (script[scriptlen]= len) >= 0xfd ) + { + script[scriptlen++] = 0xfd; + script[scriptlen++] = (len & 0xff); + script[scriptlen++] = (len >> 8) & 0xff; + } else scriptlen++; + return(scriptlen); +} + +int32_t iguana_scriptgetvarlen(int32_t *lenp,uint8_t *script) { - struct iguana_spend *s; struct iguana_kvitem *ptr; bits256 txid; - uint32_t spendind,unspentind,txidind,pkind,external; uint64_t value = 0; + int32_t offset = 0; + if ( (*lenp= script[offset++]) >= 0xfd ) + { + *lenp = script[offset] + ((int32_t)script[offset+1] << 8); + offset += 2; + } + return(offset); +} + +int32_t iguana_spendencode(struct iguana_info *coin,uint8_t *Kstackend,uint32_t stacksize,uint8_t *Kspace,uint32_t scriptoffset,struct iguana_spend *s,uint32_t sequence,uint8_t *sigsbuf,int32_t sigslen,uint32_t *poffsets,uint8_t *p2shscript,int32_t p2shlen,uint8_t *suffix,int32_t suffixlen) +{ + int32_t i,len = 0; long diff; uint8_t metascript[IGUANA_MAXSCRIPTSIZE]; uint32_t origoffset = scriptoffset; + printf("vinencode[%d] <- stacksize.%d sigslen.%d numsigs.%d numpubs.%d p2shlen.%d suffixlen.%d\n",scriptoffset,stacksize,sigslen,s->numsigs,s->numpubkeys,p2shlen,suffixlen); + if ( sigslen == 0 && s->numpubkeys == 0 && p2shlen == 0 && suffixlen == 0 ) + { + printf("spendencode: null script??\n"); + return(0); + } + s->scriptoffset = scriptoffset; + if ( s->sequenceid == 3 ) + memcpy(&metascript[len],&sequence,sizeof(sequence)), len += sizeof(sequence); + len = iguana_scriptvarlen(metascript,len,sigslen); + if ( sigslen > 0 ) + { + diff = (long)Kstackend - (long)Kspace; + printf("Kspace.%p Kstackend.%p diff.%ld stacksize.%d sigsbuf.%p sigslen.%d [%02x]\n",Kspace,Kstackend,diff,stacksize,sigsbuf,sigslen,Kspace[diff - stacksize + sigslen - 1]); + for (i=0; i %p\n",len,&Kspace[diff - stacksize]); + } + if ( s->numpubkeys > 0 ) + { + memcpy(&metascript[len],poffsets,sizeof(*poffsets) * s->numpubkeys), len += sizeof(*poffsets) * s->numpubkeys; + printf("EMIT pubkey.%d len.%d\n",poffsets[0],len); + } + if ( p2shlen != 0 ) + { + len = iguana_scriptvarlen(metascript,len,p2shlen); + memcpy(&metascript[len],p2shscript,p2shlen), len += p2shlen; + } + if ( suffixlen != 0 ) + { + printf("[%d] <- SUFFIX.(%02x) len.%d\n",len,suffix[0],suffixlen); + memcpy(&metascript[len],suffix,suffixlen), len += suffixlen; + } + scriptoffset = iguana_scriptvarlen(Kspace,scriptoffset,len); + memcpy(&Kspace[scriptoffset],metascript,len); + for (i=0; iscriptoffset]; uint32_t poffsets[16]; int32_t totalsize,sigslen,plen,stacksize=0,p2shlen=0,scriptlen = 0; + if ( (*sequenceidp= s->sequenceid) == 3 ) + { + memcpy(sequenceidp,&metascript[len],sizeof(*sequenceidp)); + len += sizeof(*sequenceidp); + } else (*sequenceidp) = -(*sequenceidp); + len += iguana_scriptgetvarlen(&totalsize,&metascript[len]); + if ( totalsize > IGUANA_MAXSCRIPTSIZE ) + { + printf("totalsize too big %d\n",totalsize); + return(0); + } + // expand metascript!! + totalsize += len; + len += iguana_scriptgetvarlen(&sigslen,&metascript[len]); + printf("totalsize %d, len %d sigslen %d\n",totalsize,len,sigslen); + if ( sigslen > 0 && sigslen < totalsize ) + { + memcpy(&stacksize,&metascript[len],sizeof(stacksize)), len += sizeof(stacksize); + diff = (long)Kstackend - (long)Kspace; + memcpy(&_script[scriptlen],&Kspace[diff - stacksize],sigslen), scriptlen += sigslen; + printf("emit.%p from.%ld sigslen.%d [%02x] stacksize.%d\n",&Kspace[diff - stacksize],diff - stacksize,sigslen,Kspace[diff - stacksize + sigslen - 1],stacksize); + } + if ( s->numpubkeys > 0 ) + { + memcpy(poffsets,&metascript[len],sizeof(*poffsets) * s->numpubkeys), len += sizeof(*poffsets) * s->numpubkeys; + for (i=0; inumpubkeys; i++) + { + printf("poffset[%d] of %d poffset %x\n",i,s->numpubkeys,poffsets[i]); + pubkey = &Kspace[poffsets[i]]; + if ( (plen= bitcoin_pubkeylen(pubkey)) <= 0 ) + printf("iguana_vinscriptdecode illegal pubkey.%d\n",i); + else + { + //_script[scriptlen++] = plen; + memcpy(&_script[scriptlen],pubkey,plen), scriptlen += plen; + } + } + } + if ( s->p2sh != 0 ) + { + len += iguana_scriptgetvarlen(&p2shlen,&metascript[len]); + if ( p2shlen <= 75 ) + _script[scriptlen++] = 0x4c, _script[scriptlen++] = p2shlen; + else _script[scriptlen++] = 0x4d, _script[scriptlen++] = p2shlen & 0xff, _script[scriptlen++] = (p2shlen>>8) & 0xff; + memcpy(&_script[scriptlen],&metascript[len],p2shlen), scriptlen += p2shlen; + } + if ( (suffixlen= (totalsize - len)) != 0 ) + memcpy(&_script[scriptlen],&metascript[len],suffixlen), scriptlen += suffixlen; + printf("vindecode[%d] -> stacksize.%d sigslen.%d numsigs.%d numpubs.%d p2shlen.%d suffixlen.%d = %d totalsize.%d len.%d\n",s->scriptoffset,stacksize,sigslen,s->numsigs,s->numpubkeys,p2shlen,suffixlen,scriptlen,totalsize,len); + return(scriptlen); +} + +uint32_t iguana_ramchain_addspend(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 prev_hash,int32_t prev_vout,uint32_t sequence,int32_t hdrsi,uint8_t *vinscript,int32_t vinscriptlen) +{ + struct iguana_spend *s; struct iguana_kvitem *ptr; bits256 txid; struct vin_info V; + uint32_t spendind,unspentind,txidind,pkind,external,poffsets[16],checksequenceid; + uint8_t sigsbuf[16*74],_script[IGUANA_MAXSCRIPTSIZE]; uint64_t value = 0; + int32_t sigsize,pubkeysize,p2shsize,numpubs,numsigs,suffixlen,i,sigslen,checklen; spendind = ramchain->H.spendind++; s = &Sx[spendind]; pkind = unspentind = 0; @@ -720,18 +800,69 @@ uint32_t iguana_ramchain_addspend(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 if ( ramchain->H.ROflag != 0 ) { iguana_ramchain_txid(coin,RAMCHAIN_ARG,&txid,s); - if ( (s->diffsequence == 0 && sequence != 0xffffffff) || (s->diffsequence != 0 && sequence == 0xffffffff) || memcmp(txid.bytes,prev_hash.bytes,sizeof(bits256)) != 0 || s->prevout != prev_vout )// || s->hdrsi != hdrsi + if ( (s->sequenceid == 1 && sequence != 0xffffffff) || (s->sequenceid == 2 && sequence != 0xfffffffe) || memcmp(txid.bytes,prev_hash.bytes,sizeof(bits256)) != 0 || s->prevout != prev_vout ) { - char str[65],str2[65]; printf("ramchain_addspend RO value mismatch diffseq.%d v %x (%d) vs (%d) %s vs %s\n",s->diffsequence,sequence,s->prevout,prev_vout,bits256_str(str,txid),bits256_str(str2,prev_hash)); + char str[65],str2[65]; printf("ramchain_addspend RO value mismatch diffseq.%d v %x (%d) vs (%d) %s vs %s\n",s->sequenceid,sequence,s->prevout,prev_vout,bits256_str(str,txid),bits256_str(str2,prev_hash)); return(0); } } else { - if ( sequence != 0xffffffff ) - s->diffsequence = 1; + // struct iguana_spend { uint32_t spendtxidind,scriptoffset; int16_t prevout; uint16_t numsigs:4,numpubkeys:4,p2sh:1,sighash:4,external:1,sequenceid:2; } __attribute__((packed)); + for (i=0; isequenceid = 1; + else if ( sequence == 0xfffffffe ) + s->sequenceid = 2; + else if ( sequence != 0 ) + s->sequenceid = 3; + else s->sequenceid = 0; s->external = external, s->spendtxidind = txidind, s->prevout = prev_vout; + s->sighash = iguana_vinscriptparse(coin,&V,&sigsize,&pubkeysize,&p2shsize,&suffixlen,vinscript,vinscriptlen); + memset(sigsbuf,0,sizeof(sigsbuf)); + memset(poffsets,0,sizeof(poffsets)); + for (i=numpubs=numsigs=sigslen=0; iH.scriptoffset,V.signers[i].pubkey,V.signers[i].rmd160)) == 0 ) + { + printf("addspend: error couldnt get pubkeyoffset\n"); + } else printf("poffset[%d] <- 0x%x (%02x %02x)\n",i,poffsets[i],Kspace[poffsets[i]],Kspace[poffsets[i]+32]); + numpubs++; + } + if ( V.signers[i].siglen > 0 ) + { + sigsbuf[sigslen++] = V.signers[i].siglen; + memcpy(&sigsbuf[sigslen],V.signers[i].sig,V.signers[i].siglen); + sigslen += V.signers[i].siglen + 1; + numsigs++; + } + } + s->numsigs = numsigs; + s->numpubkeys = numpubs; + if ( p2shsize != 0 ) + s->p2sh = 1; + if ( sigslen+numsigs+numpubs+suffixlen != 0 || s->sequenceid == 3 ) + { + ramchain->H.stacksize += sigslen; + checklen = iguana_spendencode(coin,&Kspace[ramchain->H.data->scriptspace],ramchain->H.stacksize,Kspace,ramchain->H.scriptoffset,s,sequence,sigsbuf,sigslen,poffsets,V.p2shscript,V.p2shlen,&vinscript[vinscriptlen-suffixlen],suffixlen); + ramchain->H.scriptoffset = checklen; + printf("checklen.%d scriptoffset.%d\n",checklen,ramchain->H.scriptoffset); + if ( (checklen= iguana_vinscriptdecode(coin,&checksequenceid,_script,&Kspace[ramchain->H.data->scriptspace],Kspace,s)) != vinscriptlen || memcmp(_script,vinscript,vinscriptlen) != 0 || sequence != checksequenceid ) + { + for (i=0; icoinbase = 1, printf("vin reconstructed\n"); + } //s->hdrsi = hdrsi; //s->bundlei = bundlei; //char str[65]; printf("%s set prevout.%d -> %d\n",bits256_str(str,prev_hash),prev_vout,s->prevout); @@ -748,10 +879,45 @@ uint32_t iguana_ramchain_addspend(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 return(spendind); } -int64_t iguana_hashmemsize(uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids) +uint32_t iguana_ramchain_addspend256(struct iguana_info *coin,RAMCHAIN_FUNC,bits256 prev_hash,int32_t prev_vout,uint8_t *vinscript,int32_t vinscriptlen,uint32_t sequence,struct iguana_bundle *bp) +{ + struct iguana_spend256 *s; uint32_t spendind,scriptfpos = 0; + spendind = ramchain->H.spendind++; + s = &S[spendind]; + if ( vinscriptlen > sizeof(s->vinscript) ) + { + scriptfpos = iguana_scriptsave(coin,bp,spendind,1,vinscript,vinscriptlen); + printf("S%d added sig.%d len.%d %08x\n",spendind,scriptfpos,vinscriptlen,calc_crc32(0,vinscript,vinscriptlen)); + } + if ( ramchain->H.ROflag != 0 ) + { + if ( vinscriptlen != s->vinscriptlen || (s->sequenceid == 1 && sequence != 0xffffffff) || (s->sequenceid == 2 && sequence != 0xfffffffe) || memcmp(s->prevhash2.bytes,prev_hash.bytes,sizeof(bits256)) != 0 || s->prevout != prev_vout ) //|| s->hdrsi != hdrsi + { + char str[65],str2[65]; printf("check (%d %d) (%d %d) addspend.%d v %d RO value mismatch sequenceid.%x seq.%x prev_vout(%d vs %d) %s vs %s\n",scriptfpos,s->scriptfpos,vinscriptlen,s->vinscriptlen,spendind,s->spendind,s->sequenceid,sequence,s->prevout,prev_vout,bits256_str(str,s->prevhash2),bits256_str(str2,prev_hash)); + //printf("check addspend.%d vs %d RO value mismatch (%d %d:%d) vs (%d %d:%d)\n",spendind,s->spendind,s->prevout,s->hdrsi,s->bundlei,prev_vout,hdrsi,bundlei); + exit(-1); + return(0); + } + //printf(" READ.%p spendind.%d vs %d prevout.%d hdrsi.%d:%d\n",s,spendind,s->spendind,s->prevout,s->hdrsi,s->bundlei); + } + else + { + s->sequenceid = sequence; + s->prevhash2 = prev_hash, s->prevout = prev_vout; + s->spendind = spendind; + s->scriptfpos = scriptfpos; + if ( (s->vinscriptlen= vinscriptlen) > 0 && vinscriptlen <= sizeof(s->vinscript) && scriptfpos == 0 ) + memcpy(s->vinscript,vinscript,vinscriptlen); + else printf("spend256 scriptfpos.%d\n",s->scriptfpos); + //char str[65]; printf("W.%p s.%d vout.%d/%d [%d] %s fpos.%u slen.%d\n",s,spendind,s->prevout,prev_vout,bp->hdrsi,bits256_str(str,prev_hash),s->scriptfpos,s->vinscriptlen); + } + return(spendind); +} + +int64_t iguana_hashmemsize(uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids,int32_t scriptspace) { int64_t allocsize = 0; - allocsize += (65536*4 + ((numtxids + numpkinds) * (sizeof(UT_hash_handle)*2)) + (((sizeof(struct iguana_account)) * 2 * numpkinds)) + (2 * numunspents * sizeof(struct iguana_Uextra))); + allocsize += (scriptspace + 65536*4 + ((numtxids + numpkinds) * (sizeof(UT_hash_handle)*2)) + (((sizeof(struct iguana_account)) * 2 * numpkinds)) + (2 * numunspents * sizeof(struct iguana_Uextra))); //printf("iguana_hashmemsize T.%d U.%d S.%d P.%d X.%d -> %ld\n",numtxids,numunspents,numspends,numpkinds,numexternaltxids,(long)allocsize); return(allocsize); } @@ -778,13 +944,14 @@ void _iguana_ramchain_setptrs(RAMCHAIN_PTRPS,struct iguana_ramchaindata *rdata) //printf("T.%p Ux.%p Sx.%p P.%p\n",*T,*Ux,*Sx,*P); *TXbits = (void *)(long)((long)rdata + (long)rdata->TXoffset); *PKbits = (void *)(long)((long)rdata + (long)rdata->PKoffset); + *Kspace = (void *)(long)((long)rdata + (long)rdata->Koffset); *U = 0, *S = 0; } else { *U = (void *)(long)((long)rdata + (long)rdata->Uoffset); *S = (void *)(long)((long)rdata + (long)rdata->Soffset); - *Ux = 0, *Sx = 0, *P = 0, *X = 0, *A = 0, *TXbits = 0, *PKbits = 0; //*U2 = 0, *P2 = 0, + *Ux = 0, *Sx = 0, *P = 0, *X = 0, *A = 0, *TXbits = 0, *Kspace = 0, *PKbits = 0; //*U2 = 0, *P2 = 0, } } @@ -811,7 +978,7 @@ void *iguana_ramchain_offset(void *dest,uint8_t *lhash,FILE *fp,uint64_t fpos,vo return((void *)(long)((long)destptr + fpos)); } -int64_t _iguana_rdata_action(FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],void *destptr,uint64_t fpos,uint32_t expanded,uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids,uint32_t txsparsebits,uint64_t numtxsparse,uint32_t pksparsebits,uint64_t numpksparse,uint64_t srcsize,RAMCHAIN_FUNC,int32_t numblocks) +int64_t _iguana_rdata_action(FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],void *destptr,uint64_t fpos,uint32_t expanded,uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids,uint32_t scriptspace,uint32_t txsparsebits,uint64_t numtxsparse,uint32_t pksparsebits,uint64_t numpksparse,uint64_t srcsize,RAMCHAIN_FUNC,int32_t numblocks) { #define RAMCHAIN_LARG(ind) ((lhashes == 0) ? 0 : lhashes[ind].bytes) #define SPARSECOUNT(x) ((x) << 2) @@ -864,10 +1031,11 @@ int64_t _iguana_rdata_action(FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],void *d X = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_EXTERNALS),fparg,fpos,X,&offset,(sizeof(bits256) * numexternaltxids),srcsize); TXbits = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_TXBITS),fparg,fpos,TXbits,&offset,hconv_bitlen(txbits),srcsize); PKbits = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_PKBITS),fparg,fpos,PKbits,&offset,hconv_bitlen(pkbits),srcsize); + Kspace = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_KSPACE),fparg,fpos,Kspace,&offset,scriptspace,srcsize); // at the end so it can be truncated } else { - Ux = destptr, Sx = destptr, P = destptr, A = destptr, X = destptr, TXbits = destptr, PKbits = destptr; //U2 = destptr, P2 = destptr, + Ux = destptr, Sx = destptr, P = destptr, A = destptr, X = destptr, TXbits = destptr, PKbits = destptr, Kspace = destptr; //U2 = destptr, P2 = destptr, U = iguana_ramchain_offset(rdata,RAMCHAIN_LARG(IGUANA_LHASH_UNSPENTS),fparg,fpos,U,&offset,(sizeof(struct iguana_unspent20) * numunspents),srcsize); if ( 0 && lhashes != 0 ) printf("iter.%d lhashes.%p offset.%ld destptr.%p len.%ld fparg.%p fpos.%ld srcsize.%ld\n",iter,RAMCHAIN_LARG(IGUANA_LHASH_SPENDS),(long)offset,destptr,(long)sizeof(struct iguana_spend256) * numspends,fparg,(long)fpos,(long)srcsize); @@ -886,6 +1054,8 @@ int64_t _iguana_rdata_action(FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],void *d { rdata->Uoffset = (uint64_t)((long)Ux - (long)destptr); rdata->Soffset = (uint64_t)((long)Sx - (long)destptr); + rdata->Koffset = (uint64_t)((long)Kspace - (long)destptr); + rdata->scriptspace = scriptspace;//(uint32_t)(offset - rdata->Koffset); } else { @@ -912,28 +1082,30 @@ int64_t _iguana_rdata_action(FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],void *d #undef SPARSECOUNT } -int64_t iguana_ramchain_action(RAMCHAIN_FUNC,FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],struct iguana_ramchaindata *destdata,uint64_t fpos,struct iguana_ramchaindata *srcdata,int32_t numblocks) +int64_t iguana_ramchain_action(RAMCHAIN_FUNC,FILE *fp,bits256 lhashes[IGUANA_NUMLHASHES],struct iguana_ramchaindata *destdata,uint64_t fpos,struct iguana_ramchaindata *srcdata,int32_t numblocks,int32_t scriptspace) { if ( 0 && ramchain->expanded != 0 ) printf("action.%p (%p %p %p) %ld allocated.%ld [%d:%d %d:%d]\n",srcdata,fp,lhashes,destdata,(long)fpos,(long)srcdata->allocsize,srcdata->txsparsebits,srcdata->numtxsparse,srcdata->pksparsebits,srcdata->numpksparse); - return(_iguana_rdata_action(fp,lhashes,destdata,fpos,ramchain->expanded,srcdata->numtxids,srcdata->numunspents,srcdata->numspends,srcdata->numpkinds,srcdata->numexternaltxids,srcdata->txsparsebits,srcdata->numtxsparse,srcdata->pksparsebits,srcdata->numpksparse,srcdata->allocsize,RAMCHAIN_ARG,numblocks)); + return(_iguana_rdata_action(fp,lhashes,destdata,fpos,ramchain->expanded,srcdata->numtxids,srcdata->numunspents,srcdata->numspends,srcdata->numpkinds,srcdata->numexternaltxids,scriptspace,srcdata->txsparsebits,srcdata->numtxsparse,srcdata->pksparsebits,srcdata->numpksparse,srcdata->allocsize,RAMCHAIN_ARG,numblocks)); } -int64_t iguana_ramchain_size(RAMCHAIN_FUNC,int32_t numblocks) +int64_t iguana_ramchain_size(RAMCHAIN_FUNC,int32_t numblocks,int32_t scriptspace) { - return(iguana_ramchain_action(RAMCHAIN_ARG,0,0,0,0,ramchain->H.data,numblocks)); + return(iguana_ramchain_action(RAMCHAIN_ARG,0,0,0,0,ramchain->H.data,numblocks,scriptspace)); } long iguana_ramchain_setsize(struct iguana_ramchain *ramchain,struct iguana_ramchaindata *srcdata,int32_t numblocks) { RAMCHAIN_DECLARE; struct iguana_ramchaindata *rdata = ramchain->H.data; - B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, + B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, Kspace = TXbits = PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, rdata->numtxids = ramchain->H.txidind; rdata->numunspents = ramchain->H.unspentind; rdata->numspends = ramchain->H.spendind; rdata->numpkinds = ramchain->pkind; rdata->numexternaltxids = ramchain->externalind; - rdata->allocsize = iguana_ramchain_size(RAMCHAIN_ARG,numblocks); + rdata->scriptspace = ramchain->H.scriptoffset + ramchain->H.stacksize; + rdata->stacksize = ramchain->H.stacksize; + rdata->allocsize = iguana_ramchain_size(RAMCHAIN_ARG,numblocks,ramchain->H.scriptoffset); ramchain->datasize = rdata->allocsize; return((long)rdata->allocsize); } @@ -941,36 +1113,36 @@ long iguana_ramchain_setsize(struct iguana_ramchain *ramchain,struct iguana_ramc int64_t iguana_ramchain_compact(RAMCHAIN_FUNC,struct iguana_ramchaindata *destdata,struct iguana_ramchaindata *srcdata,int32_t numblocks) { //iguana_ramchain_setsize(ramchain,srcdata); - return(iguana_ramchain_action(RAMCHAIN_ARG,0,0,destdata,0,srcdata,numblocks)); + return(iguana_ramchain_action(RAMCHAIN_ARG,0,0,destdata,0,srcdata,numblocks,ramchain->H.scriptoffset)); } -bits256 iguana_ramchain_lhashes(RAMCHAIN_FUNC,struct iguana_ramchaindata *destdata,struct iguana_ramchaindata *srcdata,int32_t numblocks) +bits256 iguana_ramchain_lhashes(RAMCHAIN_FUNC,struct iguana_ramchaindata *destdata,struct iguana_ramchaindata *srcdata,int32_t numblocks,int32_t scriptspace) { - iguana_ramchain_action(RAMCHAIN_ARG,0,destdata->lhashes,0,0,srcdata,numblocks); + iguana_ramchain_action(RAMCHAIN_ARG,0,destdata->lhashes,0,0,srcdata,numblocks,scriptspace); memset(&destdata->sha256,0,sizeof(destdata->sha256)); vcalc_sha256(0,destdata->sha256.bytes,(void *)destdata,sizeof(*destdata)); return(destdata->sha256); } -int64_t iguana_ramchain_saveaction(RAMCHAIN_FUNC,FILE *fp,struct iguana_ramchaindata *rdata,int32_t numblocks) +int64_t iguana_ramchain_saveaction(RAMCHAIN_FUNC,FILE *fp,struct iguana_ramchaindata *rdata,int32_t numblocks,int32_t scriptspace) { long before,after; before = ftell(fp); - iguana_ramchain_action(RAMCHAIN_ARG,fp,0,rdata,0,rdata,numblocks); + iguana_ramchain_action(RAMCHAIN_ARG,fp,0,rdata,0,rdata,numblocks,scriptspace); after = ftell(fp); if ( 0 && ramchain->expanded != 0 ) { char str[65]; - printf("SAVEACTION: rdata.%ld DEST T.%d U.%d S.%d P.%d X.%d -> size.%ld %ld vs %ld %p %s\n",sizeof(*rdata),rdata->numtxids,rdata->numunspents,rdata->numspends,rdata->numpkinds,rdata->numexternaltxids,(long)rdata->allocsize,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks),after-before+sizeof(*rdata),&X[1],bits256_str(str,X[1])); + printf("SAVEACTION: rdata.%ld DEST T.%d U.%d S.%d P.%d X.%d -> size.%ld %ld vs %ld %p %s\n",sizeof(*rdata),rdata->numtxids,rdata->numunspents,rdata->numspends,rdata->numpkinds,rdata->numexternaltxids,(long)rdata->allocsize,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks,scriptspace),after-before+sizeof(*rdata),&X[1],bits256_str(str,X[1])); } //printf("before.%ld after.%ld allocsize.%ld [%ld] %ld expanded.%d\n",before,after,(long)srcdata->allocsize,(long)ramchain->H.data->allocsize,(long)iguana_ramchain_size(ramchain),ramchain->expanded); return(after - before); } -int64_t iguana_ramchain_init(struct iguana_ramchain *ramchain,struct OS_memspace *mem,struct OS_memspace *hashmem,int32_t firsti,int32_t numtxids,int32_t numunspents,int32_t numspends,int32_t numpkinds,int32_t numexternaltxids,int32_t expanded,int32_t numblocks) +int64_t iguana_ramchain_init(struct iguana_ramchain *ramchain,struct OS_memspace *mem,struct OS_memspace *hashmem,int32_t firsti,int32_t numtxids,int32_t numunspents,int32_t numspends,int32_t numpkinds,int32_t numexternaltxids,int32_t scriptspace,int32_t expanded,int32_t numblocks) { RAMCHAIN_DECLARE; int64_t offset = 0; struct iguana_ramchaindata *rdata; - B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, + B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, Kspace = TXbits = PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, if ( mem == 0 ) return(0); memset(ramchain,0,sizeof(*ramchain)); @@ -990,17 +1162,17 @@ int64_t iguana_ramchain_init(struct iguana_ramchain *ramchain,struct OS_memspace numpkinds = numunspents; if ( 0 && expanded != 0 ) printf("init T.%d U.%d S.%d P.%d X.%d -> %ld\n",numtxids,numunspents,numspends,numpkinds,numexternaltxids,(long)offset); - _iguana_rdata_action(0,0,rdata,0,expanded,numtxids,numunspents,numspends,numpkinds,numexternaltxids,0,0,0,0,0,RAMCHAIN_ARG,numblocks); - if ( rdata->allocsize != iguana_ramchain_size(RAMCHAIN_ARG,numblocks) ) + _iguana_rdata_action(0,0,rdata,0,expanded,numtxids,numunspents,numspends,numpkinds,numexternaltxids,scriptspace*expanded,0,0,0,0,0,RAMCHAIN_ARG,numblocks); + if ( rdata->allocsize != iguana_ramchain_size(RAMCHAIN_ARG,numblocks,scriptspace*expanded) ) { - printf("offset.%ld vs memsize.%ld\n",(long)offset,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks)); + printf("offset.%ld scriptspace.%d allocsize.%ld vs memsize.%ld\n",(long)offset,scriptspace,(long)rdata->allocsize,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks,scriptspace*expanded)); exit(-1); } if ( offset < mem->totalsize ) iguana_memreset(mem); else { - printf("offset.%ld vs memsize.%ld\n",(long)offset,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks)); + printf("offset.%ld vs memsize.%ld\n",(long)offset,(long)iguana_ramchain_size(RAMCHAIN_ARG,numblocks,scriptspace*expanded)); printf("NEED %ld realloc for %ld\n",(long)offset,(long)mem->totalsize); exit(-1); iguana_mempurge(mem); @@ -1010,35 +1182,34 @@ int64_t iguana_ramchain_init(struct iguana_ramchain *ramchain,struct OS_memspace return(offset); } -int32_t iguana_ramchain_alloc(struct iguana_info *coin,struct iguana_ramchain *ramchain,struct OS_memspace *mem,struct OS_memspace *hashmem,uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids,int32_t height,int32_t numblocks) +int32_t iguana_ramchain_alloc(struct iguana_info *coin,struct iguana_ramchain *ramchain,struct OS_memspace *mem,struct OS_memspace *hashmem,uint32_t numtxids,uint32_t numunspents,uint32_t numspends,uint32_t numpkinds,uint32_t numexternaltxids,uint32_t scriptspace,int32_t height,int32_t numblocks) { RAMCHAIN_DECLARE; int64_t hashsize,allocsize,x; - B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, + B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, Kspace = TXbits = PKbits = 0, U = 0, S = 0, T = 0; //U2 = 0, P2 = 0, memset(ramchain,0,sizeof(*ramchain)); ramchain->height = height; - allocsize = _iguana_rdata_action(0,0,0,0,1,numtxids,numunspents,numspends,numpkinds,numexternaltxids,0,0,0,0,0,RAMCHAIN_ARG,numblocks); + allocsize = _iguana_rdata_action(0,0,0,0,1,numtxids,numunspents,numspends,numpkinds,numexternaltxids,scriptspace,0,0,0,0,0,RAMCHAIN_ARG,numblocks); //printf("T.%d U.%d S.%d P.%d X.%d -> %ld\n",numtxids,numunspents,numspends,numpkinds,numexternaltxids,(long)allocsize); memset(mem,0,sizeof(*mem)); memset(hashmem,0,sizeof(*hashmem)); - hashsize = iguana_hashmemsize(numtxids,numunspents,numspends,numpkinds,numexternaltxids); + hashsize = iguana_hashmemsize(numtxids,numunspents,numspends,numpkinds,numexternaltxids,scriptspace); while ( (x= (myallocated(0,-1)+hashsize+allocsize)) > coin->MAXMEM ) { char str[65],str2[65]; fprintf(stderr,"ht.%d wait for allocated %s < MAXMEM %s | elapsed %.2f minutes\n",height,mbstr(str,hashsize+allocsize),mbstr(str2,coin->MAXMEM),(double)(time(NULL)-coin->startutc)/60.); sleep(3); } - iguana_meminit(hashmem,"ramhashmem",0,hashsize + 4096,0); - iguana_meminit(mem,"ramchain",0,allocsize + 4096,0); + iguana_meminit(hashmem,"ramhashmem",0,hashsize + IGUANA_MAXSCRIPTSIZE,0); + iguana_meminit(mem,"ramchain",0,allocsize + IGUANA_MAXSCRIPTSIZE,0); mem->alignflag = sizeof(uint32_t); hashmem->alignflag = sizeof(uint32_t); - if ( iguana_ramchain_init(ramchain,mem,hashmem,1,numtxids,numunspents,numspends,numpkinds,numexternaltxids,1,numblocks) == 0 ) + if ( iguana_ramchain_init(ramchain,mem,hashmem,1,numtxids,numunspents,numspends,numpkinds,numexternaltxids,scriptspace,1,numblocks) == 0 ) return(-1); return(0); } long iguana_ramchain_save(struct iguana_info *coin,RAMCHAIN_FUNC,uint32_t ipbits,bits256 hash2,bits256 prevhash2,int32_t bundlei,struct iguana_bundle *bp) { - struct iguana_ramchaindata *rdata,tmp; - char fname[1024]; long fpos = -1; int32_t hdrsi,checki; FILE *fp; + struct iguana_ramchaindata *rdata,tmp; char fname[1024]; long fpos = -1; int32_t c,i,hdrsi,checki; FILE *fp; uint8_t *destoffset,*srcoffset; if ( (rdata= ramchain->H.data) == 0 ) { printf("ramchainsave no data ptr\n"); @@ -1065,11 +1236,21 @@ long iguana_ramchain_save(struct iguana_info *coin,RAMCHAIN_FUNC,uint32_t ipbits if ( fp != 0 ) { fpos = ftell(fp); - iguana_ramchain_lhashes(RAMCHAIN_ARG,rdata,rdata,bp!=0?bp->n:1); + if ( ramchain->H.stacksize != 0 ) + { + destoffset = &Kspace[ramchain->H.scriptoffset]; + srcoffset = &Kspace[ramchain->H.data->scriptspace - ramchain->H.stacksize]; + if ( destoffset != srcoffset ) + { + for (i=0; iH.stacksize; i++) + c = *srcoffset++, *destoffset++ = c; + } + } + iguana_ramchain_lhashes(RAMCHAIN_ARG,rdata,rdata,bp!=0?bp->n:1,ramchain->H.scriptoffset+ramchain->H.stacksize); tmp = *rdata; iguana_ramchain_compact(RAMCHAIN_ARG,&tmp,rdata,bp!=0?bp->n:1); fwrite(&tmp,1,sizeof(tmp),fp); - iguana_ramchain_saveaction(RAMCHAIN_ARG,fp,rdata,bp!=0?bp->n:1); + iguana_ramchain_saveaction(RAMCHAIN_ARG,fp,rdata,bp!=0?bp->n:1,ramchain->H.scriptoffset+ramchain->H.stacksize); *rdata = tmp; fclose(fp); } @@ -1335,9 +1516,9 @@ struct iguana_ramchain *iguana_ramchain_map(struct iguana_info *coin,char *fname } } _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); - if ( iguana_ramchain_size(RAMCHAIN_ARG,ramchain->numblocks) != ramchain->H.data->allocsize || fpos+ramchain->H.data->allocsize > filesize ) + if ( iguana_ramchain_size(RAMCHAIN_ARG,ramchain->numblocks,expanded*ramchain->H.data->scriptspace) != ramchain->H.data->allocsize || fpos+ramchain->H.data->allocsize > filesize ) { - printf("iguana_ramchain_map.(%s) size mismatch %ld vs %ld vs filesize.%ld numblocks.%d expanded.%d fpos.%d sum %ld\n",fname,(long)iguana_ramchain_size(RAMCHAIN_ARG,ramchain->numblocks),(long)ramchain->H.data->allocsize,(long)filesize,ramchain->numblocks,expanded,(int32_t)fpos,(long)(fpos+ramchain->H.data->allocsize)); + printf("iguana_ramchain_map.(%s) size mismatch %ld vs %ld vs filesize.%ld numblocks.%d expanded.%d fpos.%d sum %ld\n",fname,(long)iguana_ramchain_size(RAMCHAIN_ARG,ramchain->numblocks,expanded*ramchain->H.data->scriptspace),(long)ramchain->H.data->allocsize,(long)filesize,ramchain->numblocks,expanded,(int32_t)fpos,(long)(fpos+ramchain->H.data->allocsize)); exit(-1); //munmap(ramchain->fileptr,ramchain->filesize); return(0); @@ -1389,6 +1570,7 @@ void iguana_ramchain_link(struct iguana_ramchain *ramchain,bits256 firsthash2,bi ramchain->lasthash2 = lasthash2; ramchain->H.txidind = ramchain->H.unspentind = ramchain->H.spendind = ramchain->pkind = firsti; ramchain->externalind = 0; + ramchain->scriptoffset = 0; } int32_t iguana_ramchain_cmp(struct iguana_ramchain *A,struct iguana_ramchain *B,int32_t deepflag) @@ -1397,14 +1579,14 @@ int32_t iguana_ramchain_cmp(struct iguana_ramchain *A,struct iguana_ramchain *B, struct iguana_txid *Ta,*Tb; struct iguana_unspent20 *Ua,*Ub; struct iguana_spend256 *Sa,*Sb; struct iguana_pkhash *Pa,*Pb; bits256 *Xa,*Xb; struct iguana_blockRO *Ba,*Bb; struct iguana_account *ACCTa,*ACCTb; struct iguana_unspent *Uxa,*Uxb; - struct iguana_spend *Sxa,*Sxb; uint8_t *TXbitsa,*TXbitsb,*PKbitsa,*PKbitsb; + struct iguana_spend *Sxa,*Sxb; uint8_t *TXbitsa,*TXbitsb,*PKbitsa,*PKbitsb,*Kspacea,*Kspaceb; if ( A->H.data != 0 && B->H.data != 0 && A->H.data->numblocks == B->H.data->numblocks && memcmp(A->H.data->firsthash2.bytes,B->H.data->firsthash2.bytes,sizeof(A->H.data->firsthash2)) == 0 ) { if ( A->H.data->firsti == B->H.data->firsti && A->H.data->numtxids == B->H.data->numtxids && A->H.data->numunspents == B->H.data->numunspents && A->H.data->numspends == B->H.data->numspends && A->H.data->numpkinds == B->H.data->numpkinds && A->H.data->numexternaltxids == B->H.data->numexternaltxids ) { - _iguana_ramchain_setptrs(A,&Ba,&Ta,&Ua,&Sa,&Pa,&ACCTa,&Xa,&Uxa,&Sxa,&TXbitsa,&PKbitsa,A->H.data); - _iguana_ramchain_setptrs(B,&Bb,&Tb,&Ub,&Sb,&Pb,&ACCTb,&Xb,&Uxb,&Sxb,&TXbitsb,&PKbitsb,B->H.data); + _iguana_ramchain_setptrs(A,&Ba,&Ta,&Ua,&Sa,&Pa,&ACCTa,&Xa,&Uxa,&Sxa,&TXbitsa,&PKbitsa,&Kspacea,A->H.data); + _iguana_ramchain_setptrs(B,&Bb,&Tb,&Ub,&Sb,&Pb,&ACCTb,&Xb,&Uxb,&Sxb,&TXbitsb,&PKbitsb,&Kspaceb,B->H.data); for (i=A->H.data->firsti; iH.data->numtxids; i++) if ( memcmp(&Ta[i],&Tb[i],sizeof(Ta[i])) != 0 ) return(-2); @@ -1452,12 +1634,48 @@ int32_t iguana_ramchain_cmp(struct iguana_ramchain *A,struct iguana_ramchain *B, return(-1); } -int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain *dest,struct iguana_ramchain *ramchain,int32_t bundle_hdrsi) +uint8_t *iguana_scriptfpget(struct iguana_info *coin,int32_t *scriptlenp,uint8_t _script[IGUANA_MAXSCRIPTSIZE],uint32_t scriptoffset,int32_t spendflag) +{ + FILE *fp; uint8_t *scriptdata=0; int32_t scriptlen=0; struct scriptdata sdata; + *scriptlenp = 0; + if ( (fp= fopen(coin->scriptsfname[spendflag],"rb")) != 0 ) + { + fseek(fp,scriptoffset,SEEK_SET); + fread(&sdata,1,sizeof(sdata),fp); + if ( sdata.scriptlen > 0 && sdata.scriptlen <= IGUANA_MAXSCRIPTSIZE ) + { + if ( fread(_script,1,sdata.scriptlen,fp) == sdata.scriptlen ) + { + scriptdata = _script; + *scriptlenp = scriptlen = sdata.scriptlen; + //printf("raw [%d] offset.%d scriptlen.%d\n",bp->hdrsi,scriptoffset,scriptlen); + //for (i=0; i<16; i++) + // printf("%02x",_script[i]); + //printf(" set script.%d\n",scriptlen); + } + } + fclose(fp); + } + return(scriptdata); +} + +uint8_t *iguana_scriptptr(struct iguana_info *coin,int32_t *scriptlenp,uint8_t _script[IGUANA_MAXSCRIPTSIZE],uint32_t scriptfpos,uint8_t *scriptdata,int32_t scriptlen,int32_t maxsize,int32_t spendflag) +{ + *scriptlenp = scriptlen; + if ( scriptlen > 0 ) + { + if ( scriptfpos != 0 ) + scriptdata = iguana_scriptfpget(coin,scriptlenp,_script,scriptfpos,spendflag); + } + return(scriptdata); +} + +int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain *dest,struct iguana_ramchain *ramchain,struct iguana_bundle *bp) { RAMCHAIN_DECLARE; RAMCHAIN_DESTDECLARE; - int32_t j,hdrsi,prevout; uint32_t sequence,destspendind=0,desttxidind=0; - bits256 prevhash; uint64_t value; uint8_t type; - struct iguana_txid *tx; struct iguana_ramchaindata *rdata; uint8_t *rmd160; struct iguana_unspent *u; + int32_t j,hdrsi,prevout,scriptlen; uint32_t sequenceid,destspendind=0,desttxidind=0; + bits256 prevhash; uint64_t value; uint8_t type,_script[IGUANA_MAXSCRIPTSIZE]; struct iguana_unspent *u; struct scriptdata *script; + struct iguana_txid *tx; struct iguana_ramchaindata *rdata; uint8_t *rmd160,*scriptdata; if ( dest != 0 ) _iguana_ramchain_setptrs(RAMCHAIN_DESTPTRS,dest->H.data); _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); @@ -1468,7 +1686,7 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain } ramchain->H.ROflag = 1; ramchain->H.unspentind = ramchain->H.spendind = ramchain->pkind = rdata->firsti; - ramchain->externalind = 0; + ramchain->externalind = ramchain->H.scriptoffset = ramchain->H.stacksize = 0; if ( dest != 0 ) { desttxidind = dest->H.txidind; @@ -1477,7 +1695,7 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain for (ramchain->H.txidind=rdata->firsti; ramchain->H.txidindnumtxids; ramchain->H.txidind++) { if ( 0 && ramchain->expanded != 0 ) - printf("ITER TXID.%d -> dest.%p desttxid.%d dest->hashmem.%p\n",ramchain->H.txidind,dest,dest!=0?dest->H.txidind:0,dest!=0?dest->hashmem:0); + printf("ITER TXID.%d -> dest.%p desttxid.%d dest->hashmem.%p numtxids.%d\n",ramchain->H.txidind,dest,dest!=0?dest->H.txidind:0,dest!=0?dest->hashmem:0,rdata->numtxids); tx = &T[ramchain->H.txidind]; if ( iguana_ramchain_addtxid(coin,RAMCHAIN_ARG,tx->txid,tx->numvouts,tx->numvins,tx->locktime,tx->version,tx->timestamp) == 0 ) return(-1); @@ -1491,6 +1709,9 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain } for (j=0; jnumvouts; j++) { + script = 0; + scriptdata = 0; + scriptlen = 0; if ( 0 && ramchain->expanded != 0 ) printf("unspentind.%d pkind.%d Ux.%p\n",ramchain->H.unspentind,Ux[ramchain->H.unspentind].pkind,Ux); if ( ramchain->H.unspentind < rdata->numunspents ) @@ -1501,10 +1722,15 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain value = u->value; hdrsi = u->hdrsi; type = u->type; + scriptlen = 0; if ( u->pkind < rdata->numpkinds ) { rmd160 = P[u->pkind].rmd160; - if ( iguana_ramchain_addunspent(coin,RAMCHAIN_ARG,value,hdrsi,rmd160,j,type) == 0 ) + if ( u->scriptoffset != 0 ) + { + scriptdata = iguana_ramchain_scriptdecode(coin,&scriptlen,Kspace,type,_script,u->scriptoffset,P[u->pkind].pubkeyoffset < ramchain->H.scriptoffset ? P[u->pkind].pubkeyoffset : 0); + } + if ( iguana_ramchain_addunspent(coin,RAMCHAIN_ARG,value,hdrsi,rmd160,j,type,scriptdata,scriptlen) == 0 ) return(-3); } } @@ -1513,13 +1739,14 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain hdrsi = rdata->hdrsi; value = U[ramchain->H.unspentind].value; rmd160 = U[ramchain->H.unspentind].rmd160; - type = U[ramchain->H.unspentind].type; - if ( iguana_ramchain_addunspent20(coin,RAMCHAIN_ARG,value,rmd160,-20,tx->txid,j,type) == 0 ) + type = U[ramchain->H.unspentind].type & 0xf; + scriptdata = iguana_scriptptr(coin,&scriptlen,_script,U[ramchain->H.unspentind].scriptfpos,U[ramchain->H.unspentind].script,U[ramchain->H.unspentind].scriptlen,sizeof(U[ramchain->H.unspentind].script),0); + if ( iguana_ramchain_addunspent20(coin,RAMCHAIN_ARG,value,scriptdata,scriptlen,tx->txid,j,type,bp,rmd160) == 0 ) return(-4); } if ( dest != 0 ) { - if ( iguana_ramchain_addunspent(coin,RAMCHAIN_DESTARG,value,hdrsi,rmd160,j,type) == 0 ) + if ( iguana_ramchain_addunspent(coin,RAMCHAIN_DESTARG,value,hdrsi,rmd160,j,type,scriptdata,scriptlen) == 0 ) return(-5); } } else return(-6); @@ -1542,13 +1769,15 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain tx = &T[ramchain->H.txidind]; for (j=0; jnumvins; j++) { + scriptdata = 0; + script = 0; + scriptlen = 0; if ( ramchain->expanded != 0 ) { - sequence = (Sx[ramchain->H.spendind].diffsequence == 0) ? 0xffffffff : 0; + scriptlen = iguana_vinscriptdecode(coin,&sequenceid,_script,&Kspace[ramchain->H.data->scriptspace],Kspace,&Sx[ramchain->H.spendind]); + scriptdata = _script; prevout = iguana_ramchain_txid(coin,RAMCHAIN_ARG,&prevhash,&Sx[ramchain->H.spendind]); - //bundlei = Sx[ramchain->H.spendind].bundlei; - //hdrsi = Sx[ramchain->H.spendind].hdrsi; - if ( iguana_ramchain_addspend(coin,RAMCHAIN_ARG,prevhash,prevout,sequence,bundle_hdrsi) == 0 ) + if ( iguana_ramchain_addspend(coin,RAMCHAIN_ARG,prevhash,prevout,sequenceid,bp->hdrsi,scriptdata,scriptlen) == 0 ) { char str[65]; int32_t i; printf("txidind.%d spendind.%d spendtxid.%x %d vin.%d %s vout.%d\n",ramchain->H.txidind,ramchain->H.spendind,Sx[ramchain->H.spendind].spendtxidind,Sx[ramchain->H.spendind].spendtxidind&0xfffffff,j,bits256_str(str,prevhash),prevout); @@ -1562,17 +1791,16 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain else { //spendind = (tx->firstvin + j); - sequence = (S[ramchain->H.spendind].diffsequence == 0) ? 0xffffffff : 0; + sequenceid = S[ramchain->H.spendind].sequenceid; prevhash = S[ramchain->H.spendind].prevhash2; prevout = S[ramchain->H.spendind].prevout; - //bundlei = S[ramchain->H.spendind].bundlei; - //hdrsi = S[ramchain->H.spendind].hdrsi; - if ( iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,prevhash,prevout,0,0,sequence) == 0 ) + scriptdata = iguana_scriptptr(coin,&scriptlen,_script,S[ramchain->H.spendind].scriptfpos,S[ramchain->H.spendind].vinscript,S[ramchain->H.spendind].vinscriptlen,sizeof(S[ramchain->H.spendind].vinscript),1); + if ( iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,prevhash,prevout,scriptdata,scriptlen,sequenceid,bp) == 0 ) return(-8); } if ( dest != 0 ) { - if ( iguana_ramchain_addspend(coin,RAMCHAIN_DESTARG,prevhash,prevout,sequence,bundle_hdrsi) == 0 ) + if ( iguana_ramchain_addspend(coin,RAMCHAIN_DESTARG,prevhash,prevout,sequenceid,bp->hdrsi,scriptdata,scriptlen) == 0 ) return(-9); } } @@ -1582,11 +1810,91 @@ int32_t iguana_ramchain_iterate(struct iguana_info *coin,struct iguana_ramchain return(0); } +int32_t iguana_scriptspaceraw(struct iguana_info *coin,int32_t *scriptspacep,int32_t *sigspacep,int32_t *pubkeyspacep,struct iguana_msgtx *txarray,int32_t txn_count) +{ + int32_t i,j,sigspace,suffixlen,scriptspace,pubkeyspace,p2shspace,p2shsize,sigsize,pubkeysize,type,scriptlen; struct iguana_spend256 *s; struct iguana_unspent20 *u; struct iguana_msgtx *tx; struct vin_info V; uint8_t rmd160[20],scriptdata[IGUANA_MAXSCRIPTSIZE]; char asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; + for (i=sigspace=scriptspace=pubkeyspace=p2shspace=0; itx_out; j++) + { + memset(&V,0,sizeof(V)); + type = iguana_calcrmd160(coin,&V,tx->vouts[j].pk_script,tx->vouts[j].pk_scriptlen,tx->txid,j,0xffffffff); + if ( type != 0 ) // IGUANA_SCRIPT_NULL + { + memcpy(rmd160,V.rmd160,sizeof(rmd160)); + memset(&V,0,sizeof(V)); + scriptlen = iguana_scriptgen(coin,&V.M,&V.N,V.coinaddr,scriptdata,asmstr,rmd160,type,(const struct vin_info *)&V,j); + if ( tx->vouts[j].pk_scriptlen > sizeof(u->script) && (scriptlen != tx->vouts[j].pk_scriptlen || memcmp(scriptdata,tx->vouts[j].pk_script,scriptlen) != 0) ) + { + scriptspace += tx->vouts[j].pk_scriptlen; + //printf("type.%d scriptspace.%d <= %d + 2\n",type,scriptspace,tx->vouts[j].pk_scriptlen); + } + } + } + for (j=0; jtx_in; j++) + { + iguana_vinscriptparse(coin,&V,&sigsize,&pubkeysize,&p2shsize,&suffixlen,tx->vins[j].vinscript,tx->vins[j].scriptlen); + pubkeyspace += pubkeysize; + p2shspace += p2shsize; + if ( tx->vins[j].scriptlen > sizeof(s->vinscript) ) + sigspace += tx->vins[j].scriptlen; + } + } + *scriptspacep = scriptspace + p2shspace, *sigspacep = sigspace, *pubkeyspacep = pubkeyspace; + return(scriptspace + sigspace); +} + +int32_t iguana_ramchain_scriptspace(struct iguana_info *coin,int32_t *sigspacep,int32_t *pubkeyspacep,struct iguana_ramchain *ramchain) +{ + RAMCHAIN_DECLARE; + int32_t j,sigspace,pubkeyspace,scriptlen,p2shsize,pubkeysize,sigsize,scriptspace,suffixlen; + uint32_t sequence,spendind,unspentind; struct vin_info V; uint8_t _script[IGUANA_MAXSCRIPTSIZE]; + struct iguana_txid *tx; struct iguana_ramchaindata *rdata; uint8_t *scriptdata; + _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); + *sigspacep = *pubkeyspacep = 0; + if ( (rdata= ramchain->H.data) == 0 || ramchain->expanded != 0 ) + { + printf("iguana_ramchain_scriptspace cant iterate without data and requires simple ramchain\n"); + return(-1); + } + sigspace = pubkeyspace = scriptspace = 0; + for (ramchain->H.txidind=rdata->firsti; ramchain->H.txidindnumtxids; ramchain->H.txidind++) + { + tx = &T[ramchain->H.txidind]; + for (j=0; jnumvouts; j++) + { + if ( (unspentind= ramchain->H.unspentind++) < rdata->numunspents ) + if ( U[unspentind].scriptlen != 0 ) + scriptspace += U[unspentind].scriptlen + 2; + } + for (j=0; jnumvins; j++) + { + if ( (spendind= ramchain->H.spendind++) < rdata->numspends ) + { + sequence = S[spendind].sequenceid; + if ( (scriptdata= iguana_scriptptr(coin,&scriptlen,_script,S[spendind].scriptfpos,S[spendind].vinscript,S[spendind].vinscriptlen,sizeof(S[spendind].vinscript),1)) != 0 ) + { + iguana_vinscriptparse(coin,&V,&sigsize,&pubkeysize,&p2shsize,&suffixlen,scriptdata,scriptlen); + scriptspace += p2shsize; + if ( sequence != 0 && sequence != 0xffffffff && sequence != 0xfffffffe ) + scriptspace += sizeof(sequence); + sigspace += sigsize; + pubkeyspace += pubkeysize; + } + } + } + } + *sigspacep = sigspace, *pubkeyspacep = pubkeyspace; + return(scriptspace); +} + long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_txblock *origtxdata,struct iguana_msgtx *txarray,int32_t txn_count,uint8_t *data,int32_t recvlen) { int32_t verifyflag = 0; RAMCHAIN_DECLARE; long fsize; void *ptr; struct iguana_ramchain R,*mapchain,*ramchain = &addr->ramchain; - struct iguana_msgtx *tx; int32_t i,j,fpos,firsti=1,err,flag,bundlei = -2; char fname[1024]; + struct iguana_msgtx *tx; int32_t i,j,fpos,scriptsize,pubkeysize,sigsize,firsti=1,err,flag,scriptspace=0,bundlei = -2; + char fname[1024]; uint8_t rmd160[20]; struct iguana_bundle *bp = 0; struct iguana_block *block; if ( iguana_bundlefind(coin,&bp,&bundlei,origtxdata->block.RO.hash2) == 0 ) { @@ -1612,17 +1920,16 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru //printf("ramchaindata have %d:%d at %d\n",bp->hdrsi,bundlei,bp->fpos[bundlei]); return(block->fpos); } - //SETBIT(bp->recv,bundlei); fpos = -1; - //bp->recvlens[bundlei] = recvlen; - //bp->firsttxidinds[bundlei] = firsti; - if ( iguana_ramchain_init(ramchain,&addr->TXDATA,&addr->HASHMEM,1,txn_count,origtxdata->numunspents,origtxdata->numspends,0,0,0,1) == 0 ) + scriptspace = iguana_scriptspaceraw(coin,&scriptsize,&sigsize,&pubkeysize,txarray,txn_count); + //printf("bp.[%d:%d] <- scriptspace.%d expanded.%d\n",bp->hdrsi,bundlei,scriptspace,ramchain->expanded); + if ( iguana_ramchain_init(ramchain,&addr->TXDATA,&addr->HASHMEM,1,txn_count,origtxdata->numunspents,origtxdata->numspends,0,0,scriptspace,0,1) == 0 ) return(-1); iguana_ramchain_link(ramchain,origtxdata->block.RO.hash2,origtxdata->block.RO.hash2,bp->hdrsi,bp->bundleheight+bundlei,bundlei,1,firsti,0); _iguana_ramchain_setptrs(RAMCHAIN_PTRS,ramchain->H.data); - if ( T == 0 || U == 0 || S == 0 || B == 0 )// P == 0//|| X == 0 || A == 0 || U2 == 0 || P2 == 0 ) + if ( T == 0 || U == 0 || S == 0 || B == 0 ) { - printf("fatal error getting txdataptrs\n"); + printf("fatal error getting txdataptrs %p %p %p %p\n",T,U,S,B); return(-1); } for (i=0; iH.txidind++) @@ -1631,7 +1938,8 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru iguana_ramchain_addtxid(coin,RAMCHAIN_ARG,tx->txid,tx->tx_out,tx->tx_in,tx->lock_time,tx->version,tx->timestamp); for (j=0; jtx_out; j++) { - iguana_ramchain_addunspent20(coin,RAMCHAIN_ARG,tx->vouts[j].value,tx->vouts[j].pk_script,tx->vouts[j].pk_scriptlen,tx->txid,j,0); + memset(rmd160,0,sizeof(rmd160)); + iguana_ramchain_addunspent20(coin,RAMCHAIN_ARG,tx->vouts[j].value,tx->vouts[j].pk_script,tx->vouts[j].pk_scriptlen,tx->txid,j,-1,bp,rmd160); } ramchain->H.spendind += tx->tx_in; } @@ -1642,7 +1950,7 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru for (j=0; jtx_in; j++) { //char str[65]; printf("PT vin.%d %s vout.%d\n",j,bits256_str(str,tx->vins[j].prev_hash),tx->vins[j].prev_vout); - iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,tx->vins[j].prev_hash,tx->vins[j].prev_vout,tx->vins[j].sigscript,tx->vins[j].scriptlen,tx->vins[j].sequence);//,bp->hdrsi,bundlei); + iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,tx->vins[j].prev_hash,tx->vins[j].prev_vout,tx->vins[j].vinscript,tx->vins[j].scriptlen,tx->vins[j].sequence,bp);//,bp->hdrsi,bundlei); } } //char str[65]; printf("before height.%d num.%d:%d T.%d U.%d S.%d P.%d X.%d %s\n",ramchain->height,ramchain->numblocks,ramchain->H.data->numblocks,ramchain->H.txidind,ramchain->H.unspentind,ramchain->H.spendind,ramchain->pkind,ramchain->externalind,bits256_str(str,ramchain->H.data->firsthash2)); @@ -1650,7 +1958,7 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru flag = 0; if ( ramchain->H.txidind != ramchain->H.data->numtxids || ramchain->H.unspentind != ramchain->H.data->numunspents || ramchain->H.spendind != ramchain->H.data->numspends ) { - printf("error creating PT ramchain: ramchain->txidind %d != %d ramchain->data->numtxids || ramchain->unspentind %d != %d ramchain->data->numunspents || ramchain->spendind %d != %d ramchain->data->numspends\n",ramchain->H.txidind,ramchain->H.data->numtxids,ramchain->H.unspentind,ramchain->H.data->numunspents,ramchain->H.spendind,ramchain->H.data->numspends); + printf("error creating PT ramchain.[%d:%d] ramchain->txidind %d != %d ramchain->data->numtxids || ramchain->unspentind %d != %d ramchain->data->numunspents || ramchain->spendind %d != %d ramchain->data->numspends space.(%d v %d)\n",bp->hdrsi,bp->bundleheight,ramchain->H.txidind,ramchain->H.data->numtxids,ramchain->H.unspentind,ramchain->H.data->numunspents,ramchain->H.spendind,ramchain->H.data->numspends,ramchain->H.scriptoffset,ramchain->H.data->scriptspace); } else { @@ -1669,7 +1977,7 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru { //printf("mapped Soffset.%ld\n",(long)mapchain->data->Soffset); iguana_ramchain_link(&R,origtxdata->block.RO.hash2,origtxdata->block.RO.hash2,bp->hdrsi,bp->bundleheight+bundlei,bundlei,1,firsti,1); - if ( 0 ) // crashes unix + if ( 0 ) // unix issues? { if ( (err= iguana_ramchain_cmp(ramchain,mapchain,0)) != 0 ) printf("error.%d comparing ramchains\n",err); @@ -1688,12 +1996,13 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru else { iguana_ramchain_extras(&R,0); - if ( (err= iguana_ramchain_iterate(coin,0,&R,bp->hdrsi)) != 0 ) + if ( (err= iguana_ramchain_iterate(coin,0,&R,bp)) != 0 ) printf("err.%d iterate ",err); //printf("SUCCESS REMAP\n"); bp->numtxids += ramchain->H.data->numtxids; bp->numunspents += ramchain->H.data->numunspents; bp->numspends += ramchain->H.data->numspends; + bp->rawscriptspace += ramchain->H.data->scriptspace; } iguana_ramchain_free(&R,1); } @@ -1702,6 +2011,7 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru bp->numtxids += ramchain->H.data->numtxids; bp->numunspents += ramchain->H.data->numunspents; bp->numspends += ramchain->H.data->numspends; + bp->rawscriptspace += ramchain->H.data->scriptspace; } if ( fpos >= 0 ) block->fpos = fpos, block->fpipbits = (uint32_t)addr->ipbits; @@ -1826,7 +2136,7 @@ int32_t iguana_ramchain_expandedsave(struct iguana_info *coin,RAMCHAIN_FUNC,stru memcpy(ramchain->roA,ramchain->A,sizeof(*ramchain->A) * ramchain->H.data->numpkinds); memset(ramchain->A,0,sizeof(*ramchain->A) * ramchain->H.data->numpkinds); //printf("presave T.%d U.%d S.%d P.%d X.%d -> size.%ld firsti.%d\n",ramchain->H.data->numtxids,ramchain->H.data->numunspents,ramchain->H.data->numspends,ramchain->H.data->numpkinds,ramchain->H.data->numexternaltxids,(long)ramchain->H.data->allocsize,firsti); - if ( (err= iguana_ramchain_iterate(coin,0,ramchain,bp->hdrsi)) != 0 ) + if ( (err= iguana_ramchain_iterate(coin,0,ramchain,bp)) != 0 ) printf("ERROR.%d iterating presave ramchain hdrsi.%d\n",err,hdrsi); else if ( (err= iguana_ramchain_verify(coin,ramchain)) != 0 ) printf("ERROR.%d verifying presave ramchain hdrsi.%d\n",err,hdrsi); @@ -1847,7 +2157,7 @@ int32_t iguana_ramchain_expandedsave(struct iguana_info *coin,RAMCHAIN_FUNC,stru iguana_ramchain_link(mapchain,firsthash2,lasthash2,hdrsi,height,0,numblocks,firsti,1); iguana_ramchain_extras(mapchain,hashmem); //printf("MAP T.%d U.%d S.%d P.%d X.%d -> size.%ld Xoffset.%d\n",mapchain->H.data->numtxids,mapchain->H.data->numunspents,mapchain->H.data->numspends,mapchain->H.data->numpkinds,mapchain->H.data->numexternaltxids,(long)mapchain->H.data->allocsize,(int32_t)mapchain->H.data->Xoffset); - if ( (err= iguana_ramchain_iterate(coin,0,mapchain,bp->hdrsi)) != 0 ) + if ( (err= iguana_ramchain_iterate(coin,0,mapchain,bp)) != 0 ) printf("err.%d iterate mapped dest\n",err); else if ( cmpflag != 0 ) { @@ -1926,9 +2236,9 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str RAMCHAIN_DESTDECLARE; RAMCHAIN_DECLARE; void **ptrs,*ptr; long *filesizes,filesize; uint32_t *ipbits; char fname[1024]; struct iguana_ramchain *R,*mapchain,*dest,newchain; uint32_t fpipbits,now = (uint32_t)time(NULL); - int32_t i,numtxids,valid,numunspents,numspends,numpkinds,numexternaltxids,fpos; struct iguana_block *block; + int32_t i,numtxids,valid,sigspace,sigsize,pubkeysize,pubkeyspace,numunspents,numspends,numpkinds,numexternaltxids,scriptspace,fpos; struct iguana_block *block; struct OS_memspace HASHMEM; int32_t err,j,num,hdrsi,bundlei,firsti= 1,retval = -1; - B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, TXbits = 0, PKbits = 0, U = 0, S = 0, T = 0;//U2 = 0, P2 = 0, + B = 0, Ux = 0, Sx = 0, P = 0, A = 0, X = 0, Kspace = TXbits = PKbits = 0, U = 0, S = 0, T = 0;//U2 = 0, P2 = 0, R = mycalloc('s',bp->n,sizeof(*R)); ptrs = mycalloc('w',bp->n,sizeof(*ptrs)); ipbits = mycalloc('w',bp->n,sizeof(*ipbits)); @@ -1938,7 +2248,8 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str iguana_bundlemapfree(0,0,ipbits,ptrs,filesizes,bp->n,R,bp->n); return(-1); } - for (bundlei=numtxids=numunspents=numspends=0; bundlein; bundlei++) + scriptspace = sigspace = pubkeyspace = 0; + for (bundlei=numtxids=numunspents=numspends=scriptspace=0; bundlein; bundlei++) { if ( (block= bp->blocks[bundlei]) != 0 ) fpipbits = block->fpipbits, fpos = block->fpos; @@ -1960,21 +2271,30 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str mapchain->filesize = filesize; mapchain->H.data = (void *)(long)((long)ptr + fpos); mapchain->H.ROflag = 1; - if ( fpos+mapchain->H.data->allocsize > filesize || iguana_ramchain_size(MAPCHAIN_ARG,1) != mapchain->H.data->allocsize ) + if ( fpos > filesize ) + { + iguana_bundlemapfree(0,0,ipbits,ptrs,filesizes,num,R,bp->n); + printf("fpos error %d > %ld mapping hdrsi.%d bundlei.%d\n",fpos,filesize,bp->hdrsi,bundlei); + return(-1); + } + if ( fpos+mapchain->H.data->allocsize > filesize || iguana_ramchain_size(MAPCHAIN_ARG,1,0*mapchain->H.scriptoffset) != mapchain->H.data->allocsize ) { - printf("iguana_bundlesaveHT ipbits.%x size mismatch %ld vs %ld vs filesize.%ld fpos.%ld bundlei.%d expanded.%d\n",fpipbits,(long)iguana_ramchain_size(MAPCHAIN_ARG,1),(long)mapchain->H.data->allocsize,(long)filesize,(long)fpos,bundlei,mapchain->expanded); + printf("iguana_bundlesaveHT ipbits.%x size mismatch %ld vs %ld vs filesize.%ld fpos.%ld bundlei.%d expanded.%d\n",fpipbits,(long)iguana_ramchain_size(MAPCHAIN_ARG,1,0*mapchain->H.scriptoffset),(long)mapchain->H.data->allocsize,(long)filesize,(long)fpos,bundlei,mapchain->expanded); //getchar(); break; } else if ( memcmp(bp->hashes[bundlei].bytes,mapchain->H.data->firsthash2.bytes,sizeof(bits256)) != 0 ) { - char str[65],str2[65]; printf("iguana_bundlesaveHT hash2 mismatch %s vs %s\n",bits256_str(str,bp->hashes[bundlei]),bits256_str(str2,mapchain->H.data->firsthash2)); + char str[65],str2[65]; printf("iguana_bundlesaveHT.[%d:%d] hash2 mismatch %s vs %s\n",bp->hdrsi,bundlei,bits256_str(str,bp->hashes[bundlei]),bits256_str(str2,mapchain->H.data->firsthash2)); break; } iguana_ramchain_link(mapchain,bp->hashes[bundlei],bp->hashes[bundlei],bp->hdrsi,bp->bundleheight+bundlei,bundlei,1,firsti,1); numtxids += (mapchain->H.data->numtxids - 1); numunspents += (mapchain->H.data->numunspents - 1); numspends += (mapchain->H.data->numspends - 1); + scriptspace += iguana_ramchain_scriptspace(coin,&sigsize,&pubkeysize,mapchain); + sigspace += sigsize; + pubkeyspace += pubkeysize; if ( (block= bp->blocks[bundlei]) == 0 || bits256_nonz(block->RO.hash2) == 0 || block != iguana_blockfind(coin,block->RO.hash2) || memcmp(block->RO.hash2.bytes,bp->hashes[bundlei].bytes,sizeof(bits256)) != 0 ) { printf("block.%p error vs %p\n",block,iguana_blockfind(coin,block->RO.hash2)); @@ -1984,6 +2304,7 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str //printf("(%d %d %d) ",numtxids,numunspents,numspends); //printf("%d ",numtxids); } + scriptspace += pubkeyspace + sigspace; //printf("RObits\n"); if ( bundlei != bp->n ) { @@ -1997,7 +2318,7 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str dest = &bp->ramchain; //printf("E.%d depth.%d start bundle ramchain %d at %u started.%u lag.%d\n",coin->numemitted,depth,bp->bundleheight,now,starttime,now-starttime); depth++; - if ( iguana_ramchain_alloc(coin,dest,mem,&HASHMEM,numtxids,numunspents,numspends,numpkinds,numexternaltxids,bp->bundleheight,bp->n) < 0 ) + if ( iguana_ramchain_alloc(coin,dest,mem,&HASHMEM,numtxids,numunspents,numspends,numpkinds,numexternaltxids,scriptspace+sigspace,bp->bundleheight,bp->n) < 0 ) { iguana_bundlemapfree(mem,&HASHMEM,ipbits,ptrs,filesizes,num,R,bp->n); return(-1); @@ -2022,7 +2343,7 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str } else printf("error getting block (%d:%d) %p vs %p\n",bp->hdrsi,i,block,iguana_blockfind(coin,bp->hashes[i])); } dest->H.txidind = dest->H.unspentind = dest->H.spendind = dest->pkind = dest->H.data->firsti; - dest->externalind = 0; + dest->externalind = dest->H.scriptoffset = dest->H.stacksize = 0; //printf("\n"); for (bundlei=0; bundlein; bundlei++) { @@ -2032,7 +2353,7 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str coin->blocks.RO[bp->bundleheight+bundlei] = block->RO; destB[bundlei] = block->RO; //printf("(%d %d) ",R[bundlei].H.data->numtxids,dest->H.txidind); - if ( (err= iguana_ramchain_iterate(coin,dest,&R[bundlei],bp->hdrsi)) != 0 ) + if ( (err= iguana_ramchain_iterate(coin,dest,&R[bundlei],bp)) != 0 ) { printf("error ramchain_iterate hdrs.%d bundlei.%d\n",bp->hdrsi,bundlei); break; @@ -2044,6 +2365,11 @@ int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct OS_memspace *mem,str break; } } + if ( dest->H.scriptoffset+dest->H.stacksize > dest->H.data->scriptspace ) + { + printf("bundlesave: stack smashed %d+%d > %d\n",dest->H.scriptoffset,dest->H.stacksize,dest->H.data->scriptspace); + bundlei = -1; + } depth--; if ( bundlei == bp->n && iguana_ramchain_expandedsave(coin,RAMCHAIN_DESTARG,&newchain,&HASHMEM,0,bp) == 0 ) { @@ -2097,9 +2423,9 @@ int32_t iguana_bundlemergeHT(struct iguana_info *coin,struct OS_memspace *mem,st struct iguana_ramchain _Achain,_Bchain,*A,*B,R,newchain,*dest = &R; int32_t err,retval = -1,firsti = 1; memset(mem,0,sizeof(*mem)); memset(&HASHMEMA,0,sizeof(HASHMEMA)); - iguana_meminit(&HASHMEMA,"hashmemA",0,iguana_hashmemsize(bp->ramchain.H.txidind,bp->ramchain.H.unspentind,bp->ramchain.H.spendind,bp->ramchain.pkind,bp->ramchain.externalind) + 4096,0); + iguana_meminit(&HASHMEMA,"hashmemA",0,iguana_hashmemsize(bp->ramchain.H.txidind,bp->ramchain.H.unspentind,bp->ramchain.H.spendind,bp->ramchain.pkind,bp->ramchain.externalind,bp->ramchain.H.data->scriptspace) + IGUANA_MAXSCRIPTSIZE,0); memset(&HASHMEMB,0,sizeof(HASHMEMB)); - iguana_meminit(&HASHMEMB,"hashmemB",0,iguana_hashmemsize(nextbp->ramchain.H.txidind,nextbp->ramchain.H.unspentind,nextbp->ramchain.H.spendind,nextbp->ramchain.pkind,nextbp->ramchain.externalind) + 4096,0); + iguana_meminit(&HASHMEMB,"hashmemB",0,iguana_hashmemsize(nextbp->ramchain.H.txidind,nextbp->ramchain.H.unspentind,nextbp->ramchain.H.spendind,nextbp->ramchain.pkind,nextbp->ramchain.externalind,nextbp->ramchain.H.data->scriptspace) + IGUANA_MAXSCRIPTSIZE,0); memset(&_Achain,0,sizeof(_Achain)); A = &_Achain; memset(&_Bchain,0,sizeof(_Bchain)); B = &_Bchain; if ( (A= iguana_ramchain_map(coin,fnameA,bp,bp->ramchain.numblocks,A,&HASHMEMA,0,bp->hashes[0],zero,0,0,1,1)) != 0 ) @@ -2118,7 +2444,7 @@ int32_t iguana_bundlemergeHT(struct iguana_info *coin,struct OS_memspace *mem,st } if ( A->H.data != 0 && B->H.data != 0 && B->height == A->height+A->numblocks ) { - if ( iguana_ramchain_alloc(coin,dest,mem,&HASHMEM,(A->H.data->numtxids+B->H.data->numtxids),(A->H.data->numunspents+B->H.data->numunspents),(A->H.data->numspends+B->H.data->numspends),(A->H.data->numpkinds+B->H.data->numpkinds),(A->H.data->numexternaltxids+B->H.data->numexternaltxids),A->height,A->numblocks + B->numblocks) < 0 ) + if ( iguana_ramchain_alloc(coin,dest,mem,&HASHMEM,(A->H.data->numtxids+B->H.data->numtxids),(A->H.data->numunspents+B->H.data->numunspents),(A->H.data->numspends+B->H.data->numspends),(A->H.data->numpkinds+B->H.data->numpkinds),(A->H.data->numexternaltxids+B->H.data->numexternaltxids),A->H.data->scriptspace,A->height,A->numblocks + B->numblocks) < 0 ) { printf("depth.%d ht.%d fsize.%s ERROR alloc lag.%d elapsed.%ld\n",depth,dest->height,mbstr(str,dest->H.data->allocsize),now-starttime,time(NULL)-now); iguana_mergefree(mem,A,B,&HASHMEM,&HASHMEMA,&HASHMEMB); @@ -2130,9 +2456,9 @@ int32_t iguana_bundlemergeHT(struct iguana_info *coin,struct OS_memspace *mem,st iguana_ramchain_extras(dest,&HASHMEM); dest->H.txidind = dest->H.unspentind = dest->H.spendind = dest->pkind = dest->H.data->firsti; dest->externalind = 0; - if ( (err= iguana_ramchain_iterate(coin,dest,A,bp->hdrsi)) != 0 ) + if ( (err= iguana_ramchain_iterate(coin,dest,A,bp)) != 0 ) printf("error.%d ramchain_iterate A.%d\n",err,A->height); - else if ( (err= iguana_ramchain_iterate(coin,dest,B,nextbp->hdrsi)) != 0 ) + else if ( (err= iguana_ramchain_iterate(coin,dest,B,nextbp)) != 0 ) printf("error.%d ramchain_iterate B.%d\n",err,B->height); else if ( iguana_ramchain_expandedsave(coin,RAMCHAIN_DESTARG,&newchain,&HASHMEM,0,0) == 0 ) { diff --git a/iguana/iguana_recv.c b/iguana/iguana_recv.c index 19ecbe0c4..9f1083b7c 100755 --- a/iguana/iguana_recv.c +++ b/iguana/iguana_recv.c @@ -314,7 +314,7 @@ uint32_t iguana_allhashcmp(struct iguana_info *coin,struct iguana_bundle *bp,bit prev = block; } //printf("ALLHASHES FOUND! %d requested.%d\n",bp->bundleheight,n); - iguana_bundleQ(coin,bp,bp->n/2 + (rand() % 500)); + iguana_bundleQ(coin,bp,bp->n*5 + (rand() % 500)); return(bp->queued); } } @@ -342,7 +342,7 @@ void iguana_bundlespeculate(struct iguana_info *coin,struct iguana_bundle *bp,in int32_t iguana_bundleiters(struct iguana_info *coin,struct iguana_bundle *bp,int32_t timelimit) { - int32_t i,n,valid,pend,max,counter = 0; uint32_t now; struct iguana_block *block; double endmillis; + int32_t i,n,better,issued,valid,pend,max,counter = 0; uint32_t now; struct iguana_block *block; double endmillis,width; coin->numbundlesQ--; if ( bp->numhashes < bp->n && bp->bundleheight < coin->longestchain-coin->chain->bundlesize ) { @@ -362,50 +362,61 @@ int32_t iguana_bundleiters(struct iguana_info *coin,struct iguana_bundle *bp,int } } usleep(10000); - iguana_bundleQ(coin,bp,bp->n); + iguana_bundleQ(coin,bp,bp->n*5); return(0); } pend = queue_size(&coin->priorityQ) + queue_size(&coin->blocksQ); for (i=0; ipeers.active[i].pendblocks; - if ( pend >= coin->MAXPENDING*coin->MAXPEERS ) + if ( pend >= coin->MAXPENDING*coin->peers.numranked ) { - usleep(1000); - //printf("SKIP pend.%d vs %d: ITERATE bundle.%d n.%d r.%d s.%d finished.%d timelimit.%d\n",pend,coin->MAXPENDING*coin->MAXPEERS,bp->bundleheight,bp->n,bp->numrecv,bp->numsaved,bp->emitfinish,timelimit); - iguana_bundleQ(coin,bp,counter == 0 ? bp->n*5 : bp->n*2); - return(0); + for (i=better=0; ibundlescount; i++) + if ( coin->bundles[i] != 0 && coin->bundles[i]->numsaved > bp->numsaved ) + better++; + if ( better > 2*coin->peers.numranked ) + { + usleep(1000); + //printf("SKIP pend.%d vs %d: better.%d ITERATE bundle.%d n.%d r.%d s.%d finished.%d timelimit.%d\n",pend,coin->MAXPENDING*coin->peers.numranked,better,bp->bundleheight,bp->n,bp->numrecv,bp->numsaved,bp->emitfinish,timelimit); + iguana_bundleQ(coin,bp,counter == 0 ? bp->n*5 : bp->n*2); + return(0); + } } max = 1 + ((coin->MAXPENDING*coin->MAXPEERS - pend) >> 1); - endmillis = OS_milliseconds() + timelimit; + endmillis = OS_milliseconds() + timelimit*100; while ( bp->emitfinish == 0 && OS_milliseconds() < endmillis ) { now = (uint32_t)time(NULL); - for (i=n=counter=0; in; i++) + for (i=n=issued=counter=0; in; i++) { + if ( OS_milliseconds() > endmillis ) + break; if ( (block= bp->blocks[i]) != 0 ) { - if ( block->fpipbits == 0 && (block->queued == 0 || bp->issued[i] == 0 || now > bp->issued[i]+30) ) + if ( block->fpipbits == 0 && (block->queued == 0 || bp->issued[i] == 0 || now > bp->issued[i]+7) ) { //if ( bp->bundleheight == 20000 ) // printf("(%d:%d) ",bp->hdrsi,i); block->numrequests++; - iguana_blockQ(coin,bp,i,block->RO.hash2,bp->numsaved > bp->n-10); + iguana_blockQ(coin,bp,i,block->RO.hash2,bp->numsaved > bp->n*.9); bp->issued[i] = now; counter++; if ( --max <= 0 ) break; } - else if ( block->fpipbits != 0 ) - n++; + else if ( block->fpipbits != 0 && bits256_nonz(block->RO.prev_block) != 0 ) + n++, issued++; + else if ( bp->issued[i] != 0 ) + issued++; } //else printf("iguana_bundleiters[%d] unexpected null block[%d]\n",bp->bundleheight,i); bp->numsaved = n; } if ( max <= 0 ) break; - usleep(100); + usleep(1000); } - if ( 0 && counter > 0 ) - printf("ITERATE bundle.%d h.%d n.%d r.%d s.%d finished.%d issued.%d\n",bp->bundleheight,bp->numhashes,bp->n,bp->numrecv,bp->numsaved,bp->emitfinish,counter); + width = 1000 + sqrt(sqrt(bp->n * (1+bp->numsaved+issued)) * (10+coin->bundlescount-bp->hdrsi)); + //if ( 0 && counter > 0 ) + printf("ITERATE bundle.%d h.%d n.%d r.%d s.%d F.%d I.%d T.%d %f %u next %f\n",bp->bundleheight/coin->chain->bundlesize,bp->numhashes,bp->n,bp->numrecv,bp->numsaved,bp->emitfinish,issued,timelimit,endmillis-OS_milliseconds(),(uint32_t)time(NULL),width); if ( bp->emitfinish == 0 ) { if ( bp->numsaved >= bp->n ) @@ -415,9 +426,9 @@ int32_t iguana_bundleiters(struct iguana_info *coin,struct iguana_bundle *bp,int if ( (block= bp->blocks[i]) != 0 ) { //printf("(%x:%x) ",(uint32_t)block->RO.hash2.ulongs[3],(uint32_t)bp->hashes[i].ulongs[3]); - if ( iguana_blockvalidate(coin,&valid,block,0) != 0 || (bp->bundleheight+i > 0 && bits256_nonz(block->RO.prev_block) == 0) ) + if ( iguana_blockvalidate(coin,&valid,block,1) != 0 || (bp->bundleheight+i > 0 && bits256_nonz(block->RO.prev_block) == 0) ) { - //char str[65]; printf(">>>>>>> null prevblock error at ht.%d patch.(%s) and reissue\n",bp->bundleheight+i,bits256_str(str,bp->hashes[i-1])); + char str[65]; printf(">>>>>>> null prevblock error at ht.%d patch.(%s) and reissue\n",bp->bundleheight+i,bits256_str(str,block->RO.prev_block)); block->queued = 0; block->fpipbits = 0; bp->issued[i] = 0; @@ -434,7 +445,7 @@ int32_t iguana_bundleiters(struct iguana_info *coin,struct iguana_bundle *bp,int iguana_emitQ(coin,bp); return(1); } - iguana_bundleQ(coin,bp,counter == 0 ? bp->n*5 : bp->n*2); + iguana_bundleQ(coin,bp,width); } return(0); } @@ -536,8 +547,10 @@ struct iguana_bundlereq *iguana_recvblockhashes(struct iguana_info *coin,struct if ( num >= coin->chain->bundlesize ) { iguana_blockQ(coin,0,-1,blockhashes[coin->chain->bundlesize],1); + printf("call allhashes\n"); if ( iguana_allhashcmp(coin,bp,blockhashes,num) > 0 ) return(req); + printf("done allhashes\n"); } if ( (bp->speculative == 0 || num > bp->numspec) && bp->emitfinish == 0 ) { @@ -552,9 +565,9 @@ struct iguana_bundlereq *iguana_recvblockhashes(struct iguana_info *coin,struct } else if ( num >= coin->chain->bundlesize ) { - for (i=coin->bundlescount-1; i>=0; i--) + for (i=0; ibundlescount; i++) { - if ( (bp= coin->bundles[i]) != 0 && bits256_nonz(bp->hashes[0]) > 0 ) + if ( (bp= coin->bundles[i]) != 0 && bp->emitfinish == 0 && bits256_nonz(bp->hashes[0]) > 0 ) { blockhashes[0] = bp->hashes[0]; if ( iguana_allhashcmp(coin,bp,blockhashes,coin->chain->bundlesize) > 0 ) @@ -585,6 +598,8 @@ struct iguana_bundlereq *iguana_recvblock(struct iguana_info *coin,struct iguana //static int total; char str[65]; printf("RECV %s [%d:%d] block.%08x | %d\n",bits256_str(str,origblock->RO.hash2),bp!=0?bp->hdrsi:-1,bundlei,block->fpipbits,total++); if ( block != 0 ) { + if ( bp != 0 && bundlei > 0 && bits256_nonz(block->RO.prev_block) > 0 ) + iguana_blockQ(coin,bp,bundlei-1,block->RO.prev_block,0); block->RO.recvlen = recvlen; if ( req->copyflag != 0 && block->queued == 0 && bp != 0 )//block->rawdata == 0 ) { @@ -686,8 +701,8 @@ int32_t iguana_reqhdrs(struct iguana_info *coin) if ( (bp= coin->bundles[i]) != 0 && bp->emitfinish < coin->startutc ) { if ( i == coin->bundlescount-1 ) - lag = 60; - else lag = 60 + (rand() % 30); + lag = 30; + else lag = 30 + (rand() % 30); //if ( i < coin->bundlescount-1 && (bp->numhashes >= (rand() % bp->n) || time(NULL) < bp->hdrtime+lag) ) // continue; if ( bp->numhashes < bp->n && bp->bundleheight+bp->numhashes < coin->longestchain && time(NULL) > bp->issuetime+lag ) @@ -874,20 +889,20 @@ int32_t iguana_reqblocks(struct iguana_info *coin) _iguana_chainlink(coin,next); else if ( next->queued == 0 && next->fpipbits == 0 ) { - //printf("HWM next %d\n",coin->blocks.hwmchain.height+1); - iguana_blockQ(coin,bp,bundlei,next->RO.hash2,0); + printf("HWM next %d\n",coin->blocks.hwmchain.height+1); + iguana_blockQ(coin,bp,bundlei,next->RO.hash2,1); } } else { if ( bits256_nonz(bp->hashes[bundlei]) > 0 ) { - //printf("next %d\n",coin->blocks.hwmchain.height+1); + printf("next %d\n",coin->blocks.hwmchain.height+1); iguana_blockQ(coin,bp,bundlei,bp->hashes[bundlei],0); } else if ( bp->speculative != 0 && bits256_nonz(bp->speculative[bundlei]) > 0 ) { - //printf("speculative next %d\n",coin->blocks.hwmchain.height+1); + printf("speculative next %d\n",coin->blocks.hwmchain.height+1); iguana_blockQ(coin,0,-1,bp->speculative[bundlei],0); } } @@ -915,14 +930,14 @@ int32_t iguana_reqblocks(struct iguana_info *coin) } if ( next != 0 ) { - //printf("have next\n"); + //printf("have next %d\n",coin->blocks.hwmchain.height); if ( memcmp(next->RO.prev_block.bytes,coin->blocks.hwmchain.RO.hash2.bytes,sizeof(bits256)) == 0 ) { if ( _iguana_chainlink(coin,next) != 0 ) lflag++, flag++; - //else printf("chainlink error for %d\n",coin->blocks.hwmchain.height+1); + else printf("chainlink error for %d\n",coin->blocks.hwmchain.height+1); } - if ( 1 && queue_size(&coin->blocksQ) == 0 ) + if ( 1 || queue_size(&coin->blocksQ) == 0 ) { double threshold,lag = OS_milliseconds() - coin->backstopmillis; threshold = (10 + coin->longestchain - coin->blocksrecv); @@ -933,7 +948,7 @@ int32_t iguana_reqblocks(struct iguana_info *coin) else threshold = coin->avetime; threshold *= 100. * sqrt(threshold) * .000777; if ( strcmp(coin->symbol,"BTC") != 0 ) - threshold = 1000; + threshold = 300; else threshold = 10000; if ( coin->blocks.hwmchain.height < coin->longestchain && (coin->backstop != coin->blocks.hwmchain.height+1 || lag > threshold) ) { @@ -953,8 +968,6 @@ int32_t iguana_reqblocks(struct iguana_info *coin) } } } - else if ( 0 && bits256_nonz(next->RO.prev_block) > 0 ) - printf("next prev cmp error nonz.%d\n",bits256_nonz(next->RO.prev_block)); } } } @@ -966,7 +979,9 @@ int32_t iguana_processrecv(struct iguana_info *coin) // single threaded int32_t newhwm = 0,flag = 0; //printf("process bundlesQ\n"); flag += iguana_processbundlesQ(coin,&newhwm); + //printf("iguana_reqhdrs\n"); flag += iguana_reqhdrs(coin); + //printf("iguana_reqblocks\n"); flag += iguana_reqblocks(coin); return(flag); } diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index 0521b62b4..b0f459ba2 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -16,7 +16,7 @@ #include "iguana777.h" #include "SuperNET.h" -#define RPCARGS struct supernet_info *myinfo,struct iguana_info *coin,cJSON *params[],int32_t n,cJSON *json,char *remoteaddr +#define RPCARGS struct supernet_info *myinfo,struct iguana_info *coin,cJSON *params[],int32_t n,cJSON *json,char *remoteaddr,cJSON *array char *sglue(cJSON *json,struct supernet_info *myinfo,struct iguana_info *coin,char *remoteaddr,char *agent,char *method) { @@ -31,7 +31,7 @@ char *sglue(cJSON *json,struct supernet_info *myinfo,struct iguana_info *coin,ch if ( (retjson= cJSON_Parse(retstr)) != 0 ) { jdelete(retjson,"tag"); - //printf("RPCret.(%s) n.%d\n",jprint(retjson,0),cJSON_GetArraySize(retjson)); + ///printf("RPCret.(%s) n.%d\n",jprint(retjson,0),cJSON_GetArraySize(retjson)); result = cJSON_GetObjectItem(retjson,"result"); error = cJSON_GetObjectItem(retjson,"error"); if ( result != 0 && cJSON_GetArraySize(retjson) == 1 ) @@ -182,289 +182,306 @@ static char *addnode(RPCARGS) // address and pubkeys static char *validateaddress(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","validateaddress","address",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","validateaddress","address",params[0])); } static char *validatepubkey(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","validatepubkey","pubkey",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","validatepubkey","pubkey",params[0])); } static char *createmultisig(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","createmultisig","M",params[0],"pubkeys",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","createmultisig","M",params[0],"pubkeys",params[1])); } static char *addmultisigaddress(RPCARGS) { - return(sglue3(0,myinfo,coin,remoteaddr,"ramchain","createmultisig","M",params[0],"pubkeys",params[1],"account",params[2])); + return(sglue3(0,myinfo,coin,remoteaddr,"bitcoinrpc","createmultisig","M",params[0],"pubkeys",params[1],"account",params[2])); } // blockchain static char *getinfo(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","status")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","status")); } static char *getbestblockhash(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","getbestblockhash")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","getbestblockhash")); } static char *getblockcount(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","getblockcount")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","getblockcount")); } static char *getblock(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","getblock","blockhash",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","getblock","blockhash",params[0])); } static char *getblockhash(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","getblockhash","height",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","getblockhash","height",params[0])); } static char *gettransaction(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","tx","txid",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","gettransaction","txid",params[0])); } static char *listtransactions(RPCARGS) { - return(sglue3(0,myinfo,coin,remoteaddr,"ramchain","listtransactions","account",params[0],"count",params[1],"from",params[2])); + return(sglue3(0,myinfo,coin,remoteaddr,"bitcoinrpc","listtransactions","account",params[0],"count",params[1],"from",params[2])); } static char *getreceivedbyaddress(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","getreceivedbyaddress","address",params[0],"minconfs",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","getreceivedbyaddress","address",params[0],"minconfs",params[1])); } static char *listreceivedbyaddress(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","listreceivedbyaddress","minconf",params[0],"includeempty",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","listreceivedbyaddress","minconf",params[0],"includeempty",params[1])); } static char *listsinceblock(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","listsinceblock","blockhash",params[0],"target",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","listsinceblock","blockhash",params[0],"target",params[1])); } // waccount and waddress funcs static char *getreceivedbyaccount(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","getreceivedbyaccount","account",params[0],"minconfs",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","getreceivedbyaccount","account",params[0],"minconfs",params[1])); } static char *listreceivedbyaccount(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","listreceivedbyaccount","account",params[0],"includeempty",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","listreceivedbyaccount","account",params[0],"includeempty",params[1])); } static char *getnewaddress(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","getnewaddress","account",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","getnewaddress","account",params[0])); } static char *vanitygen(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","vanitygen","vanity",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","vanitygen","vanity",params[0])); } static char *makekeypair(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","makekeypair")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","makekeypair")); } static char *getaccountaddress(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","getaccountaddress","account",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","getaccountaddress","account",params[0])); } static char *setaccount(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","setaccount","address",params[0],"account",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","setaccount","address",params[0],"account",params[1])); } static char *getaccount(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","getaccount","address",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","getaccount","address",params[0])); } static char *getaddressesbyaccount(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","getaddressesbyaccount","account",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","getaddressesbyaccount","account",params[0])); } static char *listaddressgroupings(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","listaddressgroupings")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","listaddressgroupings")); } static char *getbalance(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","getbalance","account",params[0],"minconf",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","getbalance","account",params[0],"minconf",params[1])); } // wallet static char *listaccounts(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","listaccounts","minconf",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","listaccounts","minconf",params[0])); } static char *dumpprivkey(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","dumpprivkey","address",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","dumpprivkey","address",params[0])); } static char *importprivkey(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","importprivkey","wif",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","importprivkey","wif",params[0])); } static char *dumpwallet(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","dumpwallet")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","dumpwallet")); } static char *importwallet(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","importwallet","wallet",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","importwallet","wallet",params[0])); } static char *walletpassphrase(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","walletpassphrase","passphrase",params[0],"timeout",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","walletpassphrase","passphrase",params[0],"timeout",params[1])); } static char *walletpassphrasechange(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","walletpassphrasechange","oldpassphrase",params[0],"newpassphrase",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","walletpassphrasechange","oldpassphrase",params[0],"newpassphrase",params[1])); } static char *walletlock(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","walletlock")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","walletlock")); } static char *encryptwallet(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","encryptwallet","passphrase",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","encryptwallet","passphrase",params[0])); } static char *checkwallet(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","checkwallet")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","checkwallet")); } static char *repairwallet(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","repairwallet")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","repairwallet")); } static char *backupwallet(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","backupwallet","filename",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","backupwallet","filename",params[0])); } // messages static char *signmessage(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","signmessage","address",params[0],"message",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","signmessage","address",params[0],"message",params[1])); } static char *verifymessage(RPCARGS) { - return(sglue3(0,myinfo,coin,remoteaddr,"ramchain","verifymessage","address",params[0],"sig",params[1],"message",params[2])); + return(sglue3(0,myinfo,coin,remoteaddr,"bitcoinrpc","verifymessage","address",params[0],"sig",params[1],"message",params[2])); } // unspents static char *listunspent(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","listunspent","minconf",params[0],"maxconf",params[1])); + int32_t numrmds,minconf=0,maxconf=0,m = 0; uint8_t *rmdarray; cJSON *retjson; + retjson = cJSON_CreateArray(); + if ( (minconf= juint(params[0],0)) > 0 ) + { + m++; + if ( (maxconf= juint(params[1],0)) > 0 ) + m++; + } + if ( minconf == 0 ) + minconf = 1; + if ( maxconf == 0 ) + maxconf = 9999999; + rmdarray = iguana_rmdarray(coin,&numrmds,array,m); + iguana_unspents(myinfo,coin,retjson,minconf,maxconf,rmdarray,numrmds); + if ( rmdarray != 0 ) + free(rmdarray); + return(jprint(retjson,1)); +// return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","listunspent","minconf",params[0],"maxconf",params[1])); } static char *lockunspent(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","lockunspent","flag",params[0],"array",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","lockunspent","flag",params[0],"array",params[1])); } static char *listlockunspent(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","listlockunspent")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","listlockunspent")); } static char *gettxout(RPCARGS) { - return(sglue3(0,myinfo,coin,remoteaddr,"ramchain","gettxout","txid",params[0],"vout",params[1],"mempool",params[2])); + return(sglue3(0,myinfo,coin,remoteaddr,"bitcoinrpc","gettxout","txid",params[0],"vout",params[1],"mempool",params[2])); } static char *gettxoutsetinfo(RPCARGS) { - return(sglue(0,myinfo,coin,remoteaddr,"ramchain","gettxoutsetinfo")); + return(sglue(0,myinfo,coin,remoteaddr,"bitcoinrpc","gettxoutsetinfo")); } // payments static char *sendtoaddress(RPCARGS) { - return(sglue4(0,myinfo,coin,remoteaddr,"ramchain","sendtoaddress","address",params[0],"amount",params[1],"comment",params[2],"comment2",params[3])); + return(sglue4(0,myinfo,coin,remoteaddr,"bitcoinrpc","sendtoaddress","address",params[0],"amount",params[1],"comment",params[2],"comment2",params[3])); } static char *movecmd(RPCARGS) { - return(sglue5(0,myinfo,coin,remoteaddr,"ramchain","move","fromaccount",params[0],"toaccount",params[1],"amount",params[2],"minconf",params[3],"comment",params[4])); + return(sglue5(0,myinfo,coin,remoteaddr,"bitcoinrpc","move","fromaccount",params[0],"toaccount",params[1],"amount",params[2],"minconf",params[3],"comment",params[4])); } static char *sendfrom(RPCARGS) { - return(sglue6(0,myinfo,coin,remoteaddr,"ramchain","sendfrom","fromaccount",params[0],"toaddress",params[1],"amount",params[2],"minconf",params[3],"comment",params[4],"comment2",params[5])); + return(sglue6(0,myinfo,coin,remoteaddr,"bitcoinrpc","sendfrom","fromaccount",params[0],"toaddress",params[1],"amount",params[2],"minconf",params[3],"comment",params[4],"comment2",params[5])); } static char *sendmany(RPCARGS) { - return(sglue4(0,myinfo,coin,remoteaddr,"ramchain","sendmany","fromaccount",params[0],"payments",params[1],"minconf",params[2],"comment",params[3])); + return(sglue4(0,myinfo,coin,remoteaddr,"bitcoinrpc","sendmany","fromaccount",params[0],"payments",params[1],"minconf",params[2],"comment",params[3])); } static char *settxfee(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","settxfee","amount",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","settxfee","amount",params[0])); } // rawtransaction static char *getrawtransaction(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","getrawtransaction","txid",params[0],"verbose",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","getrawtransaction","txid",params[0],"verbose",params[1])); } static char *createrawtransaction(RPCARGS) { - return(sglue2(0,myinfo,coin,remoteaddr,"ramchain","createrawtransaction","vins",params[0],"vouts",params[1])); + return(sglue2(0,myinfo,coin,remoteaddr,"bitcoinrpc","createrawtransaction","vins",params[0],"vouts",params[1])); } static char *decoderawtransaction(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","decoderawtransaction","rawtx",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","decoderawtransaction","rawtx",params[0])); } static char *decodescript(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","decodescript","script",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","decodescript","script",params[0])); } static char *signrawtransaction(RPCARGS) { - return(sglue3(0,myinfo,coin,remoteaddr,"ramchain","signrawtransaction","rawtx",params[0],"vins",params[1],"privkeys",params[2])); + return(sglue3(0,myinfo,coin,remoteaddr,"bitcoinrpc","signrawtransaction","rawtx",params[0],"vins",params[1],"privkeys",params[2])); } static char *sendrawtransaction(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","sendrawtransaction","rawtx",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","sendrawtransaction","rawtx",params[0])); } static char *getrawchangeaddress(RPCARGS) { - return(sglue1(0,myinfo,coin,remoteaddr,"ramchain","getrawchangeaddress","account",params[0])); + return(sglue1(0,myinfo,coin,remoteaddr,"bitcoinrpc","getrawchangeaddress","account",params[0])); } #define true 1 @@ -574,13 +591,13 @@ int32_t is_bitcoinrpc(char *method,char *remoteaddr) return(-1); } -char *iguana_bitcoinrpc(struct supernet_info *myinfo,struct iguana_info *coin,char *method,cJSON *params[16],int32_t n,cJSON *json,char *remoteaddr) +char *iguana_bitcoinrpc(struct supernet_info *myinfo,struct iguana_info *coin,char *method,cJSON *params[16],int32_t n,cJSON *json,char *remoteaddr,cJSON *array) { int32_t i; for (i=0; i> 24), script[n++] = (locktime >> 16), script[n++] = (locktime >> 8), script[n++] = locktime; + script[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY; + script[n++] = SCRIPT_OP_DROP; + return(n); +} + +int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp) +{ + int32_t i,plen; + script[n++] = 0x50 + vp->M; + for (i=0; iN; i++) + { + if ( (plen= bitcoin_pubkeylen(vp->signers[i].pubkey)) < 0 ) + return(-1); + script[n++] = plen; + memcpy(&script[n],vp->signers[i].pubkey,plen); + n += plen; + } + script[n++] = 0x50 + vp->N; + script[n++] = SCRIPT_OP_CHECKMULTISIG; + calc_rmd160_sha256(p2sh_rmd160,script,n); + return(n); +} + +int32_t bitcoin_p2shscript(uint8_t *script,int32_t n,const uint8_t *p2shscript,const int32_t p2shlen) +{ + if ( p2shlen >= 0xfd ) + { + script[n++] = 0x4d; + script[n++] = (p2shlen & 0xff); + script[n++] = ((p2shlen >> 8) & 0xff); + } + else + { + script[n++] = 0x4c; + script[n++] = p2shlen; + } + memcpy(&script[n],p2shscript,p2shlen), n += p2shlen; + return(n); +} + +int32_t bitcoin_changescript(struct iguana_info *coin,uint8_t *changescript,int32_t n,uint64_t *changep,char *changeaddr,uint64_t inputsatoshis,uint64_t satoshis,uint64_t txfee) +{ + uint8_t addrtype,rmd160[20]; int32_t len; + *changep = 0; + if ( inputsatoshis >= (satoshis + txfee) ) + { + *changep = inputsatoshis - (satoshis + txfee); + if ( changeaddr != 0 && changeaddr[0] != 0 ) + { + bitcoin_addr2rmd160(&addrtype,rmd160,changeaddr); + if ( addrtype == coin->chain->pubtype ) + len = bitcoin_standardspend(changescript,0,rmd160); + else if ( addrtype == coin->chain->p2shtype ) + len = bitcoin_standardspend(changescript,0,rmd160); + else + { + printf("error with mismatched addrtype.%02x vs (%02x %02x)\n",addrtype,coin->chain->pubtype,coin->chain->p2shtype); + return(-1); + } + return(len); + } + else printf("error no change address when there is change\n"); + } + return(-1); +} + +int32_t bitcoin_scriptsig(struct iguana_info *coin,uint8_t *script,int32_t n,const struct vin_info *vp,struct iguana_msgtx *msgtx) +{ + int32_t i,siglen; + if ( vp->N > 1 ) + script[n++] = SCRIPT_OP_NOP; + for (i=0; iN; i++) + { + if ( (siglen= vp->signers[i].siglen) != 0 ) + { + script[n++] = siglen; + memcpy(&script[n],vp->signers[i].sig,siglen), n += siglen; + } + } + if ( vp->type == IGUANA_SCRIPT_P2SH ) + { + printf("add p2sh script to sig\n"); + n = bitcoin_p2shscript(script,n,vp->p2shscript,vp->p2shlen); + } + return(n); +} + +int32_t bitcoin_cltvscript(uint8_t p2shtype,char *ps2h_coinaddr,uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,char *senderaddr,char *otheraddr,uint8_t secret160[20],uint32_t locktime) +{ + // OP_IF + // OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + // OP_ELSE + // OP_HASH160 secret160 OP_EQUALVERIFY OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG // standard spend + // OP_ENDIF + uint8_t rmd160A[20],rmd160B[20],addrtypeA,addrtypeB; + bitcoin_addr2rmd160(&addrtypeA,rmd160A,senderaddr); + bitcoin_addr2rmd160(&addrtypeB,rmd160B,otheraddr); + script[n++] = SCRIPT_OP_IF; + n = bitcoin_checklocktimeverify(script,n,locktime); + n = bitcoin_standardspend(script,n,rmd160A); + script[n++] = SCRIPT_OP_ELSE; + n = bitcoin_revealsecret160(script,n,secret160); + n = bitcoin_standardspend(script,n,rmd160B); + script[n++] = SCRIPT_OP_ENDIF; + calc_rmd160_sha256(p2sh_rmd160,script,n); + bitcoin_address(ps2h_coinaddr,p2shtype,p2sh_rmd160,20); + return(n); +} + +int32_t iguana_scriptgen(struct iguana_info *coin,int32_t *Mp,int32_t *nump,char *coinaddr,uint8_t *script,char *asmstr,uint8_t rmd160[20],uint8_t type,const struct vin_info *vp,int32_t txi) +{ + uint8_t addrtype; char rmd160str[41],pubkeystr[256]; int32_t plen,i,m,n,flag = 0,scriptlen = 0; + m = n = 1; + asmstr[0] = 0; + if ( type == IGUANA_SCRIPT_76A988AC || type == IGUANA_SCRIPT_76AC || type == IGUANA_SCRIPT_P2SH ) + { + if ( type == IGUANA_SCRIPT_P2SH ) + addrtype = coin->chain->p2shtype; + else addrtype = coin->chain->pubtype; + init_hexbytes_noT(rmd160str,rmd160,20); + bitcoin_address(coinaddr,addrtype,rmd160,20); + } + switch ( type ) + { + case IGUANA_SCRIPT_NULL: + strcpy(asmstr,txi == 0 ? "coinbase " : "PoSbase "); + flag++; + coinaddr[0] = 0; + break; + case IGUANA_SCRIPT_76AC: + if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) < 0 ) + return(0); + init_hexbytes_noT(pubkeystr,(uint8_t *)vp->signers[0].pubkey,plen); + sprintf(asmstr,"OP_DUP %s OP_CHECKSIG // %s",pubkeystr,coinaddr); + scriptlen = bitcoin_pubkeyspend(script,0,(uint8_t *)vp->signers[0].pubkey); + //printf("[%02x] scriptlen.%d (%s)\n",vp->signers[0].pubkey[0],scriptlen,asmstr); + break; + case IGUANA_SCRIPT_76A988AC: + sprintf(asmstr,"OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG // %s",rmd160str,coinaddr); + scriptlen = bitcoin_standardspend(script,0,rmd160); + break; + case IGUANA_SCRIPT_P2SH: + sprintf(asmstr,"OP_HASH160 %s OP_EQUAL // %s",rmd160str,coinaddr); + scriptlen = bitcoin_p2shspend(script,0,rmd160); + break; + case IGUANA_SCRIPT_OPRETURN: + strcpy(asmstr,"OP_RETURN "); + flag++; + break; + case IGUANA_SCRIPT_3of3: m = 3, n = 3; break; + case IGUANA_SCRIPT_2of3: m = 2, n = 3; break; + case IGUANA_SCRIPT_1of3: m = 1, n = 3; break; + case IGUANA_SCRIPT_2of2: m = 2, n = 2; break; + case IGUANA_SCRIPT_1of2: m = 1, n = 2; break; + case IGUANA_SCRIPT_MSIG: m = vp->M, n = vp->N; break; + case IGUANA_SCRIPT_DATA: + strcpy(asmstr,"DATA ONLY"); + flag++; + break; + case IGUANA_SCRIPT_STRANGE: + strcpy(asmstr,"STRANGE SCRIPT "); + flag++; + break; + default: break;//printf("unexpected script type.%d\n",type); break; + } + if ( n > 1 ) + { + scriptlen = bitcoin_MofNspendscript(rmd160,script,0,vp); + sprintf(asmstr,"%d ",m); + for (i=0; isigners[i].pubkey)) > 0 ) + { + init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->signers[i].pubkey,plen); + strcat(asmstr," "); + } else strcat(asmstr,"NOPUBKEY "); + } + sprintf(asmstr + strlen(asmstr),"%d // M.%d of N.%d [",n,m,n); + for (i=0; isigners[i].coinaddr,ispendlen > 0 ) + init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->spendscript,vp->spendlen); + *Mp = m, *nump = n; + return(scriptlen); +} + +int32_t iguana_expandscript(struct iguana_info *coin,char *asmstr,int32_t maxlen,uint8_t *script,int32_t scriptlen) +{ + asmstr[0] = 0; + return(0); +} + +int32_t _iguana_calcrmd160(struct iguana_info *coin,struct vin_info *vp) +{ + static uint8_t zero_rmd160[20]; + char hexstr[8192]; uint8_t sha256[32],*script,type; int32_t i,n,m,plen; + vp->N = 1; + vp->M = 1; + type = IGUANA_SCRIPT_STRANGE; + if ( vp->spendlen == 0 ) + { + if ( zero_rmd160[0] == 0 ) + { + calc_rmd160_sha256(zero_rmd160,vp->spendscript,vp->spendlen); + //vcalc_sha256(0,sha256,vp->spendscript,vp->spendlen); // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + //calc_rmd160(0,zero_rmd160,sha256,sizeof(sha256)); // b472a266d0bd89c13706a4132ccfb16f7c3b9fcb + init_hexbytes_noT(hexstr,zero_rmd160,20); + char str[65]; printf("iguana_calcrmd160 zero len %s -> %s\n",bits256_str(str,*(bits256 *)sha256),hexstr); + } + memcpy(vp->rmd160,zero_rmd160,sizeof(zero_rmd160)); + return(IGUANA_SCRIPT_NULL); + } + else if ( vp->spendscript[0] == SCRIPT_OP_RETURN ) + type = IGUANA_SCRIPT_OPRETURN; + else if ( vp->spendscript[0] == SCRIPT_OP_DUP && vp->spendscript[1] == SCRIPT_OP_HASH160 && vp->spendscript[2] == 20 && vp->spendscript[vp->spendscript[2]+3] == SCRIPT_OP_EQUALVERIFY && vp->spendscript[vp->spendscript[2]+4] == SCRIPT_OP_CHECKSIG ) + { + //printf("IGUANA_SCRIPT_76A988AC plen.%d vs %d vp->spendlen\n",vp->spendscript[2]+4,vp->spendlen); + // 76a9145f69cb73016264270dae9f65c51f60d0e4d6fd4488ac + memcpy(vp->rmd160,&vp->spendscript[3],20); + if ( (plen= vp->spendscript[2]+5) != vp->spendlen ) + { + return(IGUANA_SCRIPT_STRANGE); + while ( plen < vp->spendlen ) + if ( vp->spendscript[plen++] != 0x61 ) // nop + return(IGUANA_SCRIPT_STRANGE); + } + return(IGUANA_SCRIPT_76A988AC); + } + // 21035f1321ed17d387e4433b2fa229c53616057964af065f98bfcae2233c5108055eac + else if ( vp->spendscript[0] > 0 && vp->spendscript[0] < 76 && vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKSIG && vp->spendscript[0] == vp->spendlen-2 ) + { + memcpy(vp->signers[0].pubkey,&vp->spendscript[1],vp->spendscript[0]); + calc_rmd160_sha256(vp->rmd160,vp->signers[0].pubkey,vp->spendscript[0]); + return(IGUANA_SCRIPT_76AC); + } + else if ( vp->spendscript[0] == SCRIPT_OP_HASH160 && vp->spendscript[1] == 0x14 && vp->spendlen == 23 && vp->spendscript[22] == SCRIPT_OP_EQUAL ) + { + memcpy(vp->rmd160,vp->spendscript+2,20); + return(IGUANA_SCRIPT_P2SH); + } + else if ( vp->spendlen > 34 && vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKMULTISIG && (n= vp->spendscript[vp->spendlen-2]) >= 0x51 && n <= 0x60 && (m= vp->spendscript[0]) >= 0x51 && m <= n ) // m of n multisig + { + m -= 0x50, n -= 0x50; + script = vp->spendscript+1; + for (i=0; isigners[i].pubkey,script,plen); + calc_rmd160_sha256(vp->signers[i].rmd160,vp->signers[i].pubkey,plen); + bitcoin_address(vp->signers[i].coinaddr,coin->chain->pubtype,vp->signers[i].pubkey,plen); + } + if ( (int32_t)((long)script - (long)vp->spendscript) == vp->spendlen-2 ) + { + vp->N = n; + vp->M = m; + //printf("M.%d N.%d\n",m,n); + } + calc_rmd160_sha256(vp->rmd160,vp->spendscript,vp->spendlen); + if ( n == 3 ) + { + if ( m == 3 ) + return(IGUANA_SCRIPT_3of3); + else if ( m == 2 ) + return(IGUANA_SCRIPT_2of3); + else if ( m == 1 ) + return(IGUANA_SCRIPT_1of3); + } + else if ( n == 2 ) + { + if ( m == 2 ) + return(IGUANA_SCRIPT_2of2); + else if ( m == 1 ) + return(IGUANA_SCRIPT_1of2); + } + printf("strange msig M.%d of N.%d\n",m,n); + return(IGUANA_SCRIPT_MSIG); + } + else if ( vp->spendlen == vp->spendscript[0]+1 ) + { + //printf("just data.%d\n",vp->spendlen); + memcpy(vp->rmd160,zero_rmd160,sizeof(zero_rmd160)); + return(IGUANA_SCRIPT_DATA); + } + if ( type != IGUANA_SCRIPT_OPRETURN && type != IGUANA_SCRIPT_DATA ) + { + if ( vp->spendlen > 0 && vp->spendlen < sizeof(hexstr)/2-1 ) + { + static FILE *fp; + init_hexbytes_noT(hexstr,vp->spendscript,vp->spendlen); + //char str[65]; printf("unparsed script.(%s).%d in %s len.%d\n",hexstr,vp->spendlen,bits256_str(str,vp->vin.prev_hash),vp->spendlen); + if ( 1 && fp == 0 ) + fp = fopen("unparsed.txt","w"); + if ( fp != 0 ) + fprintf(fp,"%s\n",hexstr), fflush(fp); + } else sprintf(hexstr,"pkscript overflowed %ld\n",(long)sizeof(hexstr)); + } + calc_rmd160_sha256(vp->rmd160,vp->spendscript,vp->spendlen); + return(type); +} + +int32_t iguana_calcrmd160(struct iguana_info *coin,struct vin_info *vp,uint8_t *pk_script,int32_t pk_scriptlen,bits256 debugtxid,int32_t vout,uint32_t sequence) +{ + int32_t scriptlen; uint8_t script[IGUANA_MAXSCRIPTSIZE]; char asmstr[IGUANA_MAXSCRIPTSIZE*3]; + memset(vp,0,sizeof(*vp)); + vp->vin.prev_hash = debugtxid, vp->vin.prev_vout = vout; + vp->spendlen = pk_scriptlen; + vp->vin.sequence = sequence; + memcpy(vp->spendscript,pk_script,pk_scriptlen); + if ( (vp->type= _iguana_calcrmd160(coin,vp)) >= 0 && 0 ) + { + scriptlen = iguana_scriptgen(coin,&vp->M,&vp->N,vp->coinaddr,script,asmstr,vp->rmd160,vp->type,(const struct vin_info *)vp,vout); + if ( scriptlen != pk_scriptlen || (scriptlen != 0 && memcmp(script,pk_script,scriptlen) != 0) ) + { + if ( vp->type != IGUANA_SCRIPT_OPRETURN && vp->type != IGUANA_SCRIPT_DATA && vp->type != IGUANA_SCRIPT_STRANGE ) + { + int32_t i; + printf("\n--------------------\n"); + for (i=0; itype,scriptlen,pk_scriptlen); + } + } + } + return(vp->type); +} + +int32_t bitcoin_scriptget(struct iguana_info *coin,int32_t *hashtypep,int32_t *sigsizep,int32_t *pubkeysizep,int32_t *suffixp,struct vin_info *vp,uint8_t *scriptsig,int32_t len,int32_t spendtype) +{ + char asmstr[IGUANA_MAXSCRIPTSIZE*3]; int32_t j,n,siglen,plen; + j = n = 0; + *suffixp = 0; + *hashtypep = SIGHASH_ALL; + while ( (siglen= scriptsig[n]) >= 70 && siglen <= 73 && n+siglen+1 < len && j < 16 ) + { + vp->signers[j].siglen = siglen; + memcpy(vp->signers[j].sig,&scriptsig[n+1],siglen); + if ( j == 0 ) + *hashtypep = vp->signers[j].sig[siglen-1]; + else if ( vp->signers[j].sig[siglen-1] != *hashtypep ) + { + printf("SIGHASH mismatch %d vs %d\n",vp->signers[j].sig[siglen-1],*hashtypep); + } + (*sigsizep) += (siglen + 1); + n += (siglen + 1); + j++; + if ( spendtype == 0 && j > 1 ) + spendtype = IGUANA_SCRIPT_MSIG; + } + vp->type = spendtype; + j = 0; + while ( ((plen= scriptsig[n]) == 33 || plen == 65 ) && j < 16 ) + { + memcpy(vp->signers[j].pubkey,&scriptsig[n+1],plen); + calc_rmd160_sha256(vp->signers[j].rmd160,vp->signers[j].pubkey,plen); + if ( j == 0 ) + memcpy(vp->rmd160,vp->signers[j].rmd160,20); + n += (plen + 1); + (*pubkeysizep) += plen; + j++; + } + if ( n < len && (scriptsig[n] == 0x4c || scriptsig[n] == 0x4d) ) + { + if ( scriptsig[n] == 0x4c ) + vp->p2shlen = scriptsig[n+1], n += 2; + else vp->p2shlen = ((uint32_t)scriptsig[n+1] + ((uint32_t)scriptsig[n+2] << 8)), n += 3; + memcpy(vp->p2shscript,&scriptsig[n],vp->p2shlen); + n += vp->p2shlen; + vp->type = IGUANA_SCRIPT_P2SH; + } + if ( n < len ) + *suffixp = (len - n); + /*if ( len == 0 ) + { + // txid.(eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2).v1 + decode_hex(vp->rmd160,20,"010966776006953d5567439e5e39f86a0d273bee");//3564a74f9ddb4372301c49154605573d7d1a88fe"); + vp->type = IGUANA_SCRIPT_76A988AC; + }*/ + vp->spendlen = iguana_scriptgen(coin,&vp->M,&vp->N,vp->coinaddr,vp->spendscript,asmstr,vp->rmd160,vp->type,(const struct vin_info *)vp,vp->vin.prev_vout); + //printf("type.%d asmstr.(%s) spendlen.%d\n",vp->type,asmstr,vp->spendlen); + return(vp->spendlen); +} + +int32_t iguana_vinscriptparse(struct iguana_info *coin,struct vin_info *vp,int32_t *sigsizep,int32_t *pubkeysizep,int32_t *p2shsizep,int32_t *suffixp,uint8_t *vinscript,int32_t scriptlen) +{ + int32_t hashtype; + *sigsizep = *pubkeysizep = *p2shsizep = *suffixp = 0; + if ( bitcoin_scriptget(coin,&hashtype,sigsizep,pubkeysizep,suffixp,vp,vinscript,scriptlen,0) < 0 ) + { + printf("iguana_vinscriptparse: error parsing vinscript?\n"); + return(-1); + } + if ( vp->type == IGUANA_SCRIPT_P2SH ) + *p2shsizep = vp->p2shlen + 1 + (vp->p2shlen >= 0xfd)*2; + return(hashtype); +} + +char *iguana_scriptget(struct iguana_info *coin,char *scriptstr,char *asmstr,int32_t max,int32_t hdrsi,uint32_t unspentind,bits256 txid,int32_t vout,uint8_t *rmd160,int32_t type,uint8_t *pubkey33) +{ + int32_t scriptlen; uint8_t script[IGUANA_MAXSCRIPTSIZE]; struct vin_info V,*vp = &V; + memset(vp,0,sizeof(*vp)); + scriptstr[0] = asmstr[0] = 0; + if ( pubkey33 != 0 && bitcoin_pubkeylen(pubkey33) > 0 ) + memcpy(vp->signers[0].pubkey,pubkey33,33); + scriptlen = iguana_scriptgen(coin,&vp->M,&vp->N,vp->coinaddr,script,asmstr,rmd160,type,(const struct vin_info *)vp,vout); + init_hexbytes_noT(scriptstr,script,scriptlen); + return(scriptstr); +} + +/*void iguana_bundlescript(struct iguana_info *coin,uint32_t offset,struct iguana_bundle *bp,uint32_t ind,uint8_t *spendscript,int32_t spendlen) +{ + long size = sizeof(offset) + sizeof(ind); uint32_t *ptr; + if ( bp->numscriptsmaps >= bp->maxscriptsmaps ) + { + bp->scriptsmap = realloc(bp->scriptsmap,(1000+bp->maxscriptsmaps) * (sizeof(offset) + sizeof(ind))); + bp->maxscriptsmaps += 1000; + } + ptr = (void *)((long)bp->scriptsmap + bp->numscriptsmaps*size); + ptr[0] = ind; + ptr[1] = offset; + bp->numscriptsmaps++; +}*/ + +uint32_t iguana_scriptstableadd(struct iguana_info *coin,int32_t spendflag,uint32_t fpos,uint8_t *script,uint16_t scriptlen) +{ + struct scriptinfo *ptr; + HASH_FIND(hh,coin->scriptstable[spendflag],script,scriptlen,ptr); + if ( ptr == 0 ) + { + ptr = mycalloc('w',1,sizeof(*ptr) + scriptlen); + ptr->fpos = fpos; + ptr->scriptlen = scriptlen; + memcpy(ptr->script,script,scriptlen); + HASH_ADD(hh,coin->scriptstable[spendflag],script,scriptlen,ptr); + } + return(fpos); +} + +uint32_t iguana_scriptstablefind(struct iguana_info *coin,int32_t spendflag,uint8_t *script,int32_t scriptlen) +{ + struct scriptinfo *ptr; + HASH_FIND(hh,coin->scriptstable[spendflag],script,scriptlen,ptr); + if ( ptr != 0 ) + return(ptr->fpos); + else return(0); +} + +long iguana_rwscript(struct iguana_info *coin,int32_t rwflag,void *fileptr,long offset,long filesize,FILE *fp,struct iguana_bundle *bp,uint8_t **scriptptrp,int32_t *lenp,int32_t hdrsi,uint32_t ind,int32_t spendflag) +{ + long scriptpos; struct scriptdata data; uint8_t *script = *scriptptrp; + if ( spendflag == 0 && (scriptpos= iguana_scriptstablefind(coin,spendflag,script,*lenp)) != 0 ) + return(scriptpos); + memset(&data,0,sizeof(data)); + if ( rwflag != 0 && fp != 0 && fileptr == 0 ) + { + scriptpos = ftell(fp); + data.ind = ind, data.spendflag = spendflag; + data.hdrsi = hdrsi; + data.scriptlen = *lenp; + if ( fwrite(&data,1,sizeof(data),fp) != sizeof(data) ) + return(-1); + if ( fwrite(script,1,data.scriptlen,fp) != data.scriptlen ) + return(-1); + offset = (uint32_t)ftell(fp); + printf("spend.%d filesize.%ld wrote.h%d u%d len.%d [%ld,%ld) crc.%08x\n",spendflag,coin->scriptsfilesize[spendflag],hdrsi,ind,data.scriptlen,scriptpos,ftell(fp),calc_crc32(0,script,data.scriptlen)); + } + else if ( rwflag == 0 && fp == 0 && fileptr != 0 ) + { + scriptpos = offset; + if ( offset+sizeof(data) <= filesize ) + { + memcpy(&data,(void *)((long)fileptr + offset),sizeof(data)); + if ( data.scriptlen > 0 && data.scriptlen < *lenp && offset+sizeof(data)+data.scriptlen <= filesize ) + { + if ( data.scriptlen > 0 ) + { + *scriptptrp = script = (void *)((long)fileptr + offset); + offset += data.scriptlen + sizeof(data); + if ( data.hdrsi < coin->bundlescount ) + bp = coin->bundles[data.hdrsi]; + else printf("illegal hdrsi.%d/%d\n",data.hdrsi,coin->bundlescount); + } else printf("illegal scriptlen %d\n",data.scriptlen); + //printf("hdrsi.%d loaded script.%d %u s%d\n",data.hdrsi,data.scriptlen,data.ind,data.spendflag); + } + else if ( data.scriptlen > 0 ) + { + printf("spendlen overflow.%d vs %d\n",data.scriptlen,*lenp); + return(-1); + } + } + else + { + printf("error reading from %ld\n",scriptpos); + return(-1); + } + //printf("hdrsi.%d scriptlen.%d\n",data.hdrsi,data.scriptlen); + *lenp = data.scriptlen; + } + if ( bp != 0 ) + { + //if ( spendflag == 0 ) + iguana_scriptstableadd(coin,spendflag,(uint32_t)scriptpos,script,*lenp); + } + else if ( rwflag == 0 ) + { + printf("null bp for iguana_rwscript hdrsi.%d/%d\n",data.hdrsi,coin->bundlescount); + return(-1); + } + return(offset); +} + +long iguana_initscripts(struct iguana_info *coin) +{ + long fpos=0,offset = 0; uint8_t scriptdata[IGUANA_MAXSCRIPTSIZE],*scriptptr; int32_t spendflag,size,n=0; struct scriptdata script; + for (spendflag=0; spendflag<2; spendflag++) + { + portable_mutex_lock(&coin->scripts_mutex[spendflag]); + sprintf(coin->scriptsfname[spendflag],"tmp/%s/%sscripts",coin->symbol,spendflag==0?"":"sig"), OS_portable_path(coin->scriptsfname[spendflag]); + printf("scripts fname.(%s)\n",coin->scriptsfname[spendflag]); + if ( (coin->scriptsptr[spendflag]= OS_mapfile(coin->scriptsfname[spendflag],&coin->scriptsfilesize[spendflag],0)) == 0 ) + { + coin->scriptsfp[spendflag] = fopen(coin->scriptsfname[spendflag],"wb"); + memset(&script,0,sizeof(script)); + fwrite(&script,1,sizeof(script),coin->scriptsfp[spendflag]); + } + else + { + while ( 1 ) + { + size = sizeof(scriptdata); + scriptptr = scriptdata; + if ( (offset= iguana_rwscript(coin,0,coin->scriptsptr[spendflag],offset,coin->scriptsfilesize[spendflag],0,0,&scriptptr,&size,0,0,spendflag)) < 0 ) + break; + else fpos = offset; + n++; + } + coin->scriptsfp[spendflag] = fopen(coin->scriptsfname[spendflag],"ab"); + portable_mutex_unlock(&coin->scripts_mutex[spendflag]); + printf("initialized %d scripts, fpos %ld\n",n,fpos); + return(offset); + } + portable_mutex_unlock(&coin->scripts_mutex[spendflag]); + } + return(-1); +} + +uint32_t iguana_scriptsave(struct iguana_info *coin,struct iguana_bundle *bp,uint32_t ind,int32_t spendflag,uint8_t *script,int32_t scriptlen) +{ + FILE *fp; long fpos = 0; + if ( scriptlen > 0 && (fp= coin->scriptsfp[spendflag]) != 0 ) + { + portable_mutex_lock(&coin->scripts_mutex[spendflag]); + fpos = ftell(fp); + if ( iguana_rwscript(coin,1,0,0,0,fp,bp,&script,&scriptlen,bp->hdrsi,ind,spendflag) < 0 ) + { + fseek(fp,fpos,SEEK_SET); + fpos = -1; + printf("error saving script at %ld\n",fpos); + } else fflush(fp); + portable_mutex_unlock(&coin->scripts_mutex[spendflag]); + } else printf("cant scriptsave.%d to (%s).%p scriptlen.%d\n",spendflag,coin->scriptsfname[spendflag],coin->scriptsfp[spendflag],scriptlen); + return((uint32_t)fpos); +} + +long iguana_scriptadd(struct iguana_info *coin,struct iguana_bundle *bp,uint32_t unspentind,int32_t type,uint8_t *spendscript,int32_t spendlen,uint8_t rmd160[20],int32_t vout) +{ + static long total,saved; + int32_t scriptlen; char asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; uint8_t script[IGUANA_MAXSCRIPTSIZE]; long fpos=0; struct vin_info V,*vp = &V; + if ( spendlen == 0 ) + { + printf("null script?\n"); + getchar(); + return(0); + } + memset(vp,0,sizeof(*vp)); + asmstr[0] = 0; + total++; + scriptlen = iguana_scriptgen(coin,&vp->M,&vp->N,vp->coinaddr,script,asmstr,rmd160,type,(const struct vin_info *)vp,vout); + if ( scriptlen == spendlen && memcmp(script,spendscript,scriptlen) == 0 ) + return(0); + else + { + saved++; + if ( (saved % 1000) == 0 ) + printf("add type.%d scriptlen.%d fpos.%ld saved.%ld/%ld\n",type,spendlen,coin->scriptsfp!=0?ftell(coin->scriptsfp[0]):-1,saved,total); + fpos = iguana_scriptsave(coin,bp,unspentind,0,spendscript,spendlen); + } + return(fpos); +} diff --git a/iguana/iguana_tx.c b/iguana/iguana_tx.c index bddceed77..9f2deb2d5 100755 --- a/iguana/iguana_tx.c +++ b/iguana/iguana_tx.c @@ -34,8 +34,11 @@ void iguana_vinset(struct iguana_info *coin,int32_t height,struct iguana_msgvin T = (void *)(long)((long)rdata + rdata->Toffset); spendind = (tx->firstvin + i); s = &S[spendind]; - if ( s->diffsequence == 0 ) + if ( s->sequenceid == 1 ) vin->sequence = 0xffffffff; + else if ( s->sequenceid == 2 ) + vin->sequence = 0xfffffffe; + else vin->sequence = 0; vin->prev_vout = s->prevout; iguana_ramchain_spendtxid(coin,&unspentind,&vin->prev_hash,T,rdata->numtxids,X,rdata->numexternaltxids,s); } diff --git a/iguana/iguana_unspents.c b/iguana/iguana_unspents.c new file mode 100755 index 000000000..de5c2a871 --- /dev/null +++ b/iguana/iguana_unspents.c @@ -0,0 +1,320 @@ +/****************************************************************************** + * Copyright © 2014-2016 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "iguana777.h" +#include "exchanges/bitcoin.h" + +struct iguana_pkhash *iguana_pkhashfind(struct iguana_info *coin,struct iguana_ramchain **ramchainp,int64_t *balancep,uint32_t *lastunspentindp,struct iguana_pkhash *p,uint8_t rmd160[20],int32_t firsti,int32_t endi) +{ + uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind,i; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; struct iguana_account *ACCTS; + *balancep = 0; + *ramchainp = 0; + *lastunspentindp = 0; + for (i=firsti; ibundlescount&&i<=endi; i++) + { + if ( (bp= coin->bundles[i]) != 0 ) + { + ramchain = &bp->ramchain; + if ( ramchain->H.data != 0 ) + { + PKbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->PKoffset); + P = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Poffset); + ACCTS = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Aoffset); + if ( (pkind= iguana_sparseaddpk(PKbits,ramchain->H.data->pksparsebits,ramchain->H.data->numpksparse,rmd160,P,0)) > 0 && pkind < ramchain->H.data->numpkinds ) + { + *ramchainp = ramchain; + *balancep = ACCTS[pkind].balance; + *lastunspentindp = ACCTS[pkind].lastunspentind; + *p = P[pkind]; + return(p); + } //else printf("not found pkind.%d vs num.%d\n",pkind,ramchain->H.data->numpkinds); + } else printf("%s.[%d] error null ramchain->H.data\n",coin->symbol,i); + } + } + return(0); +} + +char *iguana_bundleaddrs(struct iguana_info *coin,int32_t hdrsi) +{ + uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; cJSON *retjson; char rmdstr[41]; + if ( (bp= coin->bundles[hdrsi]) != 0 ) + { + ramchain = &bp->ramchain; + if ( ramchain->H.data != 0 ) + { + retjson = cJSON_CreateArray(); + PKbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->PKoffset); + P = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Poffset); + for (pkind=0; pkindH.data->numpkinds; pkind++,P++) + { + init_hexbytes_noT(rmdstr,P->rmd160,20); + jaddistr(retjson,rmdstr); + } + return(jprint(retjson,1)); + } + iguana_bundleQ(coin,bp,bp->n); + return(clonestr("{\"error\":\"no bundle data\"}")); + } return(clonestr("{\"error\":\"no bundle\"}")); +} + +struct iguana_bundle *iguana_spent(struct iguana_info *coin,uint32_t *unspentindp,struct iguana_ramchain *ramchain,int32_t spend_hdrsi,struct iguana_spend *s) +{ + int32_t prev_vout,height,hdrsi; uint32_t sequenceid,unspentind; char str[65]; + struct iguana_bundle *spentbp=0; struct iguana_txid *T,TX,*tp; bits256 *X; bits256 prev_hash; + X = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Xoffset); + T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); + if ( s->sequenceid == 1 ) + sequenceid = 0xffffffff; + else if ( s->sequenceid == 2 ) + sequenceid = 0xfffffffe; + else sequenceid = 0; + hdrsi = spend_hdrsi; + if ( s->prevout < 0 ) + { + //printf("n.%d coinbase at spendind.%d firstvin.%d -> firstvout.%d -> unspentind\n",m,spendind,nextT->firstvin,nextT->firstvout); + //nextT++; + //m++; + return(0); + } + else + { + prev_vout = s->prevout; + iguana_ramchain_spendtxid(coin,&unspentind,&prev_hash,T,ramchain->H.data->numtxids,X,ramchain->H.data->numexternaltxids,s); + *unspentindp = unspentind; + if ( unspentind == 0 ) + { + if ( (tp= iguana_txidfind(coin,&height,&TX,prev_hash)) != 0 ) + { + unspentind = TX.firstvout + ((prev_vout > 0) ? prev_vout : 0); + hdrsi = height / coin->chain->bundlesize; + //printf("height.%d firstvout.%d prev.%d ->U%d\n",height,TX.firstvout,prev_vout,unspentind); + } + else + { + printf("cant find prev_hash.(%s) for bp.[%d]\n",bits256_str(str,prev_hash),spend_hdrsi); + } + } + } + if ( hdrsi > spend_hdrsi || (spentbp= coin->bundles[hdrsi]) == 0 ) + printf("illegal hdrsi.%d when [%d] spentbp.%p\n",hdrsi,spend_hdrsi,spentbp);//, getchar(); + else if ( spentbp->ramchain.spents[unspentind].spendind != 0 || hdrsi < 0 ) + printf("DOUBLE SPEND? U%d %p bp.[%d] unspentind.%u already has %u, no room\n",unspentind,&spentbp->ramchain.spents[unspentind],hdrsi,unspentind,spentbp->ramchain.spents[unspentind].spendind);//, getchar(); + else if ( unspentind == 0 || unspentind >= spentbp->ramchain.H.data->numunspents ) + printf("illegal unspentind.%d vs max.%d spentbp.%p[%d]\n",unspentind,spentbp->ramchain.H.data->numunspents,spentbp,hdrsi);//, getchar(); + else return(spentbp); + return(0); +} + +int32_t iguana_spentsinit(struct iguana_info *coin,struct iguana_Uextra *spents,struct iguana_bundle *bp,struct iguana_ramchain *ramchain) +{ + //struct iguana_Uextra { uint32_t spendind; uint16_t hdrsi; } __attribute__((packed)); // unspentind + //struct iguana_spend { uint32_t spendtxidind; int16_t prevout; uint16_t tbd:14,external:1,diffsequence:1; } __attribute__((packed)); + //struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; uint16_t hdrsi:12,type:4,vout; } __attribute__((packed)); + int32_t spendind,n,max,hdrsi,errs,flag; uint32_t unspentind; struct iguana_bundle *spentbp; + struct iguana_spend *S; + S = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Soffset); + max = ramchain->H.data->numunspents; + n = ramchain->H.data->numspends; + //nextT = &T[1]; + for (spendind=1,errs=0; spendindhdrsi; + if ( (spentbp= iguana_spent(coin,&unspentind,ramchain,bp->hdrsi,&S[spendind])) != 0 ) + { + spentbp->ramchain.spents[unspentind].spendind = spendind; + spentbp->ramchain.spents[unspentind].hdrsi = bp->hdrsi; + printf("%p bp.[%d] U%d <- S%d.[%d] [%p %p %p]\n",&spentbp->ramchain.spents[unspentind],hdrsi,unspentind,spendind,bp->hdrsi,coin->bundles[0],coin->bundles[1],coin->bundles[2]); + flag = 1; + } else if ( S[spendind].prevout < 0 ) + flag = 1; + if ( flag == 0 ) + errs++; + } + printf("processed %d spendinds for bp.[%d] -> errs.%d\n",spendind,bp->hdrsi,errs); + return(-errs); +} + +// if file exists and is valid, load and then process only the incremental +long iguana_spentsfile(struct iguana_info *coin,int32_t n) +{ + int32_t i,iter,allocated = 0; long filesize,total,count; struct iguana_Uextra *spents = 0; struct iguana_ramchain *ramchain; char fname[1024]; struct iguana_bundle *bp; FILE *fp; + fname[0] = 0; + for (total=iter=0; iter<2; iter++) + { + for (count=i=0; ibundles[i]) != 0 ) + { + ramchain = &bp->ramchain; + if ( ramchain->H.data != 0 ) + { + if ( iter == 1 ) + { + ramchain->spents = &spents[count]; + //printf("bp.[%d] count.%ld %p\n",i,count,ramchain->spents); + if ( allocated != 0 && iguana_spentsinit(coin,spents,bp,ramchain) < 0 ) + { + printf("error initializing spents bp.%d\n",i); + exit(-1); + } + } + count += ramchain->H.data->numunspents; + } else break; + } else return(-1); + } + if ( i < n ) + n = (i + 1); + sprintf(fname,"DB/%s/spents_%d.%ld",coin->symbol,n,count); + printf("%s total unspents.%ld\n",fname,count); + if ( iter == 0 ) + { + total = count; + if ( (spents= OS_filestr(&filesize,fname)) == 0 ) + spents = calloc(total,sizeof(*spents)), allocated = 1; + } + else if ( total != count ) + printf("%s total.%ld != count.%ld\n",fname,total,count); + } + if ( allocated != 0 && fname[0] != 0 && (fp= fopen(fname,"wb")) != 0 ) + { + fwrite(spents,total,sizeof(*spents),fp); + fclose(fp); + } + return(total); +} + +cJSON *iguana_unspentjson(struct iguana_info *coin,int32_t hdrsi,uint32_t unspentind,struct iguana_txid *T,struct iguana_unspent *up,uint8_t rmd160[20],char *coinaddr,uint8_t *pubkey33) +{ + /*{ + "txid" : "d54994ece1d11b19785c7248868696250ab195605b469632b7bd68130e880c9a", + "vout" : 1, + "address" : "mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe", + "account" : "test label", + "scriptPubKey" : "76a9140dfc8bafc8419853b34d5e072ad37d1a5159f58488ac", + "amount" : 0.00010000, + "confirmations" : 6210, + "spendable" : true + },*/ + //struct iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; uint16_t hdrsi:12,type:4,vout; } __attribute__((packed)); + struct iguana_waccount *wacct; struct iguana_txid TX; int32_t height,ind; char scriptstr[8192],asmstr[sizeof(scriptstr)+1024]; cJSON *item; + item = cJSON_CreateObject(); + jaddbits256(item,"txid",T[up->txidind].txid); + jaddnum(item,"vout",up->vout); + jaddstr(item,"address",coinaddr); + if ( (wacct= iguana_waddressfind(coin,&ind,coinaddr)) != 0 ) + jaddstr(item,"account",wacct->account); + if ( iguana_scriptget(coin,scriptstr,asmstr,sizeof(scriptstr),hdrsi,unspentind,T[up->txidind].txid,up->vout,rmd160,up->type,pubkey33) != 0 ) + jaddstr(item,"scriptPubKey",scriptstr); + jaddnum(item,"amount",dstr(up->value)); + if ( iguana_txidfind(coin,&height,&TX,T[up->txidind].txid) != 0 ) + jaddnum(item,"confirmations",coin->longestchain - height); + return(item); +} + +int64_t iguana_pkhashbalance(struct iguana_info *coin,cJSON *array,int64_t *spentp,int32_t *nump,struct iguana_ramchain *ramchain,struct iguana_pkhash *p,uint32_t lastunspentind,uint8_t rmd160[20],char *coinaddr,uint8_t *pubkey33,int32_t hdrsi) +{ + struct iguana_unspent *U; uint32_t unspentind; int64_t balance = 0; struct iguana_txid *T; + *spentp = *nump = 0; + if ( ramchain->spents == 0 ) + { + printf("iguana_pkhashbalance: unexpected null spents\n"); + return(0); + } + unspentind = lastunspentind; + U = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Uoffset); + T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); + while ( unspentind > 0 ) + { + (*nump)++; + printf("%s u.%d %.8f\n",jprint(iguana_unspentjson(coin,hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33),1),unspentind,dstr(U[unspentind].value)); + if ( ramchain->spents[unspentind].spendind == 0 ) + { + balance += U[unspentind].value; + if ( array != 0 ) + jaddi(array,iguana_unspentjson(coin,hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33)); + } else (*spentp) += U[unspentind].value; + if ( unspentind == p->firstunspentind ) + break; + unspentind = U[unspentind].prevunspentind; + } + return(balance); +} + +int32_t iguana_pkhasharray(struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,int64_t *totalp,struct iguana_pkhash *P,int32_t max,uint8_t rmd160[20],char *coinaddr,uint8_t *pubkey33) +{ + int32_t i,n,m; int64_t spent,balance,netbalance,total; uint32_t lastunspentind; struct iguana_ramchain *ramchain; + for (total=i=n=0; ibundlescount; i++) + { + if ( iguana_pkhashfind(coin,&ramchain,&balance,&lastunspentind,&P[n],rmd160,i,i) != 0 ) + { + if ( (netbalance= iguana_pkhashbalance(coin,array,&spent,&m,ramchain,&P[n],lastunspentind,rmd160,coinaddr,pubkey33,i)) != balance-spent ) + { + printf("pkhash balance mismatch from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",m,dstr(netbalance),dstr(balance),dstr(spent),dstr(balance)-dstr(spent)); + } + else + { + P[n].firstunspentind = lastunspentind; + total += netbalance; + n++; + } + } + //printf("%d: balance %.8f, lastunspent.%u\n",i,dstr(balance),lastunspentind); + } + //printf("n.%d max.%d\n",n,max); + *totalp = total; + return(n); +} + +void iguana_unspents(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,uint8_t *rmdarray,int32_t numrmds) +{ + int64_t total,sum=0; struct iguana_pkhash *P; uint8_t *addrtypes,*pubkeys; int32_t i,flag = 0; char coinaddr[64]; + if ( rmdarray == 0 ) + rmdarray = iguana_walletrmds(myinfo,coin,&numrmds), flag++; + addrtypes = &rmdarray[numrmds * 20], pubkeys = &rmdarray[numrmds * 21]; + P = calloc(coin->bundlescount,sizeof(*P)); + for (i=0; ibundlescount,&rmdarray[i * 20],coinaddr,&pubkeys[33*i]); + printf("%s %.8f\n",coinaddr,dstr(total)); + sum += total; + } + printf("sum %.8f\n",dstr(sum)); + free(P); + if ( flag != 0 ) + free(rmdarray); +} + +uint8_t *iguana_rmdarray(struct iguana_info *coin,int32_t *numrmdsp,cJSON *array,int32_t firsti) +{ + int32_t i,n,j=0; char *coinaddr; uint8_t *addrtypes,*rmdarray = 0; + *numrmdsp = 0; + if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + *numrmdsp = n - firsti; + rmdarray = calloc(1,(n-firsti) * 21); + addrtypes = &rmdarray[(n-firsti) * 20]; + for (i=firsti; iwallet,acct,tmp) + { + HASH_ITER(hh,acct->waddrs,waddr,tmp2) + { + if ( iter == 0 ) + n++; + else if ( m < n ) + { + addrtypes[m] = waddr->type; + memcpy(&rmdarray[m * 20],waddr->rmd160,20); + memcpy(&pubkeys[m * 33],waddr->pubkey,33); + m++; + } + } + } + if ( iter == 0 ) + { + rmdarray = calloc(n,20 + 1 + 33); + addrtypes = &rmdarray[n * 20]; + pubkeys = &rmdarray[n * 21]; + } + } + return(rmdarray); +} + int32_t iguana_waccountswitch(struct iguana_info *coin,char *account,struct iguana_waccount *oldwaddr,int32_t oldind,char *coinaddr) { // what if coinaddr is already in an account? @@ -51,6 +81,20 @@ int32_t iguana_waccountswitch(struct iguana_info *coin,char *account,struct igua struct iguana_waccount *iguana_waddressfind(struct iguana_info *coin,int32_t *indp,char *coinaddr) { + int32_t n=0; struct iguana_waccount *acct,*tmp; struct iguana_waddress *waddr,*tmp2; + *indp = -1; + HASH_ITER(hh,coin->wallet,acct,tmp) + { + HASH_ITER(hh,acct->waddrs,waddr,tmp2) + { + if ( strcmp(coinaddr,waddr->coinaddr) == 0 ) + { + *indp = n; + return(acct); + } + n++; + } + } return(0); } diff --git a/iguana/main.c b/iguana/main.c index b9871f037..d04b72793 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -45,7 +45,7 @@ cJSON *API_json; #ifdef __linux__ int32_t IGUANA_NUMHELPERS = 8; #else -int32_t IGUANA_NUMHELPERS = 1; +int32_t IGUANA_NUMHELPERS = 4; #endif struct iguana_jsonitem { struct queueitem DL; struct supernet_info *myinfo; uint32_t fallback,expired,allocsize; char **retjsonstrp; char remoteaddr[64]; char jsonstr[]; }; @@ -172,7 +172,7 @@ char *SuperNET_jsonstr(struct supernet_info *myinfo,char *jsonstr,char *remotead method = jstr(json,"method"); if ( (agent= jstr(json,"agent")) != 0 && method != 0 ) return(SuperNET_parser(myinfo,agent,method,json,remoteaddr)); - else if ( method != 0 && is_bitcoinrpc(method,remoteaddr) ) + else if ( method != 0 && is_bitcoinrpc(method,remoteaddr) != 0 ) return(iguana_bitcoinRPC(myinfo,method,json,remoteaddr)); return(clonestr("{\"error\":\"need both agent and method\"}")); } @@ -251,15 +251,19 @@ char *SuperNET_processJSON(struct supernet_info *myinfo,cJSON *json,char *remote return(clonestr("{\"result\":\"processed remote DHT\"}")); } jsonstr = jprint(json,0); + //printf("RPC? (%s)\n",jsonstr); if ( remoteaddr == 0 || jstr(json,"immediate") != 0 ) retjsonstr = SuperNET_jsonstr(myinfo,jsonstr,remoteaddr); else retjsonstr = iguana_blockingjsonstr(myinfo,jsonstr,tag,timeout,remoteaddr); if ( retjsonstr != 0 ) { - if ( (retjson= cJSON_Parse(retjsonstr)) != 0 ) + if ( (retjsonstr[0] == '{' || retjsonstr[0] == '[') && (retjson= cJSON_Parse(retjsonstr)) != 0 ) { - jdelete(retjson,"tag"); - jadd64bits(retjson,"tag",tag); + if ( j64bits(retjson,"tag") != tag ) + { + jdelete(retjson,"tag"); + jadd64bits(retjson,"tag",tag); + } retstr = jprint(retjson,1); //printf("retstr.(%s) retjsonstr.%p retjson.%p\n",retstr,retjsonstr,retjson); free(retjsonstr);//,strlen(retjsonstr)+1); @@ -1114,10 +1118,10 @@ void iguana_main(void *arg) sleep(1); char *str; //iguana_launchcoin(MYINFO.rpcsymbol,cJSON_Parse("{}")); - if ( 1 && (str= SuperNET_JSON(&MYINFO,cJSON_Parse("{\"userhome\":\"/Users/jimbolaptop/Library/Application Support\",\"agent\":\"iguana\",\"method\":\"addcoin\",\"services\":128,\"maxpeers\":3,\"newcoin\":\"BTC\",\"active\":0}"),0)) != 0 ) + if ( 1 && (str= SuperNET_JSON(&MYINFO,cJSON_Parse("{\"userhome\":\"/Users/jimbolaptop/Library/Application Support\",\"agent\":\"iguana\",\"method\":\"addcoin\",\"services\":128,\"maxpeers\":64,\"newcoin\":\"BTC\",\"active\":0}"),0)) != 0 ) { free(str); - if ( 1 && (str= SuperNET_JSON(&MYINFO,cJSON_Parse("{\"userhome\":\"/Users/jimbolaptop/Library/Application Support\",\"agent\":\"iguana\",\"method\":\"addcoin\",\"services\":128,\"maxpeers\":3,\"newcoin\":\"BTCD\",\"active\":0}"),0)) != 0 ) + if ( 1 && (str= SuperNET_JSON(&MYINFO,cJSON_Parse("{\"userhome\":\"/Users/jimbolaptop/Library/Application Support\",\"agent\":\"iguana\",\"method\":\"addcoin\",\"services\":128,\"maxpeers\":128,\"newcoin\":\"BTCD\",\"active\":1}"),0)) != 0 ) { free(str); if ( 0 && (str= SuperNET_JSON(&MYINFO,cJSON_Parse("{\"agent\":\"SuperNET\",\"method\":\"login\",\"handle\":\"alice\",\"password\":\"alice\",\"passphrase\":\"alice\"}"),0)) != 0 ) @@ -1127,7 +1131,7 @@ void iguana_main(void *arg) free(str); } } - strcpy(MYINFO.rpcsymbol,"BTC"); + strcpy(MYINFO.rpcsymbol,"BTCD"); printf("BTC active.%d BTCD active.%d\n",iguana_coinfind("BTC")->active,iguana_coinfind("BTCD")->active); iguana_coinfind("BTC")->active = iguana_coinfind("BTCD")->active = 0; } @@ -1137,9 +1141,9 @@ void iguana_main(void *arg) if ( arg != 0 ) SuperNET_JSON(&MYINFO,cJSON_Parse(arg),0); { - int32_t i,n; int64_t total; char *coinaddr; struct iguana_pkhash *P; struct iguana_info *coin; uint8_t rmd160[20],addrtype; double startmillis; + int32_t i,n; int64_t total; char *coinaddr; struct iguana_pkhash *P; struct iguana_info *coin; uint8_t rmd160[20],addrtype,pubkey33[33]; double startmillis; coin = iguana_coinfind("BTCD"); - if ( 1 && coin != 0 ) + if ( 0 && coin != 0 ) { getchar(); for (i=0; ibundlescount; i++) @@ -1150,11 +1154,12 @@ void iguana_main(void *arg) coinaddr = "RUZ9AKxy6J2okcBd1PZm4YH6atmPwqV4bo"; bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); P = calloc(coin->bundlescount,sizeof(*P)); - n = iguana_pkhasharray(coin,&total,P,coin->bundlescount,rmd160); + memset(pubkey33,0,sizeof(pubkey33)); + n = iguana_pkhasharray(coin,0,0,0,&total,P,coin->bundlescount,rmd160,coinaddr,pubkey33); printf("%s has total outputs %.8f from %d bundles\n",coinaddr,dstr(total),n); startmillis = OS_milliseconds(); for (i=0; i<1000; i++) - n = iguana_pkhasharray(coin,&total,P,coin->bundlescount,rmd160); + n = iguana_pkhasharray(coin,0,0,0,&total,P,coin->bundlescount,rmd160,coinaddr,pubkey33); printf("%s has total outputs %.8f from %d bundles %.3f millis\n",coinaddr,dstr(total),n,OS_milliseconds()-startmillis); getchar(); } diff --git a/iguana/peggy_tx.c b/iguana/peggy_tx.c index 6b4ef9396..630830b81 100755 --- a/iguana/peggy_tx.c +++ b/iguana/peggy_tx.c @@ -296,7 +296,7 @@ int64_t peggy_txind_bets(uint8_t *txbuf,int32_t len,struct accts777_info *accts, int32_t peggy_univ2addr(char *coinaddr,struct peggy_univaddr *ua) { - return(btc_convrmd160(coinaddr,ua->addrtype,ua->rmd160)); + return(bitcoin_address(coinaddr,ua->addrtype,ua->rmd160,20) != 0); } int32_t peggy_addr2univ(struct peggy_univaddr *ua,char *coinaddr,char *coin) diff --git a/iguana/ramchain_api.c b/iguana/ramchain_api.c index fdc7a8f9b..bd0399095 100755 --- a/iguana/ramchain_api.c +++ b/iguana/ramchain_api.c @@ -42,14 +42,14 @@ char *iguana_APIrequest(struct iguana_info *coin,bits256 blockhash,bits256 txid, return(0); } -INT_ARG(ramchain,getblockhash,height) +INT_ARG(bitcoinrpc,getblockhash,height) { cJSON *retjson = cJSON_CreateObject(); jaddbits256(retjson,"result",iguana_blockhash(coin,height)); return(jprint(retjson,1)); } -HASH_AND_INT(ramchain,getblock,blockhash,remoteonly) +HASH_AND_INT(bitcoinrpc,getblock,blockhash,remoteonly) { char *blockstr; struct iguana_msgblock msg; struct iguana_block *block; cJSON *retjson; bits256 txid; retjson = cJSON_CreateObject(); @@ -134,13 +134,15 @@ int32_t iguana_ramtxbytes(struct iguana_info *coin,uint8_t *serialized,int32_t m *txidp = bits256_doublesha256(txidstr,serialized,len); if ( memcmp(txidp,tx->txid.bytes,sizeof(*txidp)) != 0 ) { - char str[65],str2[65]; printf("error generating txbytes txid %s vs %s\n",bits256_str(str,*txidp),bits256_str(str2,tx->txid)); - return(0); + //for (i=0; itxid)); + return(len); } return(len); } -HASH_AND_INT(ramchain,getrawtransaction,txid,verbose) +HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose) { struct iguana_txid *tx,T; char *txbytes; bits256 checktxid; int32_t len,height; cJSON *retjson; if ( (tx= iguana_txidfind(coin,&height,&T,txid)) != 0 ) @@ -148,10 +150,11 @@ HASH_AND_INT(ramchain,getrawtransaction,txid,verbose) retjson = cJSON_CreateObject(); if ( (len= iguana_ramtxbytes(coin,coin->blockspace,sizeof(coin->blockspace),&checktxid,tx,height,0,0)) > 0 ) { - txbytes = mycalloc('x',1,len*2+1); - init_hexbytes_noT(txbytes,coin->blockspace,len*2+1); + txbytes = calloc(1,len*2+1); + init_hexbytes_noT(txbytes,coin->blockspace,len); jaddstr(retjson,"result",txbytes); - myfree(txbytes,len*2+1); + //printf("txbytes.(%s)\n",txbytes); + free(txbytes); return(jprint(retjson,1)); } else if ( height >= 0 ) @@ -184,7 +187,7 @@ HASH_AND_INT(ramchain,getrawtransaction,txid,verbose) return(clonestr("{\"error\":\"cant find txid\"}")); } -STRING_ARG(ramchain,decoderawtransaction,rawtx) +STRING_ARG(bitcoinrpc,decoderawtransaction,rawtx) { uint8_t *data; int32_t datalen; cJSON *retjson = cJSON_CreateObject(); // struct iguana_msgtx msgtx; datalen = (int32_t)strlen(rawtx) >> 1; @@ -196,316 +199,324 @@ STRING_ARG(ramchain,decoderawtransaction,rawtx) return(jprint(retjson,1)); } -HASH_ARG(ramchain,gettransaction,txid) +HASH_ARG(bitcoinrpc,gettransaction,txid) { - return(ramchain_getrawtransaction(IGUANA_CALLARGS,txid,1)); + return(bitcoinrpc_getrawtransaction(IGUANA_CALLARGS,txid,1)); } -ZERO_ARGS(ramchain,getinfo) +ZERO_ARGS(bitcoinrpc,getinfo) { cJSON *retjson = cJSON_CreateObject(); jaddstr(retjson,"result",coin->statusstr); return(jprint(retjson,1)); } -ZERO_ARGS(ramchain,getbestblockhash) +ZERO_ARGS(bitcoinrpc,getbestblockhash) { cJSON *retjson = cJSON_CreateObject(); char str[65]; jaddstr(retjson,"result",bits256_str(str,coin->blocks.hwmchain.RO.hash2)); return(jprint(retjson,1)); } -ZERO_ARGS(ramchain,getblockcount) +ZERO_ARGS(bitcoinrpc,getblockcount) { cJSON *retjson = cJSON_CreateObject(); jaddnum(retjson,"result",coin->blocks.hwmchain.height); return(jprint(retjson,1)); } -HASH_AND_TWOINTS(ramchain,listsinceblock,blockhash,target,flag) +HASH_AND_TWOINTS(bitcoinrpc,listsinceblock,blockhash,target,flag) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } // pubkeys -ZERO_ARGS(ramchain,makekeypair) +ZERO_ARGS(bitcoinrpc,makekeypair) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,validatepubkey,pubkey) +STRING_ARG(bitcoinrpc,validatepubkey,pubkey) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -INT_ARRAY_STRING(ramchain,createmultisig,M,array,account) +INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,array,account) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,decodescript,script) +STRING_ARG(bitcoinrpc,decodescript,script) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,vanitygen,vanity) +STRING_ARG(bitcoinrpc,vanitygen,vanity) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -TWO_STRINGS(ramchain,signmessage,address,message) +TWO_STRINGS(bitcoinrpc,signmessage,address,message) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -THREE_STRINGS(ramchain,verifymessage,address,sig,message) +THREE_STRINGS(bitcoinrpc,verifymessage,address,sig,message) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } // tx -TWO_ARRAYS(ramchain,createrawtransaction,vins,vouts) +TWO_ARRAYS(bitcoinrpc,createrawtransaction,vins,vouts) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_AND_TWOARRAYS(ramchain,signrawtransaction,rawtx,vins,privkeys) +STRING_AND_TWOARRAYS(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_AND_INT(ramchain,sendrawtransaction,rawtx,allowhighfees) +STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } // unspents -ZERO_ARGS(ramchain,gettxoutsetinfo) +ZERO_ARGS(bitcoinrpc,gettxoutsetinfo) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -INT_AND_ARRAY(ramchain,lockunspent,flag,array) +INT_AND_ARRAY(bitcoinrpc,lockunspent,flag,array) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -ZERO_ARGS(ramchain,listlockunspent) +ZERO_ARGS(bitcoinrpc,listlockunspent) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -HASH_AND_TWOINTS(ramchain,gettxout,txid,vout,mempool) +HASH_AND_TWOINTS(bitcoinrpc,gettxout,txid,vout,mempool) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -TWOINTS_AND_ARRAY(ramchain,listunspent,minconf,maxconf,array) +TWOINTS_AND_ARRAY(bitcoinrpc,listunspent,minconf,maxconf,array) { - cJSON *retjson = cJSON_CreateObject(); + int32_t numrmds; uint8_t *rmdarray; cJSON *retjson = cJSON_CreateArray(); + if ( minconf == 0 ) + minconf = 1; + if ( maxconf == 0 ) + maxconf = 9999999; + rmdarray = iguana_rmdarray(coin,&numrmds,array,0); + iguana_unspents(myinfo,coin,retjson,minconf,maxconf,rmdarray,numrmds); + if ( rmdarray != 0 ) + free(rmdarray); return(jprint(retjson,1)); } -STRING_AND_INT(ramchain,getreceivedbyaddress,address,minconf) +STRING_AND_INT(bitcoinrpc,getreceivedbyaddress,address,minconf) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -THREE_INTS(ramchain,listreceivedbyaddress,minconf,includeempty,flag) +THREE_INTS(bitcoinrpc,listreceivedbyaddress,minconf,includeempty,flag) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } // single address/account funcs -ZERO_ARGS(ramchain,getrawchangeaddress) +ZERO_ARGS(bitcoinrpc,getrawchangeaddress) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,getnewaddress,account) +STRING_ARG(bitcoinrpc,getnewaddress,account) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -TWOSTRINGS_AND_INT(ramchain,importprivkey,wif,account,rescan) +TWOSTRINGS_AND_INT(bitcoinrpc,importprivkey,wif,account,rescan) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,dumpprivkey,address) +STRING_ARG(bitcoinrpc,dumpprivkey,address) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -TWO_STRINGS(ramchain,setaccount,address,account) +TWO_STRINGS(bitcoinrpc,setaccount,address,account) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,getaccount,address) +STRING_ARG(bitcoinrpc,getaccount,address) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,getaccountaddress,account) +STRING_ARG(bitcoinrpc,getaccountaddress,account) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } // multiple address -THREE_INTS(ramchain,getbalance,confirmations,includeempty,watchonly) +THREE_INTS(bitcoinrpc,getbalance,confirmations,includeempty,watchonly) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,getaddressesbyaccount,account) +STRING_ARG(bitcoinrpc,getaddressesbyaccount,account) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_AND_INT(ramchain,getreceivedbyaccount,account,includeempty) +STRING_AND_INT(bitcoinrpc,getreceivedbyaccount,account,includeempty) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -THREE_INTS(ramchain,listreceivedbyaccount,confirmations,includeempty,watchonly) +THREE_INTS(bitcoinrpc,listreceivedbyaccount,confirmations,includeempty,watchonly) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_AND_THREEINTS(ramchain,listtransactions,account,count,skip,includewatchonly) +STRING_AND_THREEINTS(bitcoinrpc,listtransactions,account,count,skip,includewatchonly) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } // spend funcs -DOUBLE_ARG(ramchain,settxfee,amount) +DOUBLE_ARG(bitcoinrpc,settxfee,amount) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -SS_D_I_S(ramchain,move,fromaccount,toaccount,amount,minconf,comment) +SS_D_I_S(bitcoinrpc,move,fromaccount,toaccount,amount,minconf,comment) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -SS_D_I_SS(ramchain,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2) +SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -S_A_I_S(ramchain,sendmany,fromaccount,array,minconf,comment) +S_A_I_S(bitcoinrpc,sendmany,fromaccount,array,minconf,comment) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -S_D_SS(ramchain,sendtoaddress,address,amount,comment,comment2) +S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } // entire wallet funcs -TWO_INTS(ramchain,listaccounts,minconf,includewatchonly) +TWO_INTS(bitcoinrpc,listaccounts,minconf,includewatchonly) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -ZERO_ARGS(ramchain,listaddressgroupings) +ZERO_ARGS(bitcoinrpc,listaddressgroupings) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -ZERO_ARGS(ramchain,walletlock) +ZERO_ARGS(bitcoinrpc,walletlock) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -ZERO_ARGS(ramchain,checkwallet) +ZERO_ARGS(bitcoinrpc,checkwallet) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -ZERO_ARGS(ramchain,repairwallet) +ZERO_ARGS(bitcoinrpc,repairwallet) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,dumpwallet,filename) +STRING_ARG(bitcoinrpc,dumpwallet,filename) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,backupwallet,filename) +STRING_ARG(bitcoinrpc,backupwallet,filename) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,importwallet,filename) +STRING_ARG(bitcoinrpc,importwallet,filename) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_AND_INT(ramchain,walletpassphrase,passphrase,timeout) +STRING_AND_INT(bitcoinrpc,walletpassphrase,passphrase,timeout) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -TWO_STRINGS(ramchain,walletpassphrasechange,oldpassphrase,newpassphrase) +TWO_STRINGS(bitcoinrpc,walletpassphrasechange,oldpassphrase,newpassphrase) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -STRING_ARG(ramchain,encryptwallet,passphrase) +STRING_ARG(bitcoinrpc,encryptwallet,passphrase) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -HASH_AND_STRING(ramchain,verifytx,txid,txbytes) +HASH_AND_STRING(bitcoinrpc,verifytx,txid,txbytes) { cJSON *retjson; retjson = bitcoin_txtest(coin,txbytes,txid); @@ -513,7 +524,13 @@ HASH_AND_STRING(ramchain,verifytx,txid,txbytes) return(jprint(retjson,1)); } - +STRING_AND_INT(iguana,bundleaddresses,base,height) +{ + struct iguana_info *ptr; + if ( (ptr= iguana_coinfind(base)) != 0 ) + return(iguana_bundleaddrs(ptr,height / coin->chain->bundlesize)); + else return(clonestr("{\"error\":\"base is not active\"}")); +} #undef IGUANA_ARGS #include "../includes/iguana_apiundefs.h" diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 06c7a5d36..76d544ca3 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -23,13 +23,14 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount /*TWO_STRINGS_AND_TWO_DOUBLES(InstantDEX,BTCoffer,othercoin,otherassetid,maxprice,othervolume); STRING_AND_TWO_DOUBLES(InstantDEX,ALToffer,basecoin,minprice,basevolume); STRING_AND_TWO_DOUBLES(InstantDEX,NXToffer,assetid,minprice,basevolume);*/ +STRING_AND_INT(iguana,bundleaddresses,base,height); -HASH_AND_STRING(ramchain,verifytx,txid,txbytes); -INT_ARG(ramchain,getblockhash,height); -HASH_AND_INT(ramchain,getblock,blockhash,remoteonly); -HASH_AND_INT(ramchain,getrawtransaction,txid,verbose); -HASH_ARG(ramchain,gettransaction,txid); -STRING_ARG(ramchain,decoderawtransaction,rawtx); +HASH_AND_STRING(bitcoinrpc,verifytx,txid,txbytes); +INT_ARG(bitcoinrpc,getblockhash,height); +HASH_AND_INT(bitcoinrpc,getblock,blockhash,remoteonly); +HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose); +HASH_ARG(bitcoinrpc,gettransaction,txid); +STRING_ARG(bitcoinrpc,decoderawtransaction,rawtx); FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); ZERO_ARGS(SuperNET,logout); @@ -142,68 +143,68 @@ TWO_STRINGS(iguana,removenode,activecoin,ipaddr); TWO_STRINGS(iguana,oneshot,activecoin,ipaddr); TWO_STRINGS(iguana,nodestatus,activecoin,ipaddr); -ZERO_ARGS(ramchain,getinfo); -ZERO_ARGS(ramchain,getbestblockhash); -ZERO_ARGS(ramchain,getblockcount); -ZERO_ARGS(ramchain,listaddressgroupings); -ZERO_ARGS(ramchain,walletlock); -ZERO_ARGS(ramchain,checkwallet); -ZERO_ARGS(ramchain,repairwallet); -ZERO_ARGS(ramchain,makekeypair); -ZERO_ARGS(ramchain,gettxoutsetinfo); -ZERO_ARGS(ramchain,listlockunspent); -ZERO_ARGS(ramchain,getrawchangeaddress); - -TWO_INTS(ramchain,listaccounts,minconf,includewatchonly); -THREE_INTS(ramchain,listreceivedbyaddress,minconf,includeempty,flag); -TWOINTS_AND_ARRAY(ramchain,listunspent,minconf,maxconf,array); - -STRING_ARG(ramchain,dumpwallet,filename); -STRING_ARG(ramchain,backupwallet,filename); -STRING_ARG(ramchain,encryptwallet,passphrase); -STRING_ARG(ramchain,validatepubkey,pubkey); -STRING_ARG(ramchain,getnewaddress,account); -STRING_ARG(ramchain,vanitygen,vanity); - -STRING_ARG(ramchain,getaddressesbyaccount,account); -STRING_ARG(ramchain,getaccount,address); -STRING_ARG(ramchain,getaccountaddress,account); -STRING_ARG(ramchain,dumpprivkey,address); -STRING_ARG(ramchain,importwallet,filename); -STRING_ARG(ramchain,decodescript,script); - -TWO_STRINGS(ramchain,setaccount,address,account); -TWO_STRINGS(ramchain,walletpassphrasechange,oldpassphrase,newpassphrase); -TWO_STRINGS(ramchain,signmessage,address,message); - -THREE_STRINGS(ramchain,verifymessage,address,sig,message); -THREE_INTS(ramchain,listreceivedbyaccount,confirmations,includeempty,watchonly); -THREE_INTS(ramchain,getbalance,confirmations,includeempty,watchonly); - -TWOSTRINGS_AND_INT(ramchain,importprivkey,wif,account,rescan); -STRING_AND_INT(ramchain,getreceivedbyaccount,account,includeempty); -STRING_AND_INT(ramchain,walletpassphrase,passphrase,timeout); -STRING_AND_INT(ramchain,getreceivedbyaddress,address,minconf); -STRING_AND_INT(ramchain,sendrawtransaction,rawtx,allowhighfees); - -HASH_AND_TWOINTS(ramchain,listsinceblock,blockhash,target,flag); - -STRING_AND_THREEINTS(ramchain,listtransactions,account,count,skip,includewatchonly); - -HASH_AND_TWOINTS(ramchain,gettxout,txid,vout,mempool); - -DOUBLE_ARG(ramchain,settxfee,amount); - -INT_AND_ARRAY(ramchain,lockunspent,flag,array); -INT_ARRAY_STRING(ramchain,createmultisig,M,array,account); - -TWO_ARRAYS(ramchain,createrawtransaction,vins,vouts); -STRING_AND_TWOARRAYS(ramchain,signrawtransaction,rawtx,vins,privkeys); - -SS_D_I_S(ramchain,move,fromaccount,toaccount,amount,minconf,comment); -SS_D_I_SS(ramchain,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2); -S_A_I_S(ramchain,sendmany,fromaccount,array,minconf,comment); -S_D_SS(ramchain,sendtoaddress,address,amount,comment,comment2); +ZERO_ARGS(bitcoinrpc,getinfo); +ZERO_ARGS(bitcoinrpc,getbestblockhash); +ZERO_ARGS(bitcoinrpc,getblockcount); +ZERO_ARGS(bitcoinrpc,listaddressgroupings); +ZERO_ARGS(bitcoinrpc,walletlock); +ZERO_ARGS(bitcoinrpc,checkwallet); +ZERO_ARGS(bitcoinrpc,repairwallet); +ZERO_ARGS(bitcoinrpc,makekeypair); +ZERO_ARGS(bitcoinrpc,gettxoutsetinfo); +ZERO_ARGS(bitcoinrpc,listlockunspent); +ZERO_ARGS(bitcoinrpc,getrawchangeaddress); + +TWO_INTS(bitcoinrpc,listaccounts,minconf,includewatchonly); +THREE_INTS(bitcoinrpc,listreceivedbyaddress,minconf,includeempty,flag); +TWOINTS_AND_ARRAY(bitcoinrpc,listunspent,minconf,maxconf,array); + +STRING_ARG(bitcoinrpc,dumpwallet,filename); +STRING_ARG(bitcoinrpc,backupwallet,filename); +STRING_ARG(bitcoinrpc,encryptwallet,passphrase); +STRING_ARG(bitcoinrpc,validatepubkey,pubkey); +STRING_ARG(bitcoinrpc,getnewaddress,account); +STRING_ARG(bitcoinrpc,vanitygen,vanity); + +STRING_ARG(bitcoinrpc,getaddressesbyaccount,account); +STRING_ARG(bitcoinrpc,getaccount,address); +STRING_ARG(bitcoinrpc,getaccountaddress,account); +STRING_ARG(bitcoinrpc,dumpprivkey,address); +STRING_ARG(bitcoinrpc,importwallet,filename); +STRING_ARG(bitcoinrpc,decodescript,script); + +TWO_STRINGS(bitcoinrpc,setaccount,address,account); +TWO_STRINGS(bitcoinrpc,walletpassphrasechange,oldpassphrase,newpassphrase); +TWO_STRINGS(bitcoinrpc,signmessage,address,message); + +THREE_STRINGS(bitcoinrpc,verifymessage,address,sig,message); +THREE_INTS(bitcoinrpc,listreceivedbyaccount,confirmations,includeempty,watchonly); +THREE_INTS(bitcoinrpc,getbalance,confirmations,includeempty,watchonly); + +TWOSTRINGS_AND_INT(bitcoinrpc,importprivkey,wif,account,rescan); +STRING_AND_INT(bitcoinrpc,getreceivedbyaccount,account,includeempty); +STRING_AND_INT(bitcoinrpc,walletpassphrase,passphrase,timeout); +STRING_AND_INT(bitcoinrpc,getreceivedbyaddress,address,minconf); +STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees); + +HASH_AND_TWOINTS(bitcoinrpc,listsinceblock,blockhash,target,flag); + +STRING_AND_THREEINTS(bitcoinrpc,listtransactions,account,count,skip,includewatchonly); + +HASH_AND_TWOINTS(bitcoinrpc,gettxout,txid,vout,mempool); + +DOUBLE_ARG(bitcoinrpc,settxfee,amount); + +INT_AND_ARRAY(bitcoinrpc,lockunspent,flag,array); +INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,array,account); + +TWO_ARRAYS(bitcoinrpc,createrawtransaction,vins,vouts); +STRING_AND_TWOARRAYS(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys); + +SS_D_I_S(bitcoinrpc,move,fromaccount,toaccount,amount,minconf,comment); +SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2); +S_A_I_S(bitcoinrpc,sendmany,fromaccount,array,minconf,comment); +S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2); STRING_ARG(hash,hex,message); STRING_ARG(hash,unhex,hexmsg);