Merge of Komodo and Verus Technologies Post Sapling, Pre-VerusPoP with Support for Time locked coinbases

This commit is contained in:
miketout
2018-11-14 16:40:10 -08:00
81 changed files with 4300 additions and 2785 deletions

View File

@@ -12,17 +12,16 @@ This version of Komodo contains Bitcore support for komodo and all its assetchai
This software is the VerusCoin enhanced Komodo client. Generally, you will use this if you want to mine VRSC or setup a full node. When you run the wallet it launches komodod automatically. On first launch it downloads Zcash parameters, roughly 1GB, which is mildly slow.
The wallet downloads and stores the block chain or asset chain of the coin you select. It downloads and stores the entire history of the coins transactions; depending on the speed of your computer and network connection, the synchronization process could take a day or more once the blockchain has reached a significant size.
## Development Resources
- VerusCoin:[https://veruscoin.io/](https://veruscoin.io/) Wallets and CLI tools
- Komodo Web: [https://komodoplatform.com/](https://komodoplatform.com/)
- Organization web: [https://komodoplatform.com/](https://komodoplatform.com/)
- Forum: [https://forum.komodoplatform.com/](https://forum.komodoplatform.com/)
- Komodo Website: [https://komodoplatform.com](https://komodoplatform.com/)
- Komodo Blockexplorer: [https://kmdexplorer.io](https://kmdexplorer.io/)
- Komodo Discord: [https://komodoplatform.com/discord](https://komodoplatform.com/discord)
- Forum: [https://forum.komodoplatform.com](https://forum.komodoplatform.com/)
- Mail: [info@komodoplatform.com](mailto:info@komodoplatform.com)
- Support: [https://support.komodoplatform.com/support/home](https://support.komodoplatform.com/support/home)
- Knowledgebase & How-to: [https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages](https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages)
- API references: [http://docs.komodoplatform.com/](http://docs.komodoplatform.com/)
- Blog: [http://blog.komodoplatform.com/](http://blog.komodoplatform.com/)
- Whitepaper: [Komodo Whitepaper](https://komodoplatform.com/wp-content/uploads/2018/03/2018-03-12-Komodo-White-Paper-Full.pdf)
- Knowledgebase & How-to: [https://support.komodoplatform.com/en/support/solutions](https://support.komodoplatform.com/en/support/solutions)
- API references & Dev Documentation: [https://docs.komodoplatform.com](https://docs.komodoplatform.com/)
- Blog: [https://blog.komodoplatform.com](https://blog.komodoplatform.com/)
- Whitepaper: [Komodo Whitepaper](https://komodoplatform.com/whitepaper)
- Komodo Platform public material: [Komodo Platform public material](https://docs.google.com/document/d/1AbhWrtagu4vYdkl-vsWz-HSNyNvK-W-ZasHCqe7CZy0)
## List of Komodo Platform Technologies

View File

@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_greater_than, \
@@ -11,6 +12,8 @@ from test_framework.util import assert_equal, assert_greater_than, \
import time
from decimal import Decimal
from random import choice
from string import ascii_uppercase
def assert_success(result):
assert_equal(result['result'], 'success')
@@ -18,6 +21,11 @@ def assert_success(result):
def assert_error(result):
assert_equal(result['result'], 'error')
def generate_random_string(length):
random_string = ''.join(choice(ascii_uppercase) for i in range(length))
return random_string
class CryptoConditionsTest (BitcoinTestFramework):
def setup_chain(self):
@@ -470,7 +478,6 @@ class CryptoConditionsTest (BitcoinTestFramework):
result = rpc.tokenbalance(tokenid,randompubkey)
assert_equal(result["balance"], 1)
def run_rewards_tests(self):
rpc = self.nodes[0]
result = rpc.rewardsaddress()
@@ -581,6 +588,51 @@ class CryptoConditionsTest (BitcoinTestFramework):
result = rpc.rewardsunlock("STUFF", fundingtxid, locktxid)
assert_error(result)
def run_oracles_tests(self):
rpc = self.nodes[0]
result = rpc.oraclesaddress()
assert_success(result)
for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']:
assert_equal(result[x][0], 'R')
result = rpc.oraclesaddress(self.pubkey)
assert_success(result)
for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']:
assert_equal(result[x][0], 'R')
# there are no oracles created yet
result = rpc.oracleslist()
assert_equal(result, [])
# looking up non-existent oracle should return error.
result = rpc.oraclesinfo("none")
assert_error(result)
# attempt to create oracle with not valid data type should return error
result = rpc.oraclescreate("Test", "Test", "Test")
assert_error(result)
# attempt to create oracle with description > 32 symbols should return error
too_long_name = generate_random_string(33)
result = rpc.oraclescreate(too_long_name, "Test", "s")
# attempt to create oracle with description > 4096 symbols should return error
too_long_description = generate_random_string(4100)
result = rpc.oraclescreate("Test", too_long_description, "s")
assert_error(result)
# valid creating oracles of different types
# using such naming to re-use it for data publishing / reading (e.g. oracle_s for s type)
valid_formats = ["s", "S", "d", "D", "c", "C", "t", "T", "i", "I", "l", "L", "h", "Ihh"]
for f in valid_formats:
result = rpc.oraclescreate("Test", "Test", f)
assert_success(result)
globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex'])
def run_test (self):
print("Mining blocks...")
@@ -594,12 +646,13 @@ class CryptoConditionsTest (BitcoinTestFramework):
print("Importing privkey")
rpc.importprivkey(self.privkey)
# self.run_faucet_tests()
#self.run_faucet_tests()
self.run_rewards_tests()
self.run_dice_tests()
self.run_token_tests()
self.run_faucet_tests()
self.run_oracles_tests()
if __name__ == '__main__':
CryptoConditionsTest ().main ()
CryptoConditionsTest ().main()

12
resolve.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
for f in $(git diff --name-only --diff-filter=U | cat); do
echo "Resolve conflict in $f ..."
git checkout --theirs $f
done
for f in $(git diff --name-only --diff-filter=U | cat); do
echo "Adding file $f ..."
git add $f
done

View File

@@ -291,15 +291,13 @@ libbitcoin_server_a_SOURCES = \
cc/CCcustom.cpp \
cc/CCtx.cpp \
cc/CCutils.cpp \
cc/StakeGuard.cpp \
cc/StakeGuard.h \
cc/assets.cpp \
cc/faucet.cpp \
cc/rewards.cpp \
cc/dice.cpp \
cc/lotto.cpp \
cc/fsm.cpp \
cc/MofN.cpp \
cc/heir.cpp \
cc/oracles.cpp \
cc/prices.cpp \
cc/pegs.cpp \
@@ -310,8 +308,6 @@ libbitcoin_server_a_SOURCES = \
cc/auction.cpp \
cc/betprotocol.cpp \
chain.cpp \
cheatcatcher.h \
cheatcatcher.cpp \
checkpoints.cpp \
crosschain.cpp \
crypto/haraka.h \

2
src/ac/mgnx Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=MGNX $1 $2 $3 $4 $5 $6

2
src/ac/pgt Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=PGT $1 $2 $3 $4 $5 $6

2
src/ac/pirate Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=PIRATE $1 $2 $3 $4 $5 $6

View File

@@ -145,5 +145,35 @@
"142.93.136.89",
"195.201.22.89"
]
},
{
"ac_name": "PIRATE",
"ac_supply": "0",
"ac_reward": "25600000000",
"ac_halving": "77777",
"ac_private": "1",
"addnode": [
"136.243.102.225"
]
},
{
"ac_name": "MGNX",
"ac_supply": "12465003",
"ac_staked": "90",
"ac_reward": "2000000000",
"ac_halving": "525960",
"ac_cc": "2",
"ac_end": "2629800",
"addnode": [
"142.93.27.180"
]
},
{
"ac_name": "PGT",
"ac_supply": "10000000",
"ac_end": "1",
"addnode": [
"190.114.254.104"
]
}
]

View File

@@ -39,3 +39,6 @@ echo $pubkey
~/VerusCoin/src/komodod -pubkey=$pubkey -ac_name=VRSC -ac_algo=verushash -ac_cc=1 -ac_veruspos=50 -ac_supply=0 -ac_eras=3 -ac_reward=0,38400000000,2400000000 -ac_halving=1,43200,1051920 -ac_decay=100000000,0,0 -ac_end=10080,226080,0 -ac_timelockgte=19200000000 -ac_timeunlockfrom=129600 -ac_timeunlockto=1180800 -addnode=185.25.48.236 -addnode=185.64.105.111 &
./komodod -pubkey=$pubkey -ac_name=SEC -ac_cc=333 -ac_supply=1000000000 -addnode=185.148.145.43 &
./komodod -pubkey=$pubkey -ac_name=CCL -ac_supply=200000000 -ac_end=1 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=142.93.136.89 -addnode=195.201.22.89 &
./komodod -pubkey=$pubkey -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=136.243.102.225 &
./komodod -pubkey=$pubkey -ac_name=MGNX -ac_supply=12465003 -ac_staked=90 -ac_reward=2000000000 -ac_halving=525960 -ac_cc=2 -ac_end=2629800 -addnode=142.93.27.180 &
./komodod -pubkey=$pubkey -ac_name=PGT -ac_supply=10000000 -ac_end=1 -addnode=190.114.254.104 &

View File

@@ -61,8 +61,8 @@ void WaitForShutdown(boost::thread_group* threadGroup)
}
else
{
komodo_interestsum();
komodo_longestchain();
//komodo_interestsum();
//komodo_longestchain();
MilliSleep(20000);
}
fShutdown = ShutdownRequested();

View File

@@ -95,7 +95,7 @@ EVAL(EVAL_DICE, 0xe6) \
EVAL(EVAL_FSM, 0xe7) \
EVAL(EVAL_AUCTION, 0xe8) \
EVAL(EVAL_LOTTO, 0xe9) \
EVAL(EVAL_MOFN, 0xea) \
EVAL(EVAL_HEIR, 0xea) \
EVAL(EVAL_CHANNELS, 0xeb) \
EVAL(EVAL_ORACLES, 0xec) \
EVAL(EVAL_PRICES, 0xed) \
@@ -447,7 +447,104 @@ WARNING: there is an attack vector that precludes betting any large amounts, it
In order to mitigate this, the disclosure of the house entropy needs to be delayed beyond a reasonable reorg depth (notarization). It is recommended for production dice game with significant amounts of money to use such a delayed disclosure method.
Chapter 10 - lotto example
Chapter 10 - channels example
It might be hard to believe, but channels CC implements an instant payment mechanism that is secured by dPoW in a way that is backward compatible with the existing wallets, explorers, etc. and channels CC does not require both nodes to be online. Its usecases are all the usecases for Lightning Network, it is just more secure, less expensive and backward compatible! The one aspect which some might consider a downside (and others another benefit) is that all payments are onchain. This means it would increase blockchain size, but the idea is for channels CC to be used on blockchains with relatively lower value coins, so a txfee of 0.0001 is not anything significant.
Warning: very confusing blockchain reorganization issues described below. Will be confusing to most people
From a distance, the blockchain is a chain of blocks. One block after the next, each referencing all the prior blocks. Each block containing a group of transactions. Prior to getting into a block, the transactions are broadcast to the network and if it is valid, it enters the memory pool. Each miner then constructs a valid block from these memory pool transactions and when a transaction gets mined (confirmed), it is removed from the memory pool.
That is the simple version!
The reality is quite a bit more complex, but the critical aspect is that the blockchain can (and is) reorganized as part of the expected protocol. This can happen even when there is no 51% attack happening and it is important to understand this process in detail, so here goes.
What happens if two miners find a valid block at the same time? In this case the "same time" means within the time it takes for a block to propagate to the network. When a miner finds a new block, it is broadcast to the network and nodes update and start waiting for the next block. When there are two different (and valid) blocks propagating at the same time, some nodes update with one of the blocks and some the other, lets call it blockA and blockB. Now the nodes will know about both blockA and blockB, but some will consider blockA to be the chaintip and others will consider blockB to be the chaintip.
This is where it gets confusing. Which is the correct chaintip (latest block?). It turns out that both blockA and blockB are valid at this moment in time. So there are actuall two blockchains. We have what is called a small fork! Now dont worry, the protocol will help us converge to a single chain, but in order to do that, we need the next block.
Some miners will be mining from blockA and others from blockB. In most all cases, when the next block is found, it wont be at the "same time" again. So we will end up with a chain that is blockA+blockA2 or blockB+blockB2. Here comes the small reorg! Let's assuming blockA2 was found before blockB2, so that means all nodes that had blockB as the chaintip now see a longer chain blockA+blockA2, which trumps blockB. When that happens, it reorgs the chain so it is on blockA+blockA2. To do this properly, all the transactions that were in blockB are put back into the mempool and blockA is added, then blockA2.
Of course, when blockB2 arrives, the nodes see it but blockB+blockB2 is the same length as blockA+blockA2, so no reorg happens. Since we postulated that blockAs arrived "before" blockB2, that means all nodes are on the same chaintip, including all the miners and the next block found would be blockA3, without any complications.
Believe it or not, this sort of thing is happening all the time, one all blockchains. The chaintip is a volatile thing and that is why more than one confirmation is needed to avoid the small reorgs invalidating blockhash. However, it is possible for more than just the blockhash to change. When the reorg happens, all the transactions in the block are put back into the mempool and then the new blocks are processed in order. So what happens if one of the inputs to a transaction that happened in blockB, gets spent in blockA2? Based on random utxo allocation by wallets this is not impossible if an address has a lot of activity, but if it is part of a 51% attack, then this remote chance of an utxo being spent becomes a certainity! In fact, that is what a 51% attack is.
The attack can go much deeper than just one block. For chains that use the longest chain rule, it can go quite deep indeed. So as all the reorged transactions are put back into the mempool, we feel good that it will get confirmed again. Unfortunately, there is no enforcement of a miner needing to mine any specific transaction in the mempool. And the 51% attacker is intent on mining the transaction that spends an already spent utxo in the reorganized chain. it is called a double spend, but in the reorganized chain, it is spent only once. So it is a bit of a misnomer.
The important thing to understand is that if any transaction has inputs that are signed by a node, it is possible when the chain reorganizes for that transaction to become invalid. This is why dPoW is important as it doesnt strictly use the longest chain rule, but rather the longest notarized chain rule. Once a block is notarized, then it will refuse to reorganize that block (or any block before). So the risk is still there, but only until a notarization. Please see more detailed information about dPoW <here>.
Given the above, if you are wondering how can it be possible to have a mempool payment be secured by dPoW. Since it is explained how the reorgs can make valid transactions disappear, it seems unlikely any such solution is possible. However, the CC is very powerful and it can make unlikely things possible.
The following describes how.
We know that any payment that is utxo based can be invalidated via 51% attack, or even an unlikely but not impossible random utxo allocation from a busy wallet. Which means the payment cant be via a utxo. Since the CC system is utxo based, you might think that it means CC cant solve this. However, CC is very powerful and can implement payments that are not utxo based. But before this non-utxo payment method is explained, first we need to solve the mechanics of payment.
At a high level, we want to lock funds into a channel, have this lock notarized so it cant be reorganized. Then payments can unlock funds. Additionally, if we are restricting the payment to just one destination, we also need a way for the sender to reclaim the unused funds. So there needs a way for a close channel notification, which when notarized allows the sender to reclaim all funds. After the channel close is notarized, then the only action possible should be a reclaim of sender funds.
We need to assume that any payment, channel close, reclaim can be reorganized until it is notarized so great care needs to be made that a payment that is made will always be valid. With some allowances for blocks after a channelclose is notarized, we can protect the payments using the logic of "stop accepting payments after a channelclose is seen". It might be that a full notarization of wait time after the channelclose is notarized is needed to provide sufficient time for all the payments to be reprocessed.
Now we can finally describe the requirements for the CC. The locked funds need to be able to be spent by either the sender or receiver, the former only after sufficient time after a channelclose and the latter only after a payment is seen (not just confirmed, but just seeing it should be enough). The protection from reorgs is that the payment itself reveals a secret that is needed for the payment and only the secret would be needed, so it wont matter what utxo is used. To lock funds into a CC address that can handle this we need a 1of2 CC address, which can accept a signature from either of two pubkeys. The additional CC constraints would be enforced to make sure payments are made until the channel is closed.
A hashchain has the nice property of being able to encode a lot of secrets with a single hash. You can hash the hash, over and over and the final hash is the public value. By revealing the next to last hash, it can be verified that it hashes to the final hash. There is a restriction that a hashchain needs to be of reasonable maximum depth, say 1000. That means each iteration of the hashchain that is revealed is worth 1/1000th the total channelfunds. In fact, if the 500th hash value is revealed, half the channelfunds are released. this allows 1/1000th resolution that can be released with a single hash value.
Now we can make the payment based on the hashvalue revealed at a specified depth before the prior released hashchain value. Both the sender and receiver can make a payment to the destination by attaching a hashchain secret. This means even if the sender's payment is reorganized, if the destination has the revealed secret, a replacement payment can be made that is valid. If the destination account isnt monitoring the blockchain, then it wont see the revealed secret, but in this case there shouldnt be value released for the payments that are reorganized. So it would be a case of no harm, no foul. In any event, all the payments end up verifiable on the blockchain to provide verifiability.
Payments at the speed of the mempool, protected by dPoW!
RPC calls
channelsopen:
Used to open channel between two pub keys (sender and receiver). Parameters: destination_pubkey, total_number_of_payments, payment_denomination.
Example - channelsopen 03a8fe537de2ace0d9c210b0ff945085c9192c9abf56ea22f22ce7998f289bb7bb 10 10000000
channelspayment:
Sending payment to receiver. Condition is that the channel open tx is confirmed/notarised. Parameters: open_tx_id, payment_amount, [secret] (optional, used when receiver needs to make a payment which secret has already been revealed by sender).
Example - channelspayment b9c141facc8cb71306d0de8e525b3de1450e93e17fc8799c8fda5ed52fd14440 20000000
channelsclose:
Marking channel as closed. This RPC only creates a tx which says that the channel is closed and will be used in refund RPC to withdraw funds from closed channel. This also notifies receiver that channel fund could be withdrawn, but the payment RPC is still available until all funds are withdrawn. Parameters: open_tx_id.
Example - channelsclose b9c141facc8cb71306d0de8e525b3de1450e93e17fc8799c8fda5ed52fd14440
channelsrefund:
Withdrawing funds back to senders address. Refund can be issued only when channel close tx is confirmed/notarised. Parameters: open_tx_id, close_tx_id
Example - channelsrefund b9c141facc8cb71306d0de8e525b3de1450e93e17fc8799c8fda5ed52fd14440 bb0ea34f846247642684c7c541c435b06ee79e47893640e5d2e51023841677fd
channelsinfo:
Getting info about channels in which the issuer is involved, either as sender or receiver. Call without parameters give the list of available channels. Parameters: [open_tx_id] (optional - used to get info about specific channel)
VIN/VOUT allocation
Open:
vin.0: normal input
vout.0: CC vout for channel funding on CC1of2 pubkey
vout.1: CC vout marker to senders pubKey
vout.2: CC vout marker to receiver pubkey
vout.n-2: normal change
vout.n-1: opreturn - 'O' zerotxid senderspubkey receiverspubkey totalnumberofpayments paymentamount hashchain
Payment
vin.0: normal input
vin.1: CC input from channel funding
vin.2: CC input from src marker
vout.0: CC vout change to channel funding on CC1of2 pubkey
vout.1: CC vout marker to senders pubKey
vout.2: CC vout marker to receiver pubkey
vout.3: normal output of payment amount to receiver pubkey
vout.n-2: normal change
vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret
Close:
vin.0: normal input
vin.1: CC input from channel funding
vin.2: CC input from src marker
vout.0: CC vout for channel funding
vout.1: CC vout marker to senders pubKey
vout.2: CC vout marker to receiver pubkey
vout.n-2: normal change
vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0
Refund:
vin.0: normal input
vin.1: CC input from channel funding
vin.2: CC input from src marker
vout.0: CC vout marker to senders pubKey
vout.1: CC vout marker to receiver pubKey
vout.2: normal output of CC input to senders pubkey
vout.n-2: normal change
vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpayments payment closetxid
Chapter 11 - oracles example
Oracles CC is an example where it ended up being simpler than I first expected, but at the same time a lot more powerful. It is one of the smaller CC, but it enables creation of an arbitrary number of data markets, in a performant way.
@@ -582,6 +679,39 @@ Conclusion
I hope this document has helped you understand what a Komodo utxo based CC contract is and how it is different from the other smart contracts. If you are now able to dive into the cc directory and start making your own CC contract, then I am very happy!
gateways CC
gateways CC is the first CC that combines multiple CC into a single one. In order to achieve its goals, both the assets CC and the oracles CC is used, in addition to a dapp that issues regular transactions. This general approach can be used to solve quite a few different use cases, so it is important to understand how a multi-CC solution is put together. There are some tricky issues that only arise when using more than one CC at a time.
Before the implementation details, first lets understand what the gateways CC does. At a high level it is similar to the old multigateway (from NXT AE 2014), but with improvements. The basic idea is to tokenize other crypto coins (like BTC) and then use the assets CC to transact/swap against the tokenized crypto. By enforcing a 1:1 peg between a specific token and BTC and an automated deposit/withdraw mechanism, it is possible to transact in the virtual BTC without the delay or expensive txfees. Then anybody that ends up having any of the BTC token would be able to withdraw actual BTC by redeeming the token.
BTC -> deposit to special address -> receive token that represents BTC onchain
do onchain transactions with the BTC token
anybody who obtains the BTC token can redeem the token and get actual BTC in the withdraw address
By bringing the operations onchain, it avoids the need for crosschain complications for each trade. The crosschain does still have to happen on the deposit and withdraw, but that is all. There is just one aspect that makes it not fully decentralized, which is the reliance on MofN multisig. However, with N trusted community members and a reasonable M value, it is not expected to be a big barrier. Since all operations are automated, the only trust needed is that M of the N multisig signers are running their nodes with the gateways dapp active and also that M of them wont collude to steal the funds locked in the multisig. In three years of operations, the MGW multigateway didnt have any incident of multisig signer misbehavior and it was only 2of3 multisig.
How can the gatewaysCC work? First, it needs a dedicated token that can be used to represent the external crypto coin. In order to avoid any issues with misplaced tokens, it is simplest to require that 100% of all the tokens are all locked in the gatewaysCC address. We want to make it so that the only way the tokens can be released from the locked address is when a verified deposit is made. So, we also need a deposit address, which means there needs to be a set of pubkeys that control the deposit address. It turns out, we also need to post merkleroot data from the external coin so that the information is onchain to be able to validate the external deposit. Since we are already trusting the deposit address signers to safekeep the external coins via MofN multisig, trusting them to post the merkleroots doesnt increase the trust footprint needed.
Now we have all the ingredients needed, a dedicated token, a set of multisig pubkeys and an oracle for merkleroots.
gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)
With a gatewaysbind, a new gateway is defined. the pubkeys are for the custodians of the multisig funds and they also need to be posting merkleroots to the chain, so the oracle needs to be setup and funded and each of the signers needs to run the oraclefeed dapp. That posts each new merkleroot via oraclesdata and also responds to withdraw requests.
The MofN pubkeys generates a deposit address and when funds are sent to that address along with a small amount to the claim address. With the txid from this external coin, along with the txproof and the rawtransaction, all is submitted with a gatewaysdeposit. This adds a special baton output which is a gateways CC output to invoke gateways validation and also prevents double claims by using the unspent status of the baton.
gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount
gatewaysclaim bindtxid coin deposittxid destpub amount
Once the gatewaysdeposit is validated, it can be claimed and now the token is sent to the claim address. A 1:1 pegging of the external crypto to the token is established. And as long as one of the deposit address signers is running the oraclefeed, then the deposit/claim process is fully automatic and under the control of the depositor. Nothing needs to be signed by any other party! Also by using the utxo from the deposittxid, double claims are prevented.
On the withdraw side, the tokens are sent back to the address where the tokens are locked and this needs to create a redemption right that can only be used once.
gatewayswithdraw bindtxid coin withdrawpub amount
And with a bit more magic in the oraclefeed, this is achieved. To be continued...

View File

@@ -24,9 +24,11 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys);
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount);
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount);
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount);
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount);
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin);
std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid);
std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid);
UniValue GatewaysMultisig(char *txidaddr);
std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin, std::string hex);
// CCcustom
UniValue GatewaysInfo(uint256 bindtxid);

View File

@@ -14,16 +14,16 @@
******************************************************************************/
#ifndef CC_MOFN_H
#define CC_MOFN_H
#ifndef CC_HEIR_H
#define CC_HEIR_H
#include "CCinclude.h"
#define EVAL_MOFN 0xea
#define EVAL_HEIR 0xea
bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue MofNInfo();
UniValue HeirInfo();
#endif

View File

@@ -22,6 +22,13 @@
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue PricesInfo();
UniValue PricesList();
UniValue PricesInfo(uint256 fundingtxid);
UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid);
std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector<CPubKey> pubkeys);
std::string PricesAddFunding(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount);
std::string PricesBet(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount,int32_t leverage);
std::string PricesFinish(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,uint256 bettxid);
#endif

View File

@@ -54,6 +54,8 @@ UniValue AssetInfo(uint256 tokenid);
UniValue AssetList();
std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description);
std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total);
std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode);
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal);
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid);
std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount);

View File

@@ -367,7 +367,10 @@ int64_t IsAssetvout(int64_t &price,std::vector<uint8_t> &origpubkey,const CTrans
else if ( funcid != 'E' )
{
if ( assetid == refassetid )
{
//fprintf(stderr,"returning %.8f\n",(double)nValue/COIN);
return(nValue);
}
}
else if ( funcid == 'E' )
{
@@ -447,7 +450,7 @@ int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpp
bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid)
{
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
CTransaction vinTx; uint256 hashBlock,id,id2; int32_t i,flag,numvins,numvouts; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
numvins = tx.vin.size();
numvouts = tx.vout.size();
inputs = outputs = 0;
@@ -465,8 +468,20 @@ bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti
fprintf(stderr,"vin%d %llu, ",i,(long long)assetoshis);
inputs += assetoshis;
}
else
{
if ( vinTx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 && DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid )
{
assetoshis = vinTx.vout[i].nValue;
fprintf(stderr,"vin%d %llu special case, ",i,(long long)assetoshis);
inputs += assetoshis;
}
}
}
}
if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid )
flag = 1;
else flag = 0;
for (i=0; i<numvouts; i++)
{
if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
@@ -474,6 +489,12 @@ bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti
fprintf(stderr,"vout%d %llu, ",i,(long long)assetoshis);
outputs += assetoshis;
}
else if ( flag != 0 && tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
assetoshis = tx.vout[i].nValue;
fprintf(stderr,"vout%d %llu special case, ",i,(long long)assetoshis);
outputs += assetoshis;
}
}
if ( inputs != outputs )
{

View File

@@ -17,15 +17,17 @@
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
{
char coinaddr[64],destaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t j,vout,n = 0;
char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t j,vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs!=0?maxinputs:64);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
continue;
for (j=0; j<mtx.vin.size(); j++)
if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
break;
@@ -243,6 +245,32 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
return("");
}
std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
{
CMutableTransaction mtx; CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
if ( total < 0 )
{
fprintf(stderr,"negative total %lld\n",(long long)total);
return("");
}
cp = CCinit(&C,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
{
if ( inputs > total )
CCchange = (inputs - total);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
mtx.vout.push_back(MakeCC1vout(evalcode,total,pubkey2pk(destpubkey)));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
}
return("");
}
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal)
{
CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description;

View File

@@ -22,12 +22,11 @@
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment);
std::string ChannelStop(uint64_t txfee,CPubKey destpub,uint256 origtxid);
std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 origtxid,int32_t n,int64_t amount);
std::string ChannelCollect(uint64_t txfee,uint256 paytxid,uint256 origtxid,int32_t n,int64_t amount);
std::string ChannelRefund(uint64_t txfee,uint256 stoptxid,uint256 origtxid);
std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret);
std::string ChannelClose(uint64_t txfee,uint256 opentxid);
std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid);
// CCcustom
UniValue ChannelsInfo();
UniValue ChannelsInfo(uint256 opentxid);
#endif

View File

@@ -22,7 +22,7 @@
#include "CCauction.h"
#include "CClotto.h"
#include "CCfsm.h"
#include "CCMofN.h"
#include "CCHeir.h"
#include "CCchannels.h"
#include "CCOracles.h"
#include "CCPrices.h"
@@ -30,7 +30,6 @@
#include "CCTriggers.h"
#include "CCPayments.h"
#include "CCGateways.h"
#include "StakeGuard.h"
/*
CCcustom has most of the functions that need to be extended to create a new CC contract.
@@ -56,11 +55,6 @@
// to create a new CCaddr, add to rpcwallet the CCaddress and start with -pubkey= with the pubkey of the new address, with its wif already imported. set normaladdr and CChexstr. run CCaddress and it will print the privkey along with autocorrect the CCaddress. which should then update the CCaddr here
// StakeGuard - nothing at stake
std::string StakeGuardAddr = "RCG8KwJNDVwpUBcdoa6AoHqHVJsA1uMYMR";
std::string StakeGuardPubKey = "03166b7813a4855a88e9ef7340a692ef3c2decedfdc2c7563ec79537e89667d935";
std::string StakeGuardWIF = "Uw7vRYHGKjyi1FaJ8Lv1USSuj7ntUti8fAhSDiCdbzuV6yDagaTn";
// Assets, aka Tokens
#define FUNCNAME IsAssetsInput
#define EVALCODE EVAL_ASSETS
@@ -140,13 +134,13 @@ uint8_t AuctionCCpriv[32] = { 0x8c, 0x1b, 0xb7, 0x8c, 0x02, 0xa3, 0x9d, 0x21, 0x
#undef FUNCNAME
#undef EVALCODE
// MofN
#define FUNCNAME IsMofNInput
#define EVALCODE EVAL_MOFN
const char *MofNCCaddr = "RDVHcSekmXgeYBqRupNTmqo3Rn8QRXNduy";
const char *MofNNormaladdr = "RTPwUjKYECcGn6Y4KYChLhgaht1RSU4jwf";
char MofNCChexstr[67] = { "03c91bef3d7cc59c3a89286833a3446b29e52a5e773f738a1ad2b09785e5f4179e" };
uint8_t MofNCCpriv[32] = { 0x9d, 0xa1, 0xf8, 0xf7, 0xba, 0x0a, 0x91, 0x36, 0x89, 0x9a, 0x86, 0x30, 0x63, 0x20, 0xd7, 0xdf, 0xaa, 0x35, 0xe3, 0x99, 0x32, 0x2b, 0x63, 0xc0, 0x66, 0x9c, 0x93, 0xc4, 0x5e, 0x9d, 0xb9, 0xce };
// Heir
#define FUNCNAME IsHeirInput
#define EVALCODE EVAL_HEIR
const char *HeirCCaddr = "RDVHcSekmXgeYBqRupNTmqo3Rn8QRXNduy";
const char *HeirNormaladdr = "RTPwUjKYECcGn6Y4KYChLhgaht1RSU4jwf";
char HeirCChexstr[67] = { "03c91bef3d7cc59c3a89286833a3446b29e52a5e773f738a1ad2b09785e5f4179e" };
uint8_t HeirCCpriv[32] = { 0x9d, 0xa1, 0xf8, 0xf7, 0xba, 0x0a, 0x91, 0x36, 0x89, 0x9a, 0x86, 0x30, 0x63, 0x20, 0xd7, 0xdf, 0xaa, 0x35, 0xe3, 0x99, 0x32, 0x2b, 0x63, 0xc0, 0x66, 0x9c, 0x93, 0xc4, 0x5e, 0x9d, 0xb9, 0xce };
#include "CCcustom.inc"
#undef FUNCNAME
#undef EVALCODE
@@ -221,7 +215,7 @@ uint8_t PaymentsCCpriv[32] = { 0x03, 0xc9, 0x73, 0xc2, 0xb8, 0x30, 0x3d, 0xbd, 0
#define FUNCNAME IsGatewaysInput
#define EVALCODE EVAL_GATEWAYS
const char *GatewaysCCaddr = "RKWpoK6vTRtq5b9qrRBodLkCzeURHeEk33";
const char *GatewaysNormaladdr = "RGJKV97ZN1wBfunuMt1tebiiHENNEq73Yh";
const char *GatewaysNormaladdr = "RGJKV97ZN1wBfunuMt1tebiiHENNEq73Yh"; // wif UxJFYqEvLAjWPPRvn8NN1fRWscBxQZXZB5BBgc3HiapKVQBYNcmo
char GatewaysCChexstr[67] = { "03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40" };
uint8_t GatewaysCCpriv[32] = { 0xf7, 0x4b, 0x5b, 0xa2, 0x7a, 0x5e, 0x9c, 0xda, 0x89, 0xb1, 0xcb, 0xb9, 0xe6, 0x9c, 0x2c, 0x70, 0x85, 0x37, 0xdd, 0x00, 0x7a, 0x67, 0xff, 0x7c, 0x62, 0x1b, 0xe2, 0xfb, 0x04, 0x8f, 0x85, 0xbf };
#include "CCcustom.inc"
@@ -233,15 +227,6 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
cp->evalcode = evalcode;
switch ( evalcode )
{
case EVAL_STAKEGUARD:
strcpy(cp->unspendableCCaddr,StakeGuardAddr.c_str());
strcpy(cp->normaladdr,StakeGuardAddr.c_str());
strcpy(cp->CChexstr,StakeGuardPubKey.c_str());
memcpy(cp->CCpriv,DecodeSecret(StakeGuardWIF).begin(),32);
cp->validate = StakeGuardValidate;
cp->ismyvin = IsStakeGuardInput;
break;
case EVAL_ASSETS:
strcpy(cp->unspendableCCaddr,AssetsCCaddr);
strcpy(cp->normaladdr,AssetsNormaladdr);
@@ -298,13 +283,13 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
cp->validate = AuctionValidate;
cp->ismyvin = IsAuctionInput;
break;
case EVAL_MOFN:
strcpy(cp->unspendableCCaddr,MofNCCaddr);
strcpy(cp->normaladdr,MofNNormaladdr);
strcpy(cp->CChexstr,MofNCChexstr);
memcpy(cp->CCpriv,MofNCCpriv,32);
cp->validate = MofNValidate;
cp->ismyvin = IsMofNInput;
case EVAL_HEIR:
strcpy(cp->unspendableCCaddr,HeirCCaddr);
strcpy(cp->normaladdr,HeirNormaladdr);
strcpy(cp->CChexstr,HeirCChexstr);
memcpy(cp->CCpriv,HeirCCpriv,32);
cp->validate = HeirValidate;
cp->ismyvin = IsHeirInput;
break;
case EVAL_CHANNELS:
strcpy(cp->unspendableCCaddr,ChannelsCCaddr);

View File

@@ -24,7 +24,7 @@
bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds);
std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout);
std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyvout,int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout,uint256 vin0txid,int32_t vin0vout);
double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid);
std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks);
std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount);

View File

@@ -48,12 +48,16 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include <univalue.h>
#include <exception>
#include "../komodo_defs.h"
#include "../utlist.h"
#include "../uthash.h"
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE;
extern uint32_t ASSETCHAINS_CC;
extern char ASSETCHAINS_SYMBOL[];
extern std::string CCerror;
#define SMALLVAL 0.000000000000001
#define MIN_NOTARIZATION_CONFIRMS 2
union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; };
typedef union _bits256 bits256;
@@ -104,8 +108,8 @@ int32_t is_hexstr(char *str,int32_t n);
bool myAddtomempool(CTransaction &tx, CValidationState *pstate = NULL);
//uint64_t myGettxout(uint256 hash,int32_t n);
bool myIsutxo_spentinmempool(uint256 txid,int32_t vout);
bool mytxid_inmempool(uint256 txid);
int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout);
bool mySendrawtransaction(std::string res);
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp);
@@ -133,24 +137,26 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
// CCutils
CPubKey buf2pk(uint8_t *buf33);
void endiancpy(uint8_t *dest,uint8_t *src,int32_t len);
uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv);
uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout);
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk);
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2);
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk);
CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);
CC *GetCryptoCondition(CScript const& scriptSig);
CC* GetCryptoCondition(CScript const& scriptSig);
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
bool IsCCInput(CScript const& scriptSig);
int32_t unstringbits(char *buf,uint64_t bits);
uint64_t stringbits(char *str);
uint256 revuint256(uint256 txid);
bool pubkey2addr(char *destaddr,uint8_t *pubkey33);
char *uint256_str(char *dest,uint256 txid);
char *pubkey33_str(char *dest,uint8_t *pubkey33);
uint256 Parseuint256(char *hexstr);
CPubKey pubkey2pk(std::vector<uint8_t> pubkey);
int64_t CCfullsupply(uint256 tokenid);
int64_t CCtoken_balance(char *destaddr,uint256 tokenid);
int64_t CCtoken_balance2(char *destaddr,uint256 tokenid);
bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk);
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk);
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2);
@@ -160,7 +166,7 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
std::vector<uint8_t> Mypubkey();
bool Myprivkey(uint8_t myprivkey[]);
int64_t CCduration(int32_t &numblocks,uint256 txid);
bool isCCTxNotarizedConfirmed(uint256 txid);
// CCtx
bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey);
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret);

View File

@@ -18,12 +18,12 @@
/*
FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.
This allows the contract transaction functions to create the appropriate vins and vouts and have FinalizeCCTx create a properly signed transaction.
By using -addressindex=1, it allows tracking of all the CC addresses
*/
bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey)
{
#ifdef ENABLE_WALLET
@@ -34,9 +34,8 @@ bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScrip
UpdateTransaction(mtx,vini,sigdata);
return(true);
} else fprintf(stderr,"signing error for SignTx vini.%d %.8f\n",vini,(double)utxovalue/COIN);
#else
return(false);
#endif
return(false);
}
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
@@ -112,7 +111,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
{
privkey = myprivkey;
cond = mycond;
//fprintf(stderr,"my CC addr.(%s)\n",myaddr);
}
else if ( strcmp(destaddr,unspendable) == 0 )
{
@@ -120,12 +119,14 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
cond = othercond;
//fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable);
}
else if ( strcmp(destaddr,cp->unspendableaddr2) == 0 )
else if ( strcmp(destaddr,cp->unspendableaddr2) == 0)
{
//fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2);
privkey = cp->unspendablepriv2;
if ( othercond2 == 0 )
if ( othercond2 == 0 && cp->evalcode != EVAL_CHANNELS)
othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2);
else if ( othercond2 == 0 && cp->evalcode == EVAL_CHANNELS)
othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3);
cond = othercond2;
}
else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
@@ -138,7 +139,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
}
else
{
fprintf(stderr,"vini.%d has unknown CC address.(%s)\n",i,destaddr);
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
continue;
}
uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
@@ -251,13 +252,15 @@ int64_t CCfullsupply(uint256 tokenid)
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
{
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector<uint8_t> origpubkey; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector<uint8_t> origpubkey;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN);
if ( DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 && assetid == tokenid )
{
sum += it->second.satoshis;
@@ -273,6 +276,11 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *
abovei = belowi = -1;
for (above=below=i=0; i<numunspents; i++)
{
// Filter to randomly pick utxo to avoid conflicts, and having multiple CC choose the same ones.
//if ( numunspents > 500 ) {
// if ( (rand() % 100) < 80 )
// continue;
//}
if ( (atx_value= utxos[i].nValue) <= 0 )
continue;
if ( atx_value == value )
@@ -319,21 +327,26 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=1024; int64_t above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
#ifdef ENABLE_WALLET
const CKeyStore& keystore = *pwalletMain;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
threshold = total/maxinputs;
if ( maxinputs > maxutxos )
maxutxos = maxinputs;
sum = 0;
BOOST_FOREACH(const COutput& out, vecOutputs)
{
if ( out.fSpendable != 0 )
if ( out.fSpendable != 0 && out.tx->vout[out.i].nValue >= threshold )
{
txid = out.tx->GetHash();
vout = out.i;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
{
//fprintf(stderr,"check %.8f to vins array.%d of %d %s/v%d\n",(double)out.tx->vout[out.i].nValue/COIN,n,maxutxos,txid.GetHex().c_str(),(int32_t)vout);
if ( mtx.vin.size() > 0 )
{
for (i=0; i<mtx.vin.size(); i++)
@@ -356,8 +369,9 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
up->txid = txid;
up->nValue = out.tx->vout[out.i].nValue;
up->vout = vout;
sum += up->nValue;
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
if ( n >= maxutxos )
if ( n >= maxutxos || sum >= total )
break;
}
}

View File

@@ -74,6 +74,7 @@ CC* GetCryptoCondition(CScript const& scriptSig)
std::vector<unsigned char> ffbin;
if (scriptSig.GetOp(pc, opcode, ffbin))
return cc_readFulfillmentBinary((uint8_t*)ffbin.data(), ffbin.size()-1);
else return(0);
}
bool IsCCInput(CScript const& scriptSig)
@@ -238,6 +239,16 @@ bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
}
}
return false;
//fprintf(stderr,"ExtractDestination failed\n");
return(false);
}
bool pubkey2addr(char *destaddr,uint8_t *pubkey33)
{
std::vector<uint8_t>pk; int32_t i;
for (i=0; i<33; i++)
pk.push_back(pubkey33[i]);
return(Getscriptaddress(destaddr,CScript() << pk << OP_CHECKSIG));
}
CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
@@ -420,12 +431,12 @@ int64_t CCduration(int32_t &numblocks,uint256 txid)
numblocks = 0;
if ( myGetTransaction(txid,tx,hashBlock) == 0 )
{
fprintf(stderr,"CCduration cant find duration txid %s\n",uint256_str(str,txid));
//fprintf(stderr,"CCduration cant find duration txid %s\n",uint256_str(str,txid));
return(0);
}
else if ( hashBlock == zeroid )
{
fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid));
//fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid));
return(0);
}
else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->GetHeight()) <= 0 )
@@ -435,12 +446,22 @@ int64_t CCduration(int32_t &numblocks,uint256 txid)
}
else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->GetHeight() <= txheight )
{
fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->GetHeight());
if ( pindex->nTime < txtime )
fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->GetHeight());
return(0);
}
numblocks = (pindex->GetHeight() - txheight);
duration = (pindex->nTime - txtime);
fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->GetHeight(),txheight);
//fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->GetHeight(),txheight);
return(duration);
}
bool isCCTxNotarizedConfirmed(uint256 txid)
{
int32_t confirms;
CCduration(confirms,txid);
if (confirms >= MIN_NOTARIZATION_CONFIRMS)
return (true);
return (false);
}

View File

@@ -1,460 +0,0 @@
/********************************************************************
* (C) 2018 Michael Toutonghi
*
* Distributed under the MIT software license, see the accompanying
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
*
* This crypto-condition eval solves the problem of nothing-at-stake
* in a proof of stake consensus system.
*
*/
#include "StakeGuard.h"
#include "script/script.h"
#include "main.h"
#include "hash.h"
#include "streams.h"
extern int32_t VERUS_MIN_STAKEAGE;
bool IsData(opcodetype opcode)
{
return (opcode >= 0 && opcode <= OP_PUSHDATA4) || (opcode >= OP_1 && opcode <= OP_16);
}
bool UnpackStakeOpRet(const CTransaction &stakeTx, std::vector<std::vector<unsigned char>> &vData)
{
bool isValid = stakeTx.vout[stakeTx.vout.size() - 1].scriptPubKey.GetOpretData(vData);
if (isValid && vData.size() == 1)
{
CScript data = CScript(vData[0].begin(), vData[0].end());
vData.clear();
uint32_t bytesTotal;
CScript::const_iterator pc = data.begin();
std::vector<unsigned char> vch = std::vector<unsigned char>();
opcodetype op;
bool moreData = true;
for (bytesTotal = vch.size();
bytesTotal <= nMaxDatacarrierBytes && !(isValid = (pc == data.end())) && (moreData = data.GetOp(pc, op, vch)) && IsData(op);
bytesTotal += vch.size())
{
if (op >= OP_1 && op <= OP_16)
{
vch.resize(1);
vch[0] = (op - OP_1) + 1;
}
vData.push_back(vch);
}
// if we ran out of data, we're ok
if (isValid && (vData.size() >= CStakeParams::STAKE_MINPARAMS) && (vData.size() <= CStakeParams::STAKE_MAXPARAMS))
{
return true;
}
}
return false;
}
CStakeParams::CStakeParams(const std::vector<std::vector<unsigned char>> &vData)
{
// A stake OP_RETURN contains:
// 1. source block height in little endian 32 bit
// 2. target block height in little endian 32 bit
// 3. 32 byte prev block hash
// 4. 33 byte pubkey, or not present to use same as stake destination
srcHeight = 0;
blkHeight = 0;
if (vData[0].size() == 1 &&
vData[0][0] == OPRETTYPE_STAKEPARAMS && vData[1].size() <= 4 &&
vData[2].size() <= 4 &&
vData[3].size() == sizeof(prevHash) &&
(vData.size() == STAKE_MINPARAMS || (vData.size() == STAKE_MAXPARAMS && vData[4].size() == 33)))
{
for (int i = 0, size = vData[1].size(); i < size; i++)
{
srcHeight = srcHeight | vData[1][i] << (8 * i);
}
for (int i = 0, size = vData[2].size(); i < size; i++)
{
blkHeight = blkHeight | vData[2][i] << (8 * i);
}
prevHash = uint256(vData[3]);
if (vData.size() == 4)
{
pk = CPubKey();
}
else if (vData[4].size() == 33)
{
pk = CPubKey(vData[4]);
if (!pk.IsValid())
{
// invalidate
srcHeight = 0;
}
}
else
{
// invalidate
srcHeight = 0;
}
}
}
bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams)
{
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
//printf("opret stake script: %s\nvalue at scriptPubKey[0]: %x\n", stakeTx.vout[1].scriptPubKey.ToString().c_str(), stakeTx.vout[1].scriptPubKey[0]);
if (stakeTx.vin.size() == 1 &&
stakeTx.vout.size() == 2 &&
stakeTx.vout[0].nValue > 0 &&
stakeTx.vout[1].scriptPubKey.IsOpReturn() &&
UnpackStakeOpRet(stakeTx, vData))
{
stakeParams = CStakeParams(vData);
return stakeParams.IsValid();
}
return false;
}
// this validates the format of the stake transaction and, optionally, whether or not it is
// properly signed to spend the source stake.
// it does not validate the relationship to a coinbase guard, PoS eligibility or the actual stake spend.
// the only time it matters
// is to validate a properly formed stake transaction for either pre-check before PoS validity check, or to
// validate the stake transaction on a fork that will be used to spend a winning stake that cheated by being posted
// on two fork chains
bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig)
{
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
// a valid stake transaction has one input and two outputs, one output is the monetary value and one is an op_ret with CStakeParams
// stake output #1 must be P2PK or P2PKH, unless a delegate for the coinbase is specified
if (GetStakeParams(stakeTx, stakeParams))
{
// if we have gotten this far and are still valid, we need to validate everything else
// even if the utxo is spent, this can succeed, as it only checks that is was ever valid
CTransaction srcTx = CTransaction();
uint256 blkHash = uint256();
txnouttype txType;
CBlockIndex *pindex;
if (myGetTransaction(stakeTx.vin[0].prevout.hash, srcTx, blkHash))
{
BlockMap::const_iterator it = mapBlockIndex.find(blkHash);
if (it != mapBlockIndex.end() && (pindex = it->second) != NULL)
{
std::vector<std::vector<unsigned char>> vAddr = std::vector<std::vector<unsigned char>>();
if (stakeParams.srcHeight == pindex->GetHeight() &&
(stakeParams.blkHeight - stakeParams.srcHeight >= VERUS_MIN_STAKEAGE) &&
Solver(srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey, txType, vAddr))
{
if (txType == TX_PUBKEY && !stakeParams.pk.IsValid())
{
stakeParams.pk = CPubKey(vAddr[0]);
}
if ((txType == TX_PUBKEY) || (txType == TX_PUBKEYHASH && stakeParams.pk.IsFullyValid()))
{
auto consensusBranchId = CurrentEpochBranchId(stakeParams.blkHeight, Params().GetConsensus());
if (!validateSig || VerifyScript(stakeTx.vin[0].scriptSig,
srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey,
MANDATORY_SCRIPT_VERIFY_FLAGS,
TransactionSignatureChecker(&stakeTx, (uint32_t)0, srcTx.vout[stakeTx.vin[0].prevout.n].nValue),
consensusBranchId))
{
return true;
}
}
}
}
}
}
return false;
}
bool MakeGuardedOutput(CAmount value, CPubKey &dest, CTransaction &stakeTx, CTxOut &vout)
{
CCcontract_info *cp, C;
cp = CCinit(&C,EVAL_STAKEGUARD);
CPubKey ccAddress = CPubKey(ParseHex(cp->CChexstr));
// return an output that is bound to the stake transaction and can be spent by presenting either a signed condition by the original
// destination address or a properly signed stake transaction of the same utxo on a fork
vout = MakeCC1of2vout(EVAL_STAKEGUARD, value, dest, ccAddress);
std::vector<CPubKey> vPubKeys = std::vector<CPubKey>();
vPubKeys.push_back(dest);
vPubKeys.push_back(ccAddress);
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
hw << stakeTx.vin[0].prevout.hash;
hw << stakeTx.vin[0].prevout.n;
uint256 utxo = hw.GetHash();
vData.push_back(std::vector<unsigned char>(utxo.begin(), utxo.end()));
CStakeParams p;
if (GetStakeParams(stakeTx, p))
{
// prev block hash and height is here to make validation easy
vData.push_back(std::vector<unsigned char>(p.prevHash.begin(), p.prevHash.end()));
std::vector<unsigned char> height = std::vector<unsigned char>(4);
for (int i = 0; i < 4; i++)
{
height[i] = (p.blkHeight >> (8 * i)) & 0xff;
}
vData.push_back(height);
COptCCParams ccp = COptCCParams(COptCCParams::VERSION, EVAL_STAKEGUARD, 1, 2, vPubKeys, vData);
vout.scriptPubKey << ccp.AsVector() << OP_DROP;
return true;
}
return false;
}
// validates if a stake transaction is both valid and cheating, defined by:
// the same exact utxo source, a target block height of later than that of this tx that is also targeting a fork
// of the chain. we know the transaction is a coinbase
bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating)
{
// an invalid or non-matching stake transaction cannot cheat
cheating = false;
//printf("ValidateMatchingStake: ccTx.vin[0].prevout.hash: %s, ccTx.vin[0].prevout.n: %d\n", ccTx.vin[0].prevout.hash.GetHex().c_str(), ccTx.vin[0].prevout.n);
if (ccTx.IsCoinBase())
{
CStakeParams p;
if (ValidateStakeTransaction(stakeTx, p))
{
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
CScript dummy;
if (ccTx.vout[voutNum].scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() > 0)
{
COptCCParams ccp = COptCCParams(vParams[0]);
if (ccp.IsValid() & ccp.vData.size() >= 3 && ccp.vData[2].size() <= 4)
{
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
hw << stakeTx.vin[0].prevout.hash;
hw << stakeTx.vin[0].prevout.n;
uint256 utxo = hw.GetHash();
uint32_t height = 0;
int i, dataLen = ccp.vData[2].size();
for (i = dataLen - 1; i >= 0; i--)
{
height = (height << 8) + ccp.vData[2][i];
}
// for debugging strange issue
// printf("iterator: %d, height: %d, datalen: %d\n", i, height, dataLen);
if (utxo == uint256(ccp.vData[0]))
{
if (p.prevHash != uint256(ccp.vData[1]) && p.blkHeight >= height)
{
cheating = true;
return true;
}
// if block height is equal and we are at the else, prevHash must have been equal
else if (p.blkHeight == height)
{
return true;
}
}
}
}
}
}
return false;
}
// this attaches an opret to a mutable transaction that provides the necessary evidence of a signed, cheating stake transaction
bool MakeCheatEvidence(CMutableTransaction &mtx, const CTransaction &ccTx, uint32_t voutNum, const CTransaction &cheatTx)
{
std::vector<unsigned char> vch;
CDataStream s = CDataStream(SER_DISK, CLIENT_VERSION);
bool isCheater = false;
if (ValidateMatchingStake(ccTx, voutNum, cheatTx, isCheater) && isCheater)
{
CTxOut vOut = CTxOut();
int64_t opretype_stakecheat = OPRETTYPE_STAKECHEAT;
CScript vData = CScript();
cheatTx.Serialize(s);
vch = std::vector<unsigned char>(s.begin(), s.end());
vData << opretype_stakecheat << vch;
vch = std::vector<unsigned char>(vData.begin(), vData.end());
vOut.scriptPubKey << OP_RETURN << vch;
// printf("Script encoding inner:\n%s\nouter:\n%s\n", vData.ToString().c_str(), vOut.scriptPubKey.ToString().c_str());
vOut.nValue = 0;
mtx.vout.push_back(vOut);
}
return isCheater;
}
typedef struct ccFulfillmentCheck {
std::vector<CPubKey> &vPK;
std::vector<uint32_t> &vCount;
} ccFulfillmentCheck;
// to figure out which node is signed
int CCFulfillmentVisitor(CC *cc, struct CCVisitor visitor)
{
//printf("cc_typeName: %s, cc_isFulfilled: %x, cc_isAnon: %x, cc_typeMask: %x, cc_condToJSONString:\n%s\n",
// cc_typeName(cc), cc_isFulfilled(cc), cc_isAnon(cc), cc_typeMask(cc), cc_conditionToJSONString(cc));
if (strcmp(cc_typeName(cc), "secp256k1-sha-256") == 0)
{
cJSON *json = cc_conditionToJSON(cc);
if (json)
{
cJSON *pubKeyNode = json->child->next;
if (strcmp(pubKeyNode->string, "publicKey") == 0)
{
ccFulfillmentCheck *pfc = (ccFulfillmentCheck *)(visitor.context);
//printf("public key: %s\n", pubKeyNode->valuestring);
CPubKey pubKey = CPubKey(ParseHex(pubKeyNode->valuestring));
for (int i = 0; i < pfc->vPK.size(); i++)
{
if (i < pfc->vCount.size() && (pfc->vPK[i] == pubKey))
{
pfc->vCount[i]++;
}
}
}
cJSON_free(json);
}
}
return 1;
}
int IsCCFulfilled(CC *cc, ccFulfillmentCheck *ctx)
{
struct CCVisitor visitor = {&CCFulfillmentVisitor, NULL, 0, (void *)ctx};
cc_visit(cc, visitor);
//printf("count key 1: %d, count key 2: %d\n", ctx->vCount[0], ctx->vCount[1]);
return ctx->vCount[0];
}
bool StakeGuardValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
{
// WARNING: this has not been tested combined with time locks
// validate this spend of a transaction with it being past any applicable time lock and one of the following statements being true:
// 1. the spend is signed by the original output destination's private key and normal payment requirements, spends as normal
// 2. the spend is signed by the private key of the StakeGuard contract and pushes a signed stake transaction
// with the same exact utxo source, a target block height of later than or equal to this tx, and a different prevBlock hash
// first, check to see if the spending contract is signed by the default destination address
// if so, success and we are done
// get preConditions and parameters
std::vector<std::vector<unsigned char>> preConditions = std::vector<std::vector<unsigned char>>();
std::vector<std::vector<unsigned char>> params = std::vector<std::vector<unsigned char>>();
CTransaction txOut;
bool signedByFirstKey = false;
bool validCheat = false;
CC *cc = GetCryptoCondition(tx.vin[nIn].scriptSig);
if (cc)
{
COptCCParams ccp;
signedByFirstKey = false;
validCheat = false;
// tx is the spending tx, the cc transaction comes back in txOut
if (GetCCParams(eval, tx, nIn, txOut, preConditions, params))
{
if (preConditions.size() > 0)
{
ccp = COptCCParams(preConditions[0]);
}
if (ccp.IsValid() && ccp.m == 1 && ccp.n == 2 && ccp.vKeys.size() == 2)
{
std::vector<uint32_t> vc = {0, 0};
ccFulfillmentCheck fc = {ccp.vKeys, vc};
signedByFirstKey = (IsCCFulfilled(cc, &fc) != 0);
if ((!signedByFirstKey && ccp.evalCode == EVAL_STAKEGUARD && ccp.vKeys.size() == 2 && ccp.version == COptCCParams::VERSION) &&
params.size() == 2 && params[0].size() > 0 && params[0][0] == OPRETTYPE_STAKECHEAT)
{
CDataStream s = CDataStream(std::vector<unsigned char>(params[1].begin(), params[1].end()), SER_DISK, CLIENT_VERSION);
bool checkOK = false;
CTransaction cheatTx;
try
{
cheatTx.Unserialize(s);
checkOK = true;
}
catch (...)
{
}
if (checkOK && !ValidateMatchingStake(txOut, tx.vin[0].prevout.n, cheatTx, validCheat))
{
validCheat = false;
}
}
}
}
cc_free(cc);
}
if (!(signedByFirstKey || validCheat))
{
eval->Error("error reading coinbase or spending proof invalid\n");
return false;
}
else return true;
}
bool IsStakeGuardInput(const CScript &scriptSig)
{
printf("IsStakeGuardInput: not implemented");
return false;
}
UniValue StakeGuardInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx;
CPubKey pk;
CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_STAKEGUARD);
result.push_back(Pair("result","success"));
result.push_back(Pair("name","StakeGuard"));
// all UTXOs to the contract address that are to any of the wallet addresses are to us
// each is spendable as a normal transaction, but the spend may fail if it gets spent out
// from under us
pk = GetUnspendable(cp,0);
return(result);
}

View File

@@ -1,41 +0,0 @@
/********************************************************************
* (C) 2018 Michael Toutonghi
*
* Distributed under the MIT software license, see the accompanying
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
*
* This crypto-condition eval solves the problem of nothing-at-stake
* in a proof of stake consensus system.
*
*/
#ifndef STAKEGUARD_H
#define STAKEGUARD_H
#include <vector>
#include "CCinclude.h"
#include "streams.h"
#include "script/script.h"
#define DEFAULT_STAKE_TXFEE 0
bool UnpackStakeOpRet(const CTransaction &stakeTx, std::vector<std::vector<unsigned char>> &vData);
bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig = true);
bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating);
bool MakeGuardedOutput(CAmount value, CPubKey &dest, CTransaction &stakeTx, CTxOut &vout);
bool MakeCheatEvidence(CMutableTransaction &mtx, const CTransaction &ccTx, uint32_t voutNum, const CTransaction &cheatTx);
bool StakeGuardValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
bool IsStakeGuardInput(const CScript &scriptSig);
UniValue StakeGuardInfo();
#endif

View File

@@ -167,7 +167,6 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
//vout.n-1: opreturn [EVAL_ASSETS] ['c'] [{"<assetname>":"<description>"}]
return eval->Invalid("unexpected AssetValidate for createasset");
break;
case 't': // transfer
//vin.0: normal input
//vin.1 .. vin.n-1: valid CC outputs
@@ -250,8 +249,8 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
}
fprintf(stderr,"fillbuy validated\n");
break;
case 'e': // selloffer
break; // disable swaps
//case 'e': // selloffer
// break; // disable swaps
case 's': // selloffer
//vin.0: normal input
//vin.1+: valid CC output for sale
@@ -323,6 +322,7 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
fprintf(stderr,"fill validated\n");
break;
case 'E': // fillexchange
return eval->Invalid("unexpected assets fillexchange funcid");
break; // disable asset swaps
//vin.0: normal input
//vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0]
@@ -372,6 +372,10 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
}
fprintf(stderr,"fill validated\n");
break;
default:
fprintf(stderr,"illegal assets funcid.(%c)\n",funcid);
return eval->Invalid("unexpected assets funcid");
break;
}
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
}

View File

@@ -120,6 +120,7 @@ bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
int64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);

View File

@@ -62,46 +62,86 @@ Possible third iteration:
// start of consensus code
int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub, CPubKey destpub,int32_t v)
{
char destaddr[64];
char destaddr[65],channeladdr[65];
GetCCaddress1of2(cp,channeladdr,srcpub,destpub);
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,channeladdr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
}
int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub,int32_t v)
{
char destaddr[65],ccaddr[65];
GetCCaddress(cp,ccaddr,srcpub);
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,ccaddr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
}
CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain)
{
CScript opret; uint8_t evalcode = EVAL_CHANNELS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << opentxid << srcpub << destpub << numpayments << payment << hashchain);
return(opret);
}
uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
if ( vopret.size() > 2 )
{
script = (uint8_t *)vopret.data();
if ( script[0] == EVAL_CHANNELS )
{
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> opentxid; ss >> srcpub; ss >> destpub; ss >> numpayments; ss >> payment; ss >> hashchain) != 0 )
{
return(f);
}
} else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]);
} else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
return(0);
}
bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
{
static uint256 zerohash;
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
uint256 txid,param3;
CPubKey srcpub,destpub;
int32_t param1; int64_t param2; uint8_t funcid;
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
numvins = tx.vin.size();
numvouts = tx.vout.size();
for (i=0; i<numvins; i++)
if ((numvouts=tx.vout.size()) > 0 && DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)!=0)
{
//fprintf(stderr,"vini.%d\n",i);
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
for (i=0; i<numvins; i++)
{
//fprintf(stderr,"vini.%d check mempool\n",i);
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("cant find vinTx");
else
{
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant Channels from mempool");
if ( (assetoshis= IsChannelsvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
inputs += assetoshis;
inputs += vinTx.vout[tx.vin[i].prevout.n].nValue;
}
}
}
else
{
return eval->Invalid("invalid op_return data");
}
for (i=0; i<numvouts; i++)
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsChannelsvout(cp,tx,i)) != 0 )
outputs += assetoshis;
outputs += tx.vout[i].nValue;
}
if ( inputs != outputs+txfee )
{
@@ -113,9 +153,13 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,p1,param1; bool retval;
uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain;
uint8_t funcid,hash[32],hashdest[32];
int64_t p2,param2,payment;
CPubKey srcpub, destpub;
CTransaction channelOpenTx,channelCloseTx,prevTx;
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
@@ -123,15 +167,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
return eval->Invalid("no vouts");
else
{
for (i=0; i<numvins; i++)
{
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
{
return eval->Invalid("illegal normal vini");
}
}
//fprintf(stderr,"check amounts\n");
if ( ChannelsExactAmounts(cp,eval,tx,1,10000) == false )
if (ChannelsExactAmounts(cp,eval,tx,1,10000) == false )
{
fprintf(stderr,"Channelsget invalid amount\n");
return false;
@@ -140,10 +176,188 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
{
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, srcpub, destpub, param1, param2, param3)) != 0)
{
switch ( funcid )
{
case 'O':
//vin.0: normal input
//vout.0: CC vout for channel funding on CC1of2 pubkey
//vout.1: CC vout marker to senders pubKey
//vout.2: CC vout marker to receiver pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'O' zerotxid senderspubkey receiverspubkey totalnumberofpayments paymentamount hashchain
return eval->Invalid("unexpected ChannelsValidate for channelsopen!");
case 'P':
//vin.0: normal input
//vin.1: CC input from channel funding
//vin.2: CC input from src marker
//vout.0: CC vout change to CC1of2 pubkey
//vout.1: CC vout marker to senders pubKey
//vout.2: CC vout marker to receiver pubkey
//vout.3: normal output of payment amount to receiver pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret
if (isCCTxNotarizedConfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelPayment!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelPayment!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelPayment!");
else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.0 is CC for channelPayment!");
else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)!");
else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.2 is CC for channelPayment (marker to dstPub)!");
else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("vout.3 is normal for channelPayment!");
else if ( tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)
return eval->Invalid("payment funds do not go to receiver!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else
{
if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0)
{
if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
endiancpy(hash, (uint8_t * ) & param3, 32);
for (i = 0; i < numpayments-param1; i++)
{
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t*)&genhashchain,hashdest,32);
if (hashchain!=genhashchain)
return eval->Invalid("invalid secret for payment, does not reach final hashchain!");
else if (tx.vout[3].nValue != param2*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
}
if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if (param1+param2!=p1)
return eval->Invalid("invalid payment depth!");
else if (tx.vout[3].nValue > prevTx.vout[0].nValue)
return eval->Invalid("not enough funds in channel for that amount!");
}
}
break;
case 'C':
//vin.0: normal input
//vin.1: CC input from channel funding
//vin.2: CC input from src marker
//vout.0: CC vout for channel funding
//vout.1: CC vout marker to senders pubKey
//vout.2: CC vout marker to receiver pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0
if (isCCTxNotarizedConfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelClose!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelClose!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelClose!");
else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.0 is CC for channelClose!");
else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.1 is CC for channelClose (marker to srcPub)!");
else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.2 is CC for channelClose (marker to dstPub)!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
return eval->Invalid("invalid open txid!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
else if (tx.vout[0].nValue != param1*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if (tx.vout[0].nValue != prevTx.vout[0].nValue)
return eval->Invalid("invalid CC amount, amount must match funds in channel");
}
break;
case 'R':
//vin.0: normal input
//vin.1: CC input from channel funding
//vin.2: CC input from src marker
//vout.0: CC vout marker to senders pubKey
//vout.1: CC vout marker to receiver pubKey
//vout.2: normal output of CC input to senders pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpayments payment closetxid
if (isCCTxNotarizedConfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
else if (isCCTxNotarizedConfirmed(param3) == 0)
return eval->Invalid("channelClose is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelRefund!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelRefund!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelRefund!");
else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.0 is CC for channelRefund (marker to srcPub)!");
else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.1 is CC for channelRefund (marker to dstPub)!");
else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("vout.2 is normal for channelRefund!");
else if ( tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG)
return eval->Invalid("payment funds do not go to sender!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
return eval->Invalid("invalid open txid!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0)
return eval->Invalid("invalid close txid!");
else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C')
return eval->Invalid("invalid channelclose OP_RETURN data!");
else if (tmp_txid!=opentxid)
return eval->Invalid("invalid close tx, opentxid do not match on close and refund!");
else if (tx.vout[2].nValue != param1*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[0].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if (tx.vout[2].nValue != prevTx.vout[0].nValue)
return eval->Invalid("invalid amount, refund amount and funds in channel must match!");
}
break;
default:
fprintf(stderr,"illegal channels funcid.(%c)\n",funcid);
return eval->Invalid("unexpected channels funcid");
break;
}
} else return eval->Invalid("unexpected channels missing funcid");
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
fprintf(stderr,"Channelsget validated\n");
else fprintf(stderr,"Channelsget invalid\n");
fprintf(stderr,"Channel tx validated\n");
else fprintf(stderr,"Channel tx invalid\n");
return(retval);
}
}
@@ -152,65 +366,76 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
// helper functions for rpc calls in rpcwallet.cpp
CScript EncodeChannelsOpRet(uint8_t funcid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain)
int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, CTransaction openTx, uint256 &prevtxid)
{
CScript opret; uint8_t evalcode = EVAL_CHANNELS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << srcpub << destpub << numpayments << payment << hashchain);
return(opret);
}
uint8_t DecodeChannelsOpRet(uint256 txid,const CScript &scriptPubKey,CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid;
GetOpReturnData(scriptPubKey, vopret);
if ( vopret.size() > 2 )
{
script = (uint8_t *)vopret.data();
if ( script[0] == EVAL_CHANNELS )
{
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> srcpub; ss >> destpub; ss >> numpayments; ss >> payment; ss >> hashchain) != 0 )
{
return(f);
}
} else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]);
} else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
return(0);
}
int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
char coinaddr[65]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t param1;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
CPubKey srcpub,destpub;
uint8_t myprivkey[32];
if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O')
{
GetCCaddress1of2(cp,coinaddr,srcpub,destpub);
SetCCunspents(unspentOutputs,coinaddr);
}
else
{
fprintf(stderr,"invalid channel open txid\n");
return 0;
}
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0)
{
if ( (nValue= IsChannelsvout(cp,vintx,vout)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 &&
(tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) &&
(totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)+IsChannelsMarkervout(cp,tx,srcpub,1))>0)
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
txid = it->first.txhash;
break;
}
}
}
return(totalinputs);
if (txid!=zeroid && myIsutxo_spentinmempool(txid,0) != 0)
{
txid=zeroid;
int32_t mindepth=CHANNELS_MAXPAYMENTS;
BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx)
{
const CTransaction &txmempool = e.GetTx();
const uint256 &hash = txmempool.GetHash();
if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 &&
tmp_txid==openTx.GetHash() && param1 < mindepth)
{
txid=hash;
totalinputs=txmempool.vout[0].nValue+txmempool.vout[1].nValue;
mindepth=param1;
}
}
}
if (txid != zeroid)
{
prevtxid=txid;
mtx.vin.push_back(CTxIn(txid,0,CScript()));
mtx.vin.push_back(CTxIn(txid,1,CScript()));
Myprivkey(myprivkey);
CCaddr2set(cp,EVAL_CHANNELS,srcpub,myprivkey,coinaddr);
CCaddr3set(cp,EVAL_CHANNELS,destpub,myprivkey,coinaddr);
return totalinputs;
}
else return 0;
}
std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment)
{
CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; CPubKey mypk; struct CCcontract_info *cp,C;
CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy;
CPubKey mypk; struct CCcontract_info *cp,C;
if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS )
{
CCerror = strprintf("invalid ChannelsFund param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment);
CCerror = strprintf("invalid ChannelOpen param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment);
fprintf(stderr,"%s\n",CCerror.c_str());
return("");
}
@@ -221,7 +446,7 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
funds = numpayments * payment;
if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 )
{
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1);
endiancpy(hash,(uint8_t *)&hentropy,32);
for (i=0; i<numpayments; i++)
{
@@ -232,106 +457,319 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',mypk,destpub,numpayments,payment,hashchain)));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',zeroid,mypk,destpub,numpayments,payment,hashchain)));
}
return("");
}
std::string ChannelStop(uint64_t txfee,CPubKey destpub,uint256 origtxid)
std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret)
{
CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C;
CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3;
struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments,totalnumpayments;
int64_t payment,change,funds,param2;
uint8_t hash[32],hashdest[32];
CTransaction channelOpenTx,prevTx;
cp = CCinit(&C,EVAL_CHANNELS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
fprintf(stderr, "invalid channel open txid\n");
return ("");
}
if (AddNormalinputs(mtx,mypk,2*txfee,1) > 0)
{
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount-txfee)>=0)
{
if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O')
{
if (mypk != srcpub && mypk != destpub)
{
fprintf(stderr,"this is not our channel\n");
return("");
}
else if (amount % payment != 0 || amount<payment)
{
fprintf(stderr,"invalid amount, not a magnitude of payment size\n");
return ("");
}
numpayments=amount/payment;
if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0 && (numvouts=prevTx.vout.size()) > 0 &&
((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) &&
(funcid == 'P' || funcid=='O'))
{
if (numpayments > prevdepth)
{
fprintf(stderr,"not enough funds in channel for that amount\n");
return ("");
} else if (numpayments == 0)
{
fprintf(stderr,"invalid amount\n");
return ("");
}
if (secret!=zeroid)
{
endiancpy(hash, (uint8_t * ) & secret, 32);
for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++)
{
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t * ) & gensecret, hashdest, 32);
if (gensecret!=hashchain)
{
fprintf(stderr,"invalid secret supplied\n");
return("");
}
}
else
{
hentropy = DiceHashEntropy(entropy,channelOpenTx.vin[0].prevout.hash,channelOpenTx.vin[0].prevout.n,1);
if (prevdepth-numpayments)
{
endiancpy(hash, (uint8_t * ) & hentropy, 32);
for (i = 0; i < prevdepth-numpayments; i++)
{
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t * ) & secret, hashdest, 32);
}
else endiancpy((uint8_t * ) & secret, (uint8_t * ) & hentropy, 32);
}
}
else
{
fprintf(stderr,"invalid previous tx\n");
return("");
}
}
else
{
fprintf(stderr, "invalid channel open tx\n");
return ("");
}
mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG));
return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', opentxid, mypk, destpub, prevdepth-numpayments, numpayments, secret)));
}
else
{
fprintf(stderr,"error adding CC inputs\n");
return("");
}
}
fprintf(stderr,"error adding normal inputs\n");
return("");
}
std::string ChannelClose(uint64_t txfee,uint256 opentxid)
{
CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C;
CTransaction channelOpenTx;
uint256 hashblock,tmp_txid,prevtxid,hashchain;
int32_t numvouts,numpayments;
int64_t payment,funds;
// verify this is one of our outbound channels
cp = CCinit(&C,EVAL_CHANNELS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
fprintf(stderr, "invalid channel open txid\n");
return ("");
}
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{
fprintf(stderr, "invalid channel open tx\n");
return ("");
}
if (mypk != srcpub)
{
fprintf(stderr,"cannot close, you are not channel owner\n");
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
{
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('S',mypk,destpub,0,0,zeroid)));
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && funds-txfee>0)
{
mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,funds/payment,payment,zeroid)));
}
else
{
fprintf(stderr,"error adding CC inputs\n");
return("");
}
}
fprintf(stderr,"error adding normal inputs\n");
return("");
}
std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 origtxid,int32_t n,int64_t amount)
std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
{
CMutableTransaction mtx; CPubKey mypk,destpub; uint256 secret; struct CCcontract_info *cp,C; int32_t prevdepth;
// verify lasttxid and origtxid match and src is me
// also verify hashchain depth and amount, set prevdepth
cp = CCinit(&C,EVAL_CHANNELS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
{
// add locked funds inputs
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('P',mypk,destpub,prevdepth-n,amount,secret)));
}
return("");
}
CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,payment,param2;
int32_t i,numpayments,numvouts,param1;
uint256 hashchain,hashblock,txid,prevtxid,param3,entropy,hentropy,secret;
CTransaction channelOpenTx,channelCloseTx,prevTx;
CPubKey srcpub,destpub;
uint8_t funcid,hash[32],hashdest[32];;
std::string ChannelCollect(uint64_t txfee,uint256 paytxid,uint256 origtxid,int32_t n,int64_t amount)
{
CMutableTransaction mtx; CPubKey mypk,senderpub; struct CCcontract_info *cp,C; int32_t prevdepth;
// verify paytxid and origtxid match and dest is me
// also verify hashchain depth and amount
cp = CCinit(&C,EVAL_CHANNELS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
{
// add locked funds inputs
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',senderpub,mypk,prevdepth-n,amount,paytxid)));
}
return("");
}
std::string ChannelRefund(uint64_t txfee,uint256 stoptxid,uint256 origtxid)
{
CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t amount;
// verify stoptxid and origtxid match and are mine
cp = CCinit(&C,EVAL_CHANNELS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if (GetTransaction(closetxid,channelCloseTx,hashblock,false) == 0)
{
fprintf(stderr, "invalid channel close txid\n");
return ("");
}
if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,param1,param2,param3)!='C')
{
fprintf(stderr, "invalid channel close tx\n");
return ("");
}
if (txid!=opentxid)
{
fprintf(stderr, "open and close txid are not from same channel\n");
return ("");
}
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
fprintf(stderr, "invalid channel open txid\n");
return ("");
}
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{
fprintf(stderr, "invalid channel open tx\n");
return ("");
}
if (mypk != srcpub)
{
fprintf(stderr,"cannot refund, you are not the channel owenr\n");
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
{
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',mypk,mypk,0,0,stoptxid)));
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && funds-txfee>0)
{
if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 &&
DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3) != 0)
{
hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash, channelOpenTx.vin[0].prevout.n,1);
endiancpy(hash, (uint8_t * ) & hentropy, 32);
for (i = 0; i < param1; i++)
{
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t * ) & secret, hashdest, 32);
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(CTxOut(funds-txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,destpub,param1,payment,closetxid)));
}
else
{
fprintf(stderr,"previous tx is invalid\n");
return("");
}
}
else
{
fprintf(stderr,"error adding CC inputs\n");
return("");
}
}
return("");
}
UniValue ChannelsInfo()
UniValue ChannelsInfo(uint256 channeltxid)
{
UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,hashBlock,hashchain; struct CCcontract_info *cp,C; uint8_t funcid; char myCCaddr[64]; int32_t vout,numvouts,numpayments; int64_t nValue,payment; CPubKey srcpub,destpub,mypk;
UniValue result(UniValue::VOBJ); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid;
struct CCcontract_info *cp,C; char myCCaddr[65],addr[65],str1[512],str2[256]; int32_t vout,numvouts,param1,numpayments;
int64_t nValue,param2,payment; CPubKey srcpub,destpub,mypk;
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Channels"));
cp = CCinit(&C,EVAL_CHANNELS);
mypk = pubkey2pk(Mypubkey());
GetCCaddress(cp,myCCaddr,mypk);
SetCCtxids(txids,myCCaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
if (channeltxid==zeroid)
{
//int height = it->first.blockHeight;
txid = it->first.txhash;
vout = (int32_t)it->first.index;
nValue = (int64_t)it->second;
if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
result.push_back(Pair("name","Channels Info"));
GetCCaddress(cp,myCCaddr,mypk);
SetCCtxids(txids,myCCaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
{
if ( DecodeChannelsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,srcpub,destpub,numpayments,payment,hashchain) == 'O' || funcid == 'P' )
//int height = it->first.blockHeight;
txid = it->first.txhash;
vout = (int32_t)it->first.index;
nValue = (int64_t)it->second;
if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
char str[67],str2[67];
fprintf(stderr,"%s func.%c %s -> %s %.8f num.%d of %.8f\n",mypk == srcpub ? "send" : "recv",funcid,pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),(double)tx.vout[0].nValue/COIN,numpayments,(double)payment/COIN);
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O')
{
GetCCaddress1of2(cp,addr,srcpub,destpub);
sprintf(str1,"%s - %lld payments of %lld satoshi - %s",addr,(long long)param1,(long long)param2,tx.GetHash().ToString().c_str());
result.push_back(Pair("Channel", str1));
}
}
}
}
else
{
if (GetTransaction(channeltxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 &&
(DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O'))
{
GetCCaddress1of2(cp,addr,srcpub,destpub);
sprintf(str1,"Channel %s",addr);
result.push_back(Pair("name",str1));
SetCCtxids(txids,addr);
prevtxid=zeroid;
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
{
txid = it->first.txhash;
if (txid!=prevtxid && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O' && tx.GetHash()==channeltxid)
{
sprintf(str1,"%lld payments of %lld satoshi",(long long)param1,(long long)param2);
result.push_back(Pair("Open", str1));
}
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P' && opentxid==channeltxid)
{
if (GetTransaction(opentxid,opentx,hashBlock,false) != 0 && (numvouts=opentx.vout.size()) > 0 &&
DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O')
{
Getscriptaddress(str2,tx.vout[3].scriptPubKey);
sprintf(str1,"%lld satoshi to %s, %lld payments left",(long long)(param2*payment),str2,(long long)param1);
result.push_back(Pair("Payment",str1));
}
}
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C' && opentxid==channeltxid)
{
result.push_back(Pair("Close","channel"));
}
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'R' && opentxid==channeltxid)
{
Getscriptaddress(str2,tx.vout[2].scriptPubKey);
sprintf(str1,"%lld satoshi back to %s",(long long)(param1*param2),str2);
result.push_back(Pair("Refund",str1));
}
}
prevtxid=txid;
}
}
}
return(result);
}

6
src/cc/dapps/diceloop Executable file
View File

@@ -0,0 +1,6 @@
while true
do
./c dicestatus KMDICE 5be49570c56d036abb08b6d084da93a8a86f58fc48db4a1086be95540d752d6f
sleep 10
done

View File

@@ -1,24 +0,0 @@
#!/bin/bash
# SET AC
read -p "Enter AC name you use : " acname
sed -i "/#define ACNAME */c\#define ACNAME \"$acname\"" oraclefeed.c
# Set ORACLETXID
read -p "Enter your oracle TXID (Oracle should have L data type) : " oracletxid
sed -i "/#define ORACLETXID */c\#define ORACLETXID \"$oracletxid\"" oraclefeed.c
# SET PUBKEY
read -p "Enter your pubkey : " pubkey
sed -i "/#define MYPUBKEY */c\#define MYPUBKEY \"$pubkey\"" oraclefeed.c
# COMPILATION
echo "Great, compiling !"
gcc oraclefeed.c -lm -o oracle_dapp
mv oracle_dapp ../../oracle_dapp
echo "Oracle is ready to use !"
while true; do
read -p "Would you like to run BTCUSD oracle app? [Y/N]" yn
case $yn in
[Yy]* ) cd ../..; ./oracle_dapp; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done

View File

@@ -19,6 +19,8 @@
#include <memory.h>
#include "cJSON.c"
bits256 zeroid;
char hexbyte(int32_t c)
{
c &= 0xf;
@@ -139,7 +141,7 @@ long _stripwhite(char *buf,int accept)
char *clonestr(char *str)
{
char *clone;
if ( str == 0 || str[0] == 0 )
if ( str == 0 || str[0]==0)
{
printf("warning cloning nullstr.%p\n",str);
//#ifdef __APPLE__
@@ -308,17 +310,30 @@ uint64_t get_btcusd()
return(btcusd);
}
cJSON *get_komodocli(char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2)
char *REFCOIN_CLI;
cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3)
{
long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[256];
sprintf(fname,"/tmp/oraclefeed.%s",method);
if ( acname[0] != 0 )
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,fname);
else sprintf(cmdstr,"./komodo-cli %s %s %s %s > %s\n",method,arg0,arg1,arg2,fname);
{
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname);
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,fname);
}
else if ( strcmp(refcoin,"KMD") == 0 )
sprintf(cmdstr,"./komodo-cli %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,fname);
else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 )
{
sprintf(cmdstr,"%s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname);
printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
}
system(cmdstr);
*retstrp = 0;
if ( (jsonstr= filestr(&fsize,fname)) != 0 )
{
{
jsonstr[strlen(jsonstr)-1]='\0';
//fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr);
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
*retstrp = jsonstr;
@@ -327,13 +342,13 @@ cJSON *get_komodocli(char **retstrp,char *acname,char *method,char *arg0,char *a
return(retjson);
}
bits256 komodobroadcast(char *acname,cJSON *hexjson)
bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
{
char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
if ( (hexstr= jstr(hexjson,"hex")) != 0 )
{
if ( (retjson= get_komodocli(&retstr,acname,"sendrawtransaction",hexstr,"","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
{
//fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0));
free_json(retjson);
@@ -345,19 +360,19 @@ bits256 komodobroadcast(char *acname,cJSON *hexjson)
retstr[64] = 0;
decode_hex(txid.bytes,32,retstr);
}
fprintf(stderr,"broadcast %s txid.(%s)\n",acname,bits256_str(str,txid));
fprintf(stderr,"broadcast %s txid.(%s)\n",strlen(acname)>0?acname:refcoin,bits256_str(str,txid));
free(retstr);
}
}
return(txid);
}
bits256 sendtoaddress(char *acname,char *destaddr,int64_t satoshis)
bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis)
{
char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN);
if ( (retjson= get_komodocli(&retstr,acname,"sendtoaddress",destaddr,numstr,"")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"","")) != 0 )
{
fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0));
free_json(retjson);
@@ -375,36 +390,34 @@ bits256 sendtoaddress(char *acname,char *destaddr,int64_t satoshis)
return(txid);
}
int32_t get_KMDheight(char *acname)
int32_t get_coinheight(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr; int32_t height=0;
if ( (retjson= get_komodocli(&retstr,acname,"getinfo","","","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
{
height = jint(retjson,"blocks");
//fprintf(stderr,"%s height.%d\n",acname[0]!=0?acname:"KMD",height);
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_KMDheight.(%s) error.(%s)\n",acname,retstr);
fprintf(stderr,"%s get_coinheight.(%s) error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(height);
}
bits256 get_KMDblockhash(int32_t height)
bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height)
{
cJSON *retjson; char *retstr,heightstr[32]; bits256 hash;
memset(hash.bytes,0,sizeof(hash));
sprintf(heightstr,"%d",height);
if ( (retjson= get_komodocli(&retstr,"","getblockhash",heightstr,"","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
{
fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
//fprintf(stderr,"get_KMDblockhash.(%s) %d\n",retstr,(int32_t)strlen(retstr));
if ( strlen(retstr) >= 64 )
{
retstr[64] = 0;
@@ -415,11 +428,11 @@ bits256 get_KMDblockhash(int32_t height)
return(hash);
}
bits256 get_KMDmerkleroot(bits256 blockhash)
bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash)
{
cJSON *retjson; char *retstr,str[65]; bits256 merkleroot;
memset(merkleroot.bytes,0,sizeof(merkleroot));
if ( (retjson= get_komodocli(&retstr,"","getblockheader",bits256_str(str,blockhash),"","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
{
merkleroot = jbits256(retjson,"merkleroot");
//fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot));
@@ -427,24 +440,24 @@ bits256 get_KMDmerkleroot(bits256 blockhash)
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_KMDmerkleroot error.(%s)\n",retstr);
fprintf(stderr,"%s %s get_coinmerkleroot error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(merkleroot);
}
int32_t get_KMDheader(bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight)
int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight)
{
int32_t height = 0; char str[65];
if ( prevheight == 0 )
height = get_KMDheight("") - 20;
height = get_coinheight(refcoin,acname) - 20;
else height = prevheight + 1;
if ( height > 0 )
{
*blockhashp = get_KMDblockhash(height);
*blockhashp = get_coinblockhash(refcoin,acname,height);
if ( bits256_nonz(*blockhashp) != 0 )
{
*merklerootp = get_KMDmerkleroot(*blockhashp);
*merklerootp = get_coinmerkleroot(refcoin,acname,*blockhashp);
if ( bits256_nonz(*merklerootp) != 0 )
return(height);
}
@@ -454,26 +467,26 @@ int32_t get_KMDheader(bits256 *blockhashp,bits256 *merklerootp,int32_t prevheigh
return(0);
}
cJSON *get_gatewayspending(char *acname,char *oraclestxidstr,char *coin)
cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(&retstr,acname,"gatewayspending",oraclestxidstr,coin,"")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",bindtxidstr,refcoin,"","")) != 0 )
{
//printf("pending.(%s)\n",jprint(retjson,0));
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_gatewayspending.(%s) error.(%s)\n",acname,retstr);
fprintf(stderr,"%s get_gatewayspending.(%s) error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(0);
}
cJSON *get_rawmempool(char *acname)
cJSON *get_rawmempool(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(&retstr,acname,"getrawmempool","","","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
{
//printf("mempool.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -486,11 +499,13 @@ cJSON *get_rawmempool(char *acname)
return(0);
}
cJSON *get_addressutxos(char *acname,char *coinaddr)
cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
{
cJSON *retjson; char *retstr,jsonbuf[256];
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("warning: assumes %s has addressindex enabled\n",refcoin);
sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr);
if ( (retjson= get_komodocli(&retstr,acname,"getaddressutxos",jsonbuf,"","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
{
//printf("addressutxos.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -503,28 +518,209 @@ cJSON *get_addressutxos(char *acname,char *coinaddr)
return(0);
}
cJSON *get_rawtransaction(char *acname,bits256 txid)
cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
{
cJSON *retjson; char *retstr,str[65];
if ( (retjson= get_komodocli(&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
{
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_rawtransaction.(%s) error.(%s)\n",acname,retstr);
fprintf(stderr,"get_rawtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return(0);
}
void gatewaysmarkdone(char *acname,bits256 txid)
int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare)
{
cJSON *retjson; char *retstr; int32_t res=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 )
{
if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1;
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
return (res);
}
void importaddress(char *refcoin,char *acname,char *depositaddr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,"","true","")) != 0 )
{
printf("importaddress.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"importaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
free(retstr);
}
}
void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys,char *bindtxidstr)
{
cJSON *retjson; char *retstr,Mstr[10],tmp[128];
sprintf(Mstr,"%d",M);
sprintf(tmp,"\"%s\"",bindtxidstr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,tmp,"")) != 0 )
{
fprintf(stderr,"unexpected addmultisigaddress json.(%s)\n",jprint(retjson,0));
free(retstr);
}
else if ( retstr != 0 )
{
printf("addmultisigaddress.(%s)\n",retstr);
free_json(retjson);
}
}
cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required)
{
cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid;
*totalp = 0;
if ( (n= cJSON_GetArraySize(unspents)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(unspents,i);
satoshis = jdouble(item,"amount") * SATOSHIDEN;
txid = jbits256(item,"txid");
v = jint(item,"vout");
if ( bits256_nonz(txid) != 0 )
{
vin = cJSON_CreateObject();
jaddbits256(vin,"txid",txid);
jaddnum(vin,"vout",v);
jaddi(vins,vin);
*totalp += satoshis;
if ( (*totalp) >= required )
break;
}
}
}
return(vins);
}
char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signeraddr,char *withdrawaddr,int64_t satoshis)
{
char *retstr,*retstr2,array[128],*txstr = 0; cJSON *retjson2,*retjson,*vins,*vouts; int64_t txfee,total,change = 0;
if ( strcmp(refcoin,"BTC") == 0 )
txfee = 20000;
else txfee = 10000;
if ( satoshis < txfee )
{
printf("createmultisig satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN);
return(0);
}
satoshis -= txfee;
sprintf(array,"\'[\"%s\"]\'",depositaddr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 )
{
//createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...}
if ( (vins= getinputarray(&total,retjson,satoshis)) != 0 )
{
if ( total >= satoshis )
{
vouts = cJSON_CreateObject();
jaddnum(vouts,withdrawaddr,(double)satoshis/SATOSHIDEN);
if ( total > satoshis+txfee )
{
change = (total - satoshis);
jaddnum(vouts,depositaddr,(double)change/SATOSHIDEN);
}
char *tmpA=jprint(vins,1);
char *tmpB=jprint(vouts,1);
char *argA=malloc(sizeof(char) * (strlen(tmpA)+3));
char *argB=malloc(sizeof(char) * (strlen(tmpB)+3));
sprintf(argA,"\'%s\'",tmpA);
sprintf(argB,"\'%s\'",tmpB);
if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 )
{
printf("createmultisig: unexpected JSON2.(%s)\n",jprint(retjson2,0));
free_json(retjson2);
}
else if ( txstr == 0 )
printf("createmultisig: null txstr and JSON2\n");
free(tmpA);
free(tmpB);
free(argA);
free(argB);
}
}
free_json(retjson);
}
else if ( retstr != 0 )
{
printf("createmultisig: unexpected null JSON, retstr.(%s)\n",retstr);
free(retstr);
}
else printf("createmultisig: null retstr and JSON\n");
return(txstr);
}
cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx)
{
char *retstr,*hexstr; cJSON *retjson;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 )
{
if ( is_cJSON_True(jobj(retjson,"complete")) != 0 )
return(retjson);
else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) )
{
jaddnum(retjson,"partialtx",1);
return(retjson);
}
free_json(retjson);
}
return(0);
}
char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K)
{
char *retstr,*hexstr,*hex=0; cJSON *retjson;
if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",txidaddr,"","","")) != 0 )
{
if ((hexstr=jstr(retjson,"hex")) != 0 )
{
if (strlen(hexstr)>0) hex = clonestr(hexstr);
}
*K=jint(retjson,"number_of_signs");
free_json(retjson);
}
return(hex);
}
bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex)
{
char str[65],*retstr; cJSON *retjson;
printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,txid));
if ( (retjson= get_komodocli(&retstr,acname,"gatewaysmarkdone",bits256_str(str,txid),"","")) != 0 )
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 )
{
komodobroadcast(acname,retjson);
return(komodobroadcast(refcoin,acname,retjson));
}
else if ( retstr != 0 )
{
printf("error parsing gatewayspartialsing.(%s)\n",retstr);
free(retstr);
}
return (zeroid);
}
void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin,bits256 cointxid)
{
char str[65],str2[65],*retstr; cJSON *retjson;
printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,bits256_str(str2,cointxid),"")) != 0 )
{
komodobroadcast(refcoin,acname,retjson);
free_json(retjson);
}
else if ( retstr != 0 )
@@ -534,17 +730,57 @@ void gatewaysmarkdone(char *acname,bits256 txid)
}
}
int32_t tx_has_voutaddress(char *acname,bits256 txid,char *coinaddr)
int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys)
{
cJSON *txobj,*vouts,*vout,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numvouts,retval = 0;
if ( (txobj= get_rawtransaction(acname,txid)) != 0 )
char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 )
{
if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 )
if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 )
{
for (i=0; i<numvouts; i++)
strcpy(depositaddr,deposit);
if ( jstr(retjson,"coin") != 0 && strcmp(jstr(retjson,"coin"),coin) == 0 && jint(retjson,"N") >= 1 )
{
vout = jitem(vouts,i);
if ( (sobj= jobj(vout,"scriptPubKey")) != 0 )
*Mp = jint(retjson,"M");
*Np = jint(retjson,"N");
}
else printf("coin.%s vs %s\n",jstr(retjson,"coin"),coin);
if ((pubarray=jarray(&n,retjson,"pubkeys"))!=0)
{
*pubkeys=malloc((sizeof(char)*70*n)+64);
sprintf(*pubkeys,"\"[");
for (int i=0;i<n;i++)
{
sprintf(temp,"\\\"%s\\\"",jstri(pubarray,i));
if (i<n-1) strcat(temp,",");
strcat(*pubkeys,temp);
}
sprintf(temp,"]\"");
strcat(*pubkeys,temp);
}
}
else printf("%s != %s\n",oracle,oraclestr);
free_json(retjson);
}
else if ( retstr != 0 )
{
printf("error parsing get_gatewaysinfo.(%s)\n",retstr);
free(retstr);
}
if ( *Mp <= 0 || *Np <= 0 )
return(-1);
else return(0);
}
int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr)
{
cJSON *txobj,*vouts,*vout,*vins,*vin,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numarray,retval = 0, hasvout=0;
if ( (txobj= get_rawtransaction(refcoin,acname,txid)) != 0 )
{
if ( (vouts= jarray(&numarray,txobj,"vout")) != 0 )
{
for (i=0; i<numarray; i++)
{
if ((vout = jitem(vouts,i)) !=0 && (sobj= jobj(vout,"scriptPubKey")) != 0 )
{
if ( (addresses= jarray(&n,sobj,"addresses")) != 0 )
{
@@ -554,36 +790,65 @@ int32_t tx_has_voutaddress(char *acname,bits256 txid,char *coinaddr)
if ( strcmp(addr,coinaddr) == 0 )
{
//fprintf(stderr,"found %s in %s v%d\n",coinaddr,bits256_str(str,txid),i);
retval = 1;
hasvout = 1;
break;
}
}
}
}
if (hasvout==1) break;
}
}
// if (hasvout==1 && (vins=jarray(&numarray,txobj,"vin"))!=0)
// {
// for (int i=0;i<numarray;i++)
// {
// if ((vin=jitem(vins,i))!=0 && validateaddress(refcoin,acname,jstr(vin,"address"),"ismine")!=0)
// {
// retval=1;
// break;
// }
// }
// }
free_json(txobj);
}
return(retval);
return(hasvout);
}
int32_t coinaddrexists(char *acname,char *coinaddr)
int32_t markerfromthisnodeorunconfirmed(char *refcoin,char *acname,char *coinaddr)
{
cJSON *array; bits256 txid; int32_t i,n,num=0;
if ( (array= get_addressutxos(acname,coinaddr)) != 0 )
cJSON *array,*item,*rawtx,*vins,*vin; bits256 txid,tmptxid; int32_t i,n,m,num=0; char *retstr;
if ( (array= get_addressutxos(refcoin,acname,coinaddr)) != 0 )
{
num = cJSON_GetArraySize(array);
free_json(array);
} else return(-1);
n=cJSON_GetArraySize(array);
for (i=0; i<n; i++)
{
if ((item=jitem(array,i))!=0 && (bits256_nonz(tmptxid=jbits256(item,"txid")))!=0 && (rawtx=get_rawtransaction(refcoin,acname,tmptxid))!=0 && (vins=jarray(&m,rawtx,"vin"))!=0)
{
for (int j=0;j<m;j++)
{
if ((vin=jitem(vins,j))!=0 && validateaddress(refcoin,acname,jstr(vin,"address"),"ismine")!=0)
{
num=1;
break;
}
}
}
if (num==1) break;
}
free_json(array);
}
else return(-1);
if ( num == 0 )
{
if ( (array= get_rawmempool(acname)) != 0 )
if ( (array= get_rawmempool(refcoin,acname)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) != 0 )
{
for (i=0; i<n; i++)
{
txid = jbits256i(array,i);
if ( tx_has_voutaddress(acname,txid,coinaddr) > 0 )
if ( tx_has_voutaddress(refcoin,acname,txid,coinaddr) > 0 )
{
num = 1;
break;
@@ -592,11 +857,11 @@ int32_t coinaddrexists(char *acname,char *coinaddr)
}
free_json(array);
} else return(-1);
}
}
return(num);
}
void update_gatewayspending(char *acname,char *oraclestxidstr,char *coin)
void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N)
{
// check queue to prevent duplicate
// check KMD chain and mempool for txidaddr
@@ -605,10 +870,11 @@ void update_gatewayspending(char *acname,char *oraclestxidstr,char *coin)
/// if enough sigs, sendrawtransaction and when it confirms spend marker (txid.2)
/// if not enough sigs, post partially signed to acname with marker2
// monitor marker2, for the partially signed withdraws
cJSON *retjson,*pending,*item; char str[65],*coinstr,*txidaddr,*signeraddr,*withdrawaddr; int32_t i,n,retval,processed = 0; bits256 txid,withtxid,origtxid; int64_t satoshis;
if ( (retjson= get_gatewayspending(acname,oraclestxidstr,coin)) != 0 )
cJSON *retjson,*pending,*item,*clijson; char str[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,origtxid; int64_t satoshis;
memset(&zeroid,0,sizeof(zeroid));
if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 )
{
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,coin) == 0 )
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
{
if ( (pending= jarray(&n,retjson,"pending")) != 0 )
{
@@ -619,33 +885,64 @@ void update_gatewayspending(char *acname,char *oraclestxidstr,char *coin)
item = jitem(pending,i);
origtxid = jbits256(item,"txid");
//process item.0 {"txid":"10ec8f4dad6903df6b249b361b879ac77b0617caad7629b97e10f29fa7e99a9b","txidaddr":"RMbite4TGugVmkGmu76ytPHDEQZQGSUjxz","withdrawaddr":"RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc","amount":"1.00000000","depositaddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","signeraddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj"}
if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
{
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && (retval= coinaddrexists(acname,txidaddr)) == 0 )
{
// this is less errors but more expensive: ./komodo-cli z_sendmany "signeraddr" '[{"address":"<txidaddr>","amount":0.0001},{"address":"<withdrawaddr>","amount":<withamount>}]'
txid = sendtoaddress(acname,txidaddr,10000);
if ( bits256_nonz(txid) != 0 && coinaddrexists(acname,txidaddr) > 0 )
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0)
{
// the actual withdraw
if ( strcmp(depositaddr,signeraddr) == 0 )
{
// the actual withdraw
withtxid = sendtoaddress(strcmp("KMD",coin)==0?"":coin,withdrawaddr,satoshis);
if ( bits256_nonz(withtxid) != 0 )
txid= sendtoaddress("KMD",acname,txidaddr,10000);
if (bits256_nonz(txid) != 0)
{
fprintf(stderr,"withdraw %s %s %s %.8f processed\n",coin,bits256_str(str,withtxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
gatewaysmarkdone(acname,origtxid);
processed++;
cointxid = sendtoaddress(refcoin,"",withdrawaddr,satoshis);
if ( bits256_nonz(cointxid) != 0)
{
fprintf(stderr,"withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid);
processed++;
}
else
{
fprintf(stderr,"ERROR withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
}
}
else
{
fprintf(stderr,"ERROR withdraw %s %s %s %.8f processed\n",coin,bits256_str(str,withtxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
fprintf(stderr,"ERROR sending withdraw marker %s %s to %s %.8f processed\n",refcoin,bits256_str(str,cointxid),txidaddr,(double)10000/SATOSHIDEN);
}
} else fprintf(stderr,"error sending %s txidaddr.%s -> %s exists.%d\n",acname,txidaddr,bits256_str(str,txid),coinaddrexists(acname,txidaddr));
}
else if ( retval > 0 )
{
fprintf(stderr,"already did withdraw %s %s %.8f processed\n",coin,withdrawaddr,(double)satoshis/SATOSHIDEN);
gatewaysmarkdone(acname,origtxid);
}
}
else
{
if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0)
{
rawtx = createmultisig(refcoin,"",depositaddr,signeraddr,withdrawaddr,satoshis);
}
if ( rawtx != 0 )
{
if ( (clijson= addmultisignature(refcoin,"",signeraddr,rawtx)) != 0 )
{
if ( is_cJSON_True(jobj(clijson,"complete")) != 0 )
{
cointxid = komodobroadcast(refcoin,"",clijson);
if ( bits256_nonz(cointxid) != 0 )
{
fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN);
gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid);
}
}
else if ( jint(clijson,"partialtx") != 0 )
{
txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex"));
fprintf(stderr,"%d of %d partialtx %s sent\n",K+1,N,bits256_str(str,txid));
}
free_json(clijson);
}
processed++;
free(rawtx);
} else fprintf(stderr,"couldnt create msig rawtx\n");
}
}
}
}
}
@@ -654,7 +951,7 @@ void update_gatewayspending(char *acname,char *oraclestxidstr,char *coin)
}
}
int32_t get_oracledata(int32_t prevheight,char *hexstr,int32_t maxsize,char *format)
int32_t get_oracledata(char *refcoin,char *acname,int32_t prevheight,char *hexstr,int32_t maxsize,char *format)
{
int32_t i; uint32_t height; uint64_t price; bits256 blockhash,merkleroot;
hexstr[0] = 0;
@@ -670,7 +967,7 @@ int32_t get_oracledata(int32_t prevheight,char *hexstr,int32_t maxsize,char *for
}
else if ( strcmp(format,"Ihh") == 0 )
{
if ( (height= get_KMDheader(&blockhash,&merkleroot,prevheight)) > prevheight )
if ( (height= get_coinheader(refcoin,acname,&blockhash,&merkleroot,prevheight)) > prevheight )
{
for (i=0; i<4; i++)
sprintf(&hexstr[i*2],"%02x",(uint8_t)((height >> (i*8)) & 0xff));
@@ -711,28 +1008,56 @@ oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 034
int32_t main(int32_t argc,char **argv)
{
cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,n,height,prevheight = 0; char *format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,hexstr[4096]; uint64_t price; bits256 txid;
if ( argc != 6 )
cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,M,N,n,height,prevheight = 0; char *pubkeys,*format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid;
if ( argc < 6 )
{
printf("usage: oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID\nPowered by CoinDesk (%s) %.8f\n","https://www.coindesk.com/price/",dstr(get_btcusd()));
printf("usage: oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID [refcoin_cli]\n");
return(-1);
}
printf("Powered by CoinDesk (%s) %.8f\n","https://www.coindesk.com/price/",dstr(get_btcusd()));
acname = argv[1];
oraclestr = argv[2];
pkstr = argv[3];
format = argv[4];
bindtxidstr = argv[5];
if ( argc > 6 )
REFCOIN_CLI = argv[6];
else REFCOIN_CLI = "./komodo-cli";
if ( strncmp(format,"Ihh",3) != 0 && format[0] != 'L' )
{
printf("only formats of L and Ihh are supported now\n");
return(-1);
}
M = N = 1;
acheight = 0;
refcoin[0] = 0;
while ( 1 )
{
retstr = 0;
if ( prevheight < (get_KMDheight("") - 10) && (clijson= get_komodocli(&retstr,acname,"oraclesinfo",oraclestr,"","")) != 0 )
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_komodocli("KMD",&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
{
if ( refcoin[0] == 0 && jstr(clijson,"name") != 0 )
{
strcpy(refcoin,jstr(clijson,"name"));
if ( strcmp("KMD",refcoin) != 0 && argc != 7 )
{
printf("need to specify path to refcoin's cli as last argv\n");
exit(0);
}
pubkeys=0;
if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) < 0 )
{
printf("cant find bindtxid.(%s)\n",bindtxidstr);
exit(0);
}
if (validateaddress(refcoin,"",depositaddr,"iswatchonly")==0)
{
if (M==N==1) importaddress(refcoin,"",depositaddr);
else addmultisigaddress(refcoin,"",M,pubkeys,bindtxidstr);
}
if (pubkeys!=0) free(pubkeys);
printf("set refcoin %s <- %s [%s] M.%d of N.%d\n",depositaddr,refcoin,REFCOIN_CLI,M,N);
}
if ( (regjson= jarray(&n,clijson,"registered")) != 0 )
{
for (i=0; i<n; i++)
@@ -740,18 +1065,18 @@ int32_t main(int32_t argc,char **argv)
item = jitem(regjson,i);
if ( (pubstr= jstr(item,"publisher")) != 0 && strcmp(pkstr,pubstr) == 0 )
{
if ( (height= get_oracledata(prevheight,hexstr,sizeof(hexstr),"Ihh")) != 0 )
if ( (height= get_oracledata(refcoin,"",prevheight,hexstr,sizeof(hexstr),"Ihh")) != 0 )
{
if ( (clijson2= get_komodocli(&retstr2,acname,"oraclesdata",oraclestr,hexstr,"")) != 0 )
if ( (clijson2= get_komodocli("KMD",&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
{
//printf("data.(%s)\n",jprint(clijson2,0));
txid = komodobroadcast(acname,clijson2);
txid = komodobroadcast("KMD",acname,clijson2);
if ( bits256_nonz(txid) != 0 )
{
prevheight = height;
acheight = get_KMDheight(acname);
printf("ht.%d <- %s\n",height,hexstr);
update_gatewayspending(acname,bindtxidstr,"KMD");
acheight = get_coinheight(refcoin,"");
printf("%s ht.%d <- %s\n",refcoin,height,hexstr);
update_gatewayspending(refcoin,acname,bindtxidstr,M,N);
}
free_json(clijson2);
}

3
src/cc/dapps/sendmany Executable file
View File

@@ -0,0 +1,3 @@
export addr="RXgCPfi6wccRr3Eai3X9duTTkAirhcQLNo"
./komodo-cli -ac_name=KMDICE sendmany "" "{\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023}"

File diff suppressed because it is too large Load Diff

View File

@@ -76,15 +76,13 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
case EVAL_IMPORTPAYOUT:
//return ImportPayout(vparams, txTo, nIn);
break;
case EVAL_IMPORTCOIN:
//return ImportCoin(vparams, txTo, nIn);
break;
default:
// only support coinbase guard for now
if (ecode == EVAL_STAKEGUARD)
return(ProcessCC(cp,this, vparams, txTo, nIn));
return(ProcessCC(cp,this, vparams, txTo, nIn));
break;
}
return Invalid("invalid-code, dont forget to add EVAL_NEWCC to Eval::Dispatch");
@@ -100,10 +98,9 @@ bool Eval::GetSpendsConfirmed(uint256 hash, std::vector<CTransaction> &spends) c
bool Eval::GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const
{
// there is a LOCK(cs_main) in the normal GetTransaction(), which leads to deadlocks
//bool fAllowSlow = false; // Don't allow slow
//return GetTransaction(hash, txOut, hashBlock, fAllowSlow);
return myGetTransaction(hash, txOut,hashBlock);
if (!myGetTransaction(hash, txOut,hashBlock)) {
return(GetTransaction(hash, txOut,hashBlock));
} else return(true);
}
@@ -117,7 +114,6 @@ bool Eval::GetTxConfirmed(const uint256 &hash, CTransaction &txOut, CBlockIndex
return true;
}
unsigned int Eval::GetCurrentHeight() const
{
return chainActive.Height();

View File

@@ -36,9 +36,9 @@
* there should be a code identifying it. For example,
* a possible code is EVAL_BITCOIN_SCRIPT, where the entire binary
* after the code is interpreted as a bitcoin script.
* Verus EVAL_STAKEGUARD is 0x01
*/
#define FOREACH_EVAL(EVAL) \
EVAL(EVAL_STAKEGUARD, 0x1) \
EVAL(EVAL_IMPORTPAYOUT, 0xe1) \
EVAL(EVAL_IMPORTCOIN, 0xe2) \
EVAL(EVAL_ASSETS, 0xe3) \
@@ -48,7 +48,7 @@
EVAL(EVAL_FSM, 0xe7) \
EVAL(EVAL_AUCTION, 0xe8) \
EVAL(EVAL_LOTTO, 0xe9) \
EVAL(EVAL_MOFN, 0xea) \
EVAL(EVAL_HEIR, 0xea) \
EVAL(EVAL_CHANNELS, 0xeb) \
EVAL(EVAL_ORACLES, 0xec) \
EVAL(EVAL_PRICES, 0xed) \

View File

@@ -142,14 +142,17 @@ bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/maxinputs;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
continue;
//char str[65]; fprintf(stderr,"check %s/v%d %.8f`\n",uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )

View File

@@ -122,6 +122,7 @@ bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, u
int64_t AddFSMInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);

View File

@@ -18,10 +18,10 @@
/*
prevent duplicate bindtxid via mempool scan
wait for notarization for oraclefeed and validation of gatewaysdeposit
debug multisig and do partial signing
validation
string oracles
string oracles
*/
/*
@@ -58,7 +58,7 @@ string oracles
5. Now a gatewaysbind can bind an external coin to an asset, along with the oracle for the merkleroots. the txid from the bind is used in most of the other gateways CC calls
usage:
./c tokencreate KMD 1000000 KMD_equivalent_token_for_gatewaysCC
./c tokencreate KMD 1000000 KMD_equivalent_token_for_gatewaysCC
a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a
transfer to gateways pubkey: 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 RDMqGyREkP1Gwub1Nr5Ye8a325LGZsWBCb
@@ -74,6 +74,7 @@ string oracles
./c oraclessubscribe 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 1000
f9499d8bb04ffb511fcec4838d72e642ec832558824a2ce5aed87f1f686f8102
gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)
./c gatewaysbind a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 KMD 100000000000000 1 1 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92
e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e
@@ -93,7 +94,7 @@ string oracles
"remaining": "1000000.00000000",
"issued": "0.00000000"
}
To make a gateway deposit, send the funds to the "deposit" address, along with any amount to the same pubkey address you want to get the assetized KMD to appear in.
0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 pubkey for RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha
@@ -105,16 +106,16 @@ string oracles
./komodo-cli getrawtransaction bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009
010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b
gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount
./komodo-cli -ac_name=AT5 gatewaysdeposit e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e 1003776 KMD bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 0 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
./komodo-cli -ac_name=AT5 gatewaysdeposit e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e 1003776 KMD bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 0 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
-> 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6
to get the merkleroots onchain, from the multisig signers nodes run the oraclefeed program with acname oracletxid pubkey Ihh
./oraclefeed AT5 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 Ihh
gatewaysclaim bindtxid coin deposittxid destpub amount
./c gatewaysclaim e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
./c gatewaysclaim e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999
now the asset is in the pubkey's asset address!
it can be used, traded freely and any node who has the asset can do a gatewayswithdraw
@@ -125,14 +126,24 @@ string oracles
Now there is a withdraw pending, so it needs to be processed by the signing nodes on the KMD side
gatewayspending bindtxid coin
gatewayspending bindtxid coin
gatewayspending will display all pending withdraws and if it is done on one of the msigpubkeys, then it will queue it for processing
./c gatewayspending e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD
*/
Implementation Issues:
When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly.
Care must be taken so that tokens are not lost and can be converted back.
This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241
The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS.
*/
int32_t GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue)
void GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue)
{
char destaddr[64],str[65];
Getscriptaddress(destaddr,scriptPubKey);
@@ -167,6 +178,41 @@ uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint25
return(0);
}
uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,int32_t &K, CPubKey &signerpk, std::string &coin,std::string &hex)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> K; ss >> signerpk; ss >> coin; ss >> hex) != 0 )
{
return(f);
}
return(0);
}
uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &assetid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 )
{
return(f);
}
return(0);
}
uint8_t DecodeGatewaysMarkdoneOpRet(const CScript &scriptPubKey, std::string &refcoin, uint256 &cointxid)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> cointxid) != 0 )
{
return(f);
}
return(0);
}
uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector<CPubKey> &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
@@ -178,8 +224,11 @@ uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,st
if ( prefix == 60 )
{
if ( N > 1 )
Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG);
{
strcpy(depositaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,pubkeys))).ToString().c_str());
//Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
fprintf(stderr,"f.%c M.%d of N.%d size.%d -> %s\n",f,M,N,(int32_t)pubkeys.size(),depositaddr);
} else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG);
}
else
{
@@ -281,28 +330,47 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 refassetid,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector<uint8_t> origpubkey; std::vector<uint8_t> vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/maxinputs;
fprintf(stderr,"check %s for gateway inputs\n",coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
// no need to prevent dup
if ( it->second.satoshis < threshold )
continue;
for (j=0; j<mtx.vin.size(); j++)
if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
break;
if ( j != mtx.vin.size() )
continue;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey);
fprintf(stderr,"check %s vout.%d %.8f %.8f\n",destaddr,vout,(double)vintx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
continue;
GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret);
if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> assetid) != 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
assetid = revuint256(assetid);
char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for refassetid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,refassetid),uint256_str(str2,assetid),(double)vintx.vout[vout].nValue/COIN);
if ( assetid == refassetid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
//fprintf(stderr,"total %llu maxinputs.%d %.8f\n",(long long)total,maxinputs,(double)it->second.satoshis/COIN);
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
//nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
}
}
}
}
@@ -376,7 +444,7 @@ UniValue GatewaysInfo(uint256 bindtxid)
result.push_back(Pair("name","Gateways"));
cp = CCinit(&C,EVAL_GATEWAYS);
Gatewayspk = GetUnspendable(cp,0);
_GetCCaddress(gatewaysassets,EVAL_ASSETS,Gatewayspk);
_GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk);
if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 )
{
depositaddr[0] = 0;
@@ -399,7 +467,7 @@ UniValue GatewaysInfo(uint256 bindtxid)
result.push_back(Pair("tokenid",uint256_str(str,tokenid)));
sprintf(numstr,"%.8f",(double)totalsupply/COIN);
result.push_back(Pair("totalsupply",numstr));
remaining = CCaddress_balance(gatewaysassets);
remaining = CCtoken_balance(gatewaysassets,tokenid);
sprintf(numstr,"%.8f",(double)remaining/COIN);
result.push_back(Pair("remaining",numstr));
sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN);
@@ -432,19 +500,24 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t
{
CMutableTransaction mtx; CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char destaddr[64],coinaddr[64],str[65],*fstr;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( strcmp((char *)"KMD",coin.c_str()) == 0 )
{
taddr = 0;
prefix = 60;
prefix2 = 85;
}
else
{
fprintf(stderr,"set taddr, prefix, prefix2 for %s\n",coin.c_str());
taddr = 0;
prefix = 60;
prefix2 = 85;
}
if ( N == 0 || N > 15 || M > N )
{
fprintf(stderr,"illegal M.%d or N.%d\n",M,N);
return("");
}
if ( strcmp((char *)"KMD",coin.c_str()) != 0 )
{
fprintf(stderr,"only KMD supported for now\n");
return("");
}
taddr = 0;
prefix = 60;
prefix2 = 85;
if ( pubkeys.size() != N )
{
fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size());
@@ -463,7 +536,7 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( _GetCCaddress(destaddr,EVAL_ASSETS,gatewayspk) == 0 )
if ( _GetCCaddress(destaddr,EVAL_GATEWAYS,gatewayspk) == 0 )
{
fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid));
return("");
@@ -475,7 +548,7 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t
}
if ( CCtoken_balance(destaddr,tokenid) != totalsupply )
{
fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)totalsupply/COIN);
fprintf(stderr,"Gateway bind.%s (%s) destaddr.%s globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),destaddr,cp->unspendableCCaddr,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)totalsupply/COIN);
return("");
}
if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
@@ -509,26 +582,38 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t
uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
{
CTransaction tx; uint256 hash,mhash,hashBlock,oracletxid; int64_t val; int32_t numvouts; int64_t merkleht; CPubKey pk; std::vector<uint8_t>data;
CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts; int64_t val,merkleht; CPubKey pk; std::vector<uint8_t>data;
txid = zeroid;
char str[65]; fprintf(stderr,"reverse scan %s\n",uint256_str(str,batontxid));
char str[65];
//fprintf(stderr,"start reverse scan %s\n",uint256_str(str,batontxid));
while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
fprintf(stderr,"reverse scan %s\n",uint256_str(str,batontxid));
if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,hash,pk,data) == 'D' && oracletxid == reforacletxid )
//fprintf(stderr,"check %s\n",uint256_str(str,batontxid));
if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid )
{
//fprintf(stderr,"decoded %s\n",uint256_str(str,batontxid));
if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height )
{
if ( oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()) == sizeof(hash) &&
oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()) == sizeof(hash) && mhash != zeroid )
len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size());
len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size());
char str2[65]; fprintf(stderr,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash));
if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid )
{
txid = batontxid;
//fprintf(stderr,"set txid\n");
return(mhash);
} else return(zeroid);
}
batontxid = hash;
}
else
{
//fprintf(stderr,"missing hash\n");
return(zeroid);
}
} //else fprintf(stderr,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height);
batontxid = bhash;
//fprintf(stderr,"new hash %s\n",uint256_str(str,batontxid));
} else break;
}
fprintf(stderr,"end of loop\n");
return(zeroid);
}
@@ -584,18 +669,18 @@ int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout
}
if ( txid == cointxid )
{
fprintf(stderr,"verify proof for cointxid in merkleroot\n");
fprintf(stderr,"verified proof for cointxid in merkleroot\n");
return(nValue);
} else fprintf(stderr,"(%s) != (%s) or txid mismatch.%d or script mismatch\n",refdepositaddr,destaddr,txid != cointxid);
} else fprintf(stderr,"(%s) != (%s) or txid %s mismatch.%d or script mismatch\n",refdepositaddr,destaddr,uint256_str(str,txid),txid != cointxid);
return(0);
}
int64_t GatewaysDepositval(CTransaction tx)
int64_t GatewaysDepositval(CTransaction tx,CPubKey mypk)
{
int32_t numvouts,height; int64_t amount; std::string coin,deposithex; std::vector<CPubKey> publishers; std::vector<uint256>txids; uint256 bindtxid,cointxid; std::vector<uint8_t> proof; CPubKey claimpubkey;
if ( (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' )
if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk )
{
// coin, bindtxid, publishers
fprintf(stderr,"need to validate deposittxid more\n");
@@ -639,7 +724,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::
txids.push_back(txid);
}
}
fprintf(stderr,"m.%d of n.%d\n",m,n);
fprintf(stderr,"cointxid.%s m.%d of n.%d\n",uint256_str(str,cointxid),m,n);
if ( merkleroot == zeroid || m < n/2 )
{
//uint256 tmp;
@@ -660,7 +745,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::
}
if ( AddNormalinputs(mtx,mypk,3*txfee,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,destpub));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,destpub,amount)));
}
@@ -670,18 +755,12 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount)
{
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint8_t M,N,taddr,prefix,prefix2,mypriv[32]; std::string coin; std::vector<CPubKey> msigpubkeys; int64_t totalsupply,depositamount,inputs,CCchange=0; int32_t numvouts; uint256 hashBlock,assetid,oracletxid; char str[65],depositaddr[64],coinaddr[64];
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; int64_t totalsupply,depositamount,inputs,CCchange=0; int32_t numvouts; uint256 hashBlock,assetid,oracletxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64];
cp = CCinit(&C,EVAL_GATEWAYS);
assetscp = CCinit(&C2,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
_GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
CCaddr2set(assetscp,EVAL_ASSETS,gatewayspk,cp->CCpriv,coinaddr);
Myprivkey(mypriv);
_GetCCaddress(coinaddr,EVAL_GATEWAYS,mypk);
CCaddr3set(assetscp,EVAL_GATEWAYS,mypk,mypriv,coinaddr);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
@@ -694,10 +773,10 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui
}
if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
fprintf(stderr,"cant find deposittxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( (depositamount= GatewaysDepositval(tx)) != amount )
if ( (depositamount= GatewaysDepositval(tx,mypk)) != amount )
{
fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN);
return("");
@@ -705,35 +784,33 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui
//fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2);
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( (inputs= AddAssetInputs(assetscp,mtx,gatewayspk,assetid,amount,60)) > 0 )
if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,assetid,amount,60)) > 0 )
{
if ( inputs > amount )
CCchange = (inputs - amount);
mtx.vin.push_back(CTxIn(deposittxid,0,CScript()));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk));
_GetCCaddress(destaddr,EVAL_GATEWAYS,mypk);
printf("expecting deposittxid/v0 to be to %s\n",destaddr);
mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk)); // transfer back to normal token
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,gatewayspk));
return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
}
}
fprintf(stderr,"cant find enough inputs or mismatched total\n");
return("");
}
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount)
{
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2,mypriv[32]; std::string coin; std::vector<CPubKey> msigpubkeys; char depositaddr[64],str[65],coinaddr[64];
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C;
uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin;
std::vector<CPubKey> msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; CScript opret;
cp = CCinit(&C,EVAL_GATEWAYS);
assetscp = CCinit(&C2,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
_GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
CCaddr2set(assetscp,EVAL_ASSETS,gatewayspk,cp->CCpriv,coinaddr);
Myprivkey(mypriv);
_GetCCaddress(coinaddr,EVAL_GATEWAYS,mypk);
CCaddr3set(assetscp,EVAL_GATEWAYS,mypk,mypriv,coinaddr);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
@@ -746,42 +823,49 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin
}
if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 )
{
if ( (inputs= AddAssetInputs(assetscp,mtx,mypk,assetid,amount,60)) > 0 )
if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,assetid,amount,60)) > 0 )
{
if ( inputs > amount )
CCchange = (inputs - amount);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,gatewayspk));
mtx.vout.push_back(CTxOut(txfee,CScript() << withdrawpub << OP_CHECKSIG));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG));
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,amount,gatewayspk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG));
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk));
opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'W' << assetid << refcoin << withdrawpub << amount);
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
}
fprintf(stderr,"cant find enough inputs or mismatched total\n");
return("");
}
std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid)
std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid)
{
CMutableTransaction mtx; CScript opret; CPubKey mypk; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 5000;
mypk = pubkey2pk(Mypubkey());
mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript()));
mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'M' << cointxid << refcoin);
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
{
UniValue result(UniValue::VOBJ),pending(UniValue::VARR),obj(UniValue::VOBJ); CTransaction tx; std::string coin; CPubKey mypk,gatewayspk; std::vector<CPubKey> msigpubkeys; uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],signeraddr[64]; int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply; struct CCcontract_info *cp,C;
UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector<CPubKey> msigpubkeys;
uint256 cointxid,hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2;
char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],signeraddr[64];
int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
cp = CCinit(&C,EVAL_GATEWAYS);
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
_GetCCaddress(coinaddr,EVAL_ASSETS,gatewayspk);
_GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
@@ -799,20 +883,23 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
{
queueflag = 1;
break;
}
Getscriptaddress(withmarker,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG);
SetCCunspents(unspentOutputs,withmarker);
}
SetCCunspents(unspentOutputs,coinaddr);
numqueued = 0;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 )
nValue = (int64_t)it->second.satoshis;
fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue);
if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) &&
DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0)
{
Getscriptaddress(destaddr,tx.vout[0].scriptPubKey);
Getscriptaddress(withaddr,tx.vout[1].scriptPubKey);
if ( strcmp(destaddr,coinaddr) == 0 )
{
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid",uint256_str(str,txid)));
CCtxidaddr(txidaddr,txid);
obj.push_back(Pair("txidaddr",txidaddr));
@@ -824,7 +911,6 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
obj.push_back(Pair("depositaddr",depositaddr));
Getscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG);
obj.push_back(Pair("signeraddr",signeraddr));
// numqueued += GatewaysAddQueue(refcoin,txid,tx.vout[1].scriptPubKey,tx.vout[0].nValue);
}
pending.push_back(obj);
}
@@ -836,3 +922,72 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
return(result);
}
UniValue GatewaysMultisig(char *txidaddr)
{
std::string parthex,hex,refcoin; uint256 txid,hashBlock; CTransaction tx; int32_t i,maxK,K,numvouts; CPubKey signerpk;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; UniValue result(UniValue::VOBJ);
SetCCunspents(unspentOutputs,txidaddr);
maxK=0;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if (GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK )
{
maxK=K;
parthex=hex;
}
}
BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx)
{
const CTransaction &txmempool = e.GetTx();
const uint256 &hash = txmempool.GetHash();
if ((numvouts=txmempool.vout.size()) > 0 && DecodeGatewaysPartialOpRet(txmempool.vout[numvouts-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK)
{
maxK=K;
parthex=hex;
}
}
result.push_back(Pair("hex",parthex));
result.push_back(Pair("number_of_signs",maxK));
return (result);
}
std::string GatewaysPartialSign(uint64_t txfee,uint256 txid,std::string refcoin, std::string hex)
{
CMutableTransaction mtx; CScript opret; CPubKey mypk,txidaddrpk,signerpk; struct CCcontract_info *cp,C; CTransaction tx;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; char txidaddr[65];
int32_t maxK,K=0; uint256 tmptxid,parttxid,hashBlock;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 5000;
mypk = pubkey2pk(Mypubkey());
txidaddrpk=CCtxidaddr(txidaddr,txid);
SetCCunspents(unspentOutputs,txidaddr);
maxK=0;
if (unspentOutputs.size()==0)
{
if (AddNormalinputs(mtx,mypk,2*txfee,2)==0) fprintf(stderr,"error adding funds for partialsign\n");
}
else
{
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
tmptxid = it->first.txhash;
if (GetTransaction(tmptxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK )
{
maxK=K;
parttxid=tmptxid;
}
}
if (maxK>0) mtx.vin.push_back(CTxIn(parttxid,0,CScript()));
else fprintf(stderr,"Error finding previous partial tx\n");
}
mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(txidaddrpk)) << OP_CHECKSIG));
opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'P' << maxK+1 << mypk << refcoin << hex);
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}

View File

@@ -13,30 +13,16 @@
* *
******************************************************************************/
#include "CCMofN.h"
#include "CCHeir.h"
/*
The idea of MofN CC is to allow non-interactive multisig, preferably in a cross chain compatible way, ie. for actual bitcoin multisig.
full redeemscript in an initial tx with opreturn
ability to post partial signatures and construct a full transaction from M such partial signatures
a new transaction would refer to the initialtx and other partial would refer to both
There is no need for a CC contract to use it for normal multisig as normal multisig transactions are already supported.
In order to take advantage of CC powers, we can create a more powerful multisig using shamir's secret MofN (up to 255) algo to allow spends. Using the same non-interactive partial signing is possible. also, in addition to spending, data payload can have additional data that is also revealed when the funds are spent.
rpc calls needed:
1) create msig address (normal or shamir)
2) post payment with partial sig
3) add partial sig to 2)
4) combine and submit M partial sigs
The idea of Heir CC is to allow crypto inheritance.
A special 1of2 CC address is created that is freely spendable by the creator. The heir is only allowed to spend after the specified amount of idle blocks. The idea is that if the address doesnt spend any funds for a year (or whatever amount set), then it is time to allow the heir to spend. The design requires the heir to spend all the funds at once
*/
// start of consensus code
int64_t IsMofNvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
int64_t IsHeirvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
{
char destaddr[64];
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
@@ -47,7 +33,7 @@ int64_t IsMofNvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
return(0);
}
bool MofNExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
bool HeirExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
{
static uint256 zerohash;
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
@@ -65,8 +51,8 @@ bool MofNExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &
{
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant MofN from mempool");
if ( (assetoshis= IsMofNvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
return eval->Invalid("cant Heir from mempool");
if ( (assetoshis= IsHeirvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
inputs += assetoshis;
}
}
@@ -74,7 +60,7 @@ bool MofNExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &
for (i=0; i<numvouts; i++)
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsMofNvout(cp,tx,i)) != 0 )
if ( (assetoshis= IsHeirvout(cp,tx,i)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+txfee )
@@ -85,7 +71,7 @@ bool MofNExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &
else return(true);
}
bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return(false);
@@ -105,9 +91,9 @@ bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
}
}
//fprintf(stderr,"check amounts\n");
if ( MofNExactAmounts(cp,eval,tx,1,10000) == false )
if ( HeirExactAmounts(cp,eval,tx,1,10000) == false )
{
fprintf(stderr,"mofnget invalid amount\n");
fprintf(stderr,"Heirget invalid amount\n");
return false;
}
else
@@ -116,8 +102,8 @@ bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
memcpy(hash,&txid,sizeof(hash));
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
fprintf(stderr,"mofnget validated\n");
else fprintf(stderr,"mofnget invalid\n");
fprintf(stderr,"Heirget validated\n");
else fprintf(stderr,"Heirget invalid\n");
return(retval);
}
}
@@ -126,8 +112,9 @@ bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddMofNInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
int64_t AddHeirInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
@@ -139,7 +126,7 @@ int64_t AddMofNInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsMofNvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsHeirvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -154,27 +141,27 @@ int64_t AddMofNInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe
return(totalinputs);
}
std::string MofNGet(uint64_t txfee,int64_t nValue)
std::string HeirGet(uint64_t txfee,int64_t nValue)
{
CMutableTransaction mtx,tmpmtx; CPubKey mypk,mofnpk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
cp = CCinit(&C,EVAL_MOFN);
CMutableTransaction mtx,tmpmtx; CPubKey mypk,Heirpk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
cp = CCinit(&C,EVAL_HEIR);
if ( txfee == 0 )
txfee = 10000;
mofnpk = GetUnspendable(cp,0);
Heirpk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddMofNInputs(cp,mtx,mofnpk,nValue+txfee,60)) > 0 )
if ( (inputs= AddHeirInputs(cp,mtx,Heirpk,nValue+txfee,60)) > 0 )
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_MOFN,CCchange,mofnpk));
mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,CCchange,Heirpk));
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
fprintf(stderr,"start at %u\n",(uint32_t)time(NULL));
j = rand() & 0xfffffff;
for (i=0; i<1000000; i++,j++)
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_MOFN << (uint8_t)'G' << j));
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
{
len >>= 1;
@@ -190,35 +177,35 @@ std::string MofNGet(uint64_t txfee,int64_t nValue)
}
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
return("");
} else fprintf(stderr,"cant find mofn inputs\n");
} else fprintf(stderr,"cant find Heir inputs\n");
return("");
}
std::string MofNFund(uint64_t txfee,int64_t funds)
std::string HeirFund(uint64_t txfee,int64_t funds)
{
CMutableTransaction mtx; CPubKey mypk,mofnpk; CScript opret; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_MOFN);
CMutableTransaction mtx; CPubKey mypk,Heirpk; CScript opret; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_HEIR);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
mofnpk = GetUnspendable(cp,0);
Heirpk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
{
mtx.vout.push_back(MakeCC1vout(EVAL_MOFN,funds,mofnpk));
mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,funds,Heirpk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
return("");
}
UniValue MofNInfo()
UniValue HeirInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx; CPubKey mofnpk; struct CCcontract_info *cp,C; int64_t funding;
CMutableTransaction mtx; CPubKey Heirpk; struct CCcontract_info *cp,C; int64_t funding;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","MofN"));
cp = CCinit(&C,EVAL_MOFN);
mofnpk = GetUnspendable(cp,0);
funding = AddMofNInputs(cp,mtx,mofnpk,0,0);
result.push_back(Pair("name","Heir"));
cp = CCinit(&C,EVAL_HEIR);
Heirpk = GetUnspendable(cp,0);
funding = AddHeirInputs(cp,mtx,Heirpk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
return(result);

View File

@@ -162,6 +162,7 @@ bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
int64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
@@ -291,10 +292,11 @@ std::string LottoCreate(uint64_t txfee,char *planstr,int64_t funding,int32_t tic
sbits = stringbits(planstr);
if ( AddNormalinputs(mtx,mypk,funding+txfee,60) > 0 )
{
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1);
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,funding,lottopk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_LOTTO << (uint8_t)'F' << sbits << ticketsize << odds << firstheight << period << hentropy)));
}
return("");
}
std::string LottoTicket(uint64_t txfee,uint256 lottoid,int64_t numtickets)

View File

@@ -157,7 +157,8 @@ uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint25
{
if ( e == EVAL_ORACLES && f == 'D' )
return(f);
}
//else fprintf(stderr,"DecodeOraclesData evalcode.%d f.%c\n",e,f);
} //else fprintf(stderr,"DecodeOraclesData not enough opereturn data\n");
return(0);
}
@@ -439,6 +440,7 @@ int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
for (i=0; i<n; i++)
fprintf(stderr,"%llu ",(long long)prices[i]);
fprintf(stderr,"-> %llu ht.%d\n",(long long)price,height);
return(price);
}
int64_t OracleCorrelatedPrice(int32_t height,std::vector <int64_t> origprices)
@@ -649,8 +651,12 @@ bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
}
return eval->Invalid("unexpected OraclesValidate 'D' tx invalid");
break;
default:
fprintf(stderr,"illegal oracles funcid.(%c)\n",script[1]);
return eval->Invalid("unexpected OraclesValidate funcid");
break;
}
}
} else return eval->Invalid("unexpected oracles missing funcid");
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
}
return(true);
@@ -665,6 +671,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
//fprintf(stderr,"addoracleinputs from (%s)\n",coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
@@ -803,7 +810,7 @@ std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> da
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data)));
} else fprintf(stderr,"couldnt find enough oracle inputs, limit 1 per utxo\n");
} else fprintf(stderr,"couldnt find enough oracle inputs %s, limit 1 per utxo\n",coinaddr);
} else fprintf(stderr,"couldnt add normal inputs\n");
return("");
}
@@ -852,11 +859,18 @@ UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num)
UniValue OracleInfo(uint256 origtxid)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ);
UniValue result(UniValue::VOBJ),a(UniValue::VARR);
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CMutableTransaction mtx; CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
cp = CCinit(&C,EVAL_ORACLES);
CCtxidaddr(markeraddr,origtxid);
if ( GetTransaction(origtxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find oracleid\n");
result.push_back(Pair("result","error"));
result.push_back(Pair("error","cant find oracleid"));
return(result);
}
if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
{
if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
@@ -875,6 +889,7 @@ UniValue OracleInfo(uint256 origtxid)
{
if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
{
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("publisher",pubkey33_str(str,(uint8_t *)pk.begin())));
Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);

View File

@@ -115,6 +115,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);

View File

@@ -122,6 +122,7 @@ bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);

View File

@@ -28,67 +28,62 @@
Funds work like with dice, ie. there is a Prices plan that traders bet against.
PricesOpen -> oracletxid start with 'L' price, leverage, amount
funds are locked into global CC address
PricesFunding oracletxid, margin, priceaveraging, maxleverage, funding, longtoken, shorttoken, N [pubkeys]
PricesBet -> oracletxid start with 'L', leverage, funding, direction
funds are locked into global CC address
it can be closed at anytime by the trader for cash settlement
the house account can close it if rekt
Implementation Notes:
In order to eliminate the need for worrying about sybil attacks, each prices plan would be able to specific pubkey(s?) for whitelisted publishers. It would be possible to have a non-whitelisted plan that would use 50% correlation between publishers.
delta neutral balancing of risk exposure
delta neutral balancing of riskexposure: fabs(long exposure - short exposure)
bet +B at leverage L
absval(sum(+BLi) - sum(-Bli))
validate: update riskexposure and it needs to be <= funds
PricesProfits: limit withdraw to funds in excess of riskexposure
PricesFinish: payout (if winning) and update riskexposure
need long/short exposure assets
funding -> 1of2 CC global CC address and dealer address, exposure tokens to global 1of2 assets CC address
pricebet -> user funds and exposure token to 1of2 address.
pricewin -> winnings from dealer funds, exposure token back to global address
priceloss -> exposuretoken back to global address
exposure address, funds address
*/
// start of consensus code
int64_t IsPricesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
int64_t PricesOraclePrice(int64_t &rektprice,uint64_t mode,uint256 oracletxid,std::vector<CPubKey>pubkeys,int32_t dir,int64_t amount,int32_t leverage)
{
char destaddr[64];
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
int64_t price;
// howto ensure price when block it confirms it not known
// get price from oracle + current chaintip
// normalize leveraged amount
if ( dir > 0 )
rektprice = price * leverage / (leverage-1);
else rektprice = price * (leverage-1) / leverage;
return(price);
}
bool PricesExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
CScript EncodePricesFundingOpRet(uint8_t funcid,CPubKey planpk,uint256 oracletxid,uint256 longtoken,uint256 shorttoken,int32_t millimargin,uint64_t mode,int32_t maxleverage,std::vector<CPubKey> pubkeys,uint256 bettoken)
{
static uint256 zerohash;
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
numvins = tx.vin.size();
numvouts = tx.vout.size();
for (i=0; i<numvins; i++)
{
//fprintf(stderr,"vini.%d\n",i);
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
{
//fprintf(stderr,"vini.%d check mempool\n",i);
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("cant find vinTx");
else
{
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant Prices from mempool");
if ( (assetoshis= IsPricesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
inputs += assetoshis;
}
}
}
for (i=0; i<numvouts; i++)
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsPricesvout(cp,tx,i)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+txfee )
{
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
return eval->Invalid("mismatched inputs != outputs + txfee");
}
else return(true);
CScript opret;
fprintf(stderr,"implement EncodePricesFundingOpRet\n");
return(opret);
}
uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &oracletxid,uint256 &longtoken,uint256 &shorttoken,int32_t &millimargin,uint64_t &mode,int32_t &maxleverage,std::vector<CPubKey> &pubkeys,uint256 &bettoken)
{
fprintf(stderr,"implement DecodePricesFundingOpRet\n");
return(0);
}
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
@@ -111,12 +106,12 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
}
}
//fprintf(stderr,"check amounts\n");
if ( PricesExactAmounts(cp,eval,tx,1,10000) == false )
//if ( PricesExactAmounts(cp,eval,tx,1,10000) == false )
{
fprintf(stderr,"Pricesget invalid amount\n");
return false;
}
else
//else
{
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
@@ -132,20 +127,21 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char *destaddr,uint256 tolenid,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
// add threshold check
int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
SetCCunspents(unspentOutputs,destaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
// need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && vout < vintx.vout.size() )
{
if ( (nValue= IsPricesvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
// need to verify assetid
if ( (nValue= vintx.vout[vout].nValue) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -160,49 +156,18 @@ int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
return(totalinputs);
}
#ifdef later
UniValue PricesInfo(uint256 pricesid)
{
UniValue result(UniValue::VOBJ); CPubKey pricepk; uint256 hashBlock,oracletxid; CTransaction vintx; int64_t minbet,maxbet,maxodds; uint64_t funding; char numstr[65]; struct CCcontract_info *cp,C;
if ( GetTransaction(pricesid,vintx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
ERR_RESULT("cant find fundingtxid");
return(result);
}
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,oracletxid,minbet,maxbet,maxodds) == 0 )
{
fprintf(stderr,"fundingtxid isnt price creation txid\n");
ERR_RESULT("fundingtxid isnt price creation txid");
return(result);
}
result.push_back(Pair("result","success"));
result.push_back(Pair("pricesid",uint256_str(str,pricesid)));
result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
sprintf(numstr,"%.8f",(double)minbet/COIN);
result.push_back(Pair("minbet",numstr));
sprintf(numstr,"%.8f",(double)maxbet/COIN);
result.push_back(Pair("maxbet",numstr));
result.push_back(Pair("maxodds",maxodds));
cp = CCinit(&C,EVAL_PRICES);
pricepk = GetUnspendable(cp,0);
funding = PricePlanFunds(cp,pricepk,pricesid);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
return(result);
}
UniValue PricesList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction vintx; int64_t minbet,maxbet,maxodds; char str[65];
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint64_t mode; int32_t margin,maxleverage; std::vector<CPubKey>pubkeys; uint256 txid,hashBlock,oracletxid,longtoken,shorttoken,bettoken; CPubKey planpk,pricespk; char str[65]; CTransaction vintx;
cp = CCinit(&C,EVAL_PRICES);
pricespk = GetUnspendable(cp,0);
SetCCtxids(addressIndex,cp->normaladdr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,oracletxid,minbet,maxbet,maxodds) != 0 )
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' )
{
result.push_back(uint256_str(str,txid));
}
@@ -211,59 +176,161 @@ UniValue PricesList()
return(result);
}
std::string PricesCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
// longtoken satoshis limits long exposure
// shorttoken satoshis limits short exposure
// both must be in the 1of2 CC address with its total supply
// bettoken
std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector<CPubKey> pubkeys)
{
CMutableTransaction mtx; uint256 zero; CScript fundingPubKey; CPubKey mypk,pricepk; int64_t a,b,c,d; uint64_t sbits; struct CCcontract_info *cp,C;
if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || maxodds > 9999 || timeoutblocks < 0 || timeoutblocks > 1440 )
CMutableTransaction mtx; CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C;
if ( funding < 100*COIN || maxleverage <= 0 || maxleverage > 10000 )
{
CCerror = "invalid parameter error";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( funds < 100*COIN )
cp = CCinit(&C,EVAL_PRICES);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
if ( (N= (int32_t)pubkeys.size()) || N > 15 )
{
CCerror = "price plan needs at least 100 coins";
fprintf(stderr,"%s\n", CCerror.c_str() );
fprintf(stderr,"too many pubkeys N.%d\n",N);
return("");
}
memset(&zero,0,sizeof(zero));
if ( (cp= Pricesinit(fundingPubKey,zero,&C,planstr,txfee,mypk,pricepk,sbits,a,b,c,d)) == 0 )
for (i=0; i<N; i++)
{
CCerror = "Priceinit error in create funding";
fprintf(stderr,"%s\n", CCerror.c_str() );
Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
if ( CCaddress_balance(coinaddr) == 0 )
{
fprintf(stderr,"N.%d but pubkeys[%d] has no balance\n",N,i);
return("");
}
}
if ( GetCCaddress1of2(cp,houseaddr,pricespk,mypk) == 0 )
{
fprintf(stderr,"PricesCreateFunding cant create globaladdr\n");
return("");
}
if ( AddNormalinputs(mtx,mypk,funds+3*txfee,60) > 0 )
if ( CCtoken_balance(houseaddr,longtoken) != CCfullsupply(longtoken) )
{
fprintf(stderr,"PricesCreateFunding (%s) globaladdr.%s token balance %.8f != %.8f\n",uint256_str(str,longtoken),houseaddr,(double)CCtoken_balance(houseaddr,longtoken)/COIN,(double)CCfullsupply(longtoken)/COIN);
return("");
}
if ( CCtoken_balance(houseaddr,shorttoken) != CCfullsupply(shorttoken) )
{
fprintf(stderr,"PricesCreateFunding (%s) globaladdr.%s token balance %.8f != %.8f\n",uint256_str(str,longtoken),houseaddr,(double)CCtoken_balance(houseaddr,longtoken)/COIN,(double)CCfullsupply(shorttoken)/COIN);
return("");
}
if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
return("");
}
fprintf(stderr,"error check bettoken\n");
if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,pricepk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricepk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',sbits,minbet,maxbet,maxodds,timeoutblocks)));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',mypk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken)));
}
else
{
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
std::string PricesAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
UniValue PricesInfo(uint256 fundingtxid)
{
CMutableTransaction mtx; CScript fundingPubKey,scriptPubKey; CPubKey mypk,pricepk; struct CCcontract_info *cp,C; int64_t minbet,maxbet,maxodds;
if ( amount < 0 )
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CPubKey pricespk,planpk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction vintx; int64_t balance,supply,exposure; uint64_t funding,mode; int32_t i,margin,maxleverage; char numstr[65],houseaddr[64],exposureaddr[64],str[65]; std::vector<CPubKey>pubkeys; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_PRICES);
pricespk = GetUnspendable(cp,0);
if ( GetTransaction(fundingtxid,vintx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
ERR_RESULT("cant find fundingtxid");
return(result);
}
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("fundingtxid",uint256_str(str,fundingtxid)));
result.push_back(Pair("bettoken",uint256_str(str,bettoken)));
result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
sprintf(numstr,"%.3f",(double)margin/1000);
result.push_back(Pair("profitmargin",numstr));
result.push_back(Pair("maxleverage",maxleverage));
result.push_back(Pair("mode",(int64_t)mode));
for (i=0; i<pubkeys.size(); i++)
a.push_back(pubkey33_str(str,(uint8_t *)&pubkeys[i]));
result.push_back(Pair("pubkeys",a));
GetCCaddress1of2(cp,houseaddr,pricespk,planpk);
GetCCaddress1of2(cp,exposureaddr,pricespk,pricespk); // assets addr
result.push_back(Pair("houseaddr",houseaddr));
result.push_back(Pair("betaddr",exposureaddr));
result.push_back(Pair("longtoken",uint256_str(str,longtoken)));
supply = CCfullsupply(longtoken);
result.push_back(Pair("longsupply",supply));
balance = CCtoken_balance(houseaddr,longtoken);
result.push_back(Pair("longavail",balance));
exposure = CCtoken_balance(exposureaddr,longtoken);
result.push_back(Pair("longexposure",exposure));
result.push_back(Pair("shorttoken",uint256_str(str,shorttoken)));
supply = CCfullsupply(shorttoken);
result.push_back(Pair("shortsupply",supply));
balance = CCtoken_balance(houseaddr,shorttoken);
result.push_back(Pair("shortavail",balance));
exposure = CCtoken_balance(exposureaddr,shorttoken);
result.push_back(Pair("shortexposure",exposure));
sprintf(numstr,"%.8f",(double)CCtoken_balance(houseaddr,bettoken)/COIN);
result.push_back(Pair("funds",numstr));
}
return(result);
}
std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount)
{
CMutableTransaction mtx; struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,CCchange = 0; uint64_t funding,mode; int32_t margin,maxleverage; char houseaddr[64],myaddr[64]; std::vector<CPubKey>pubkeys;
if ( amount < 10000 )
{
CCerror = "amount must be positive";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( (cp= Pricesinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,pricepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
return("");
scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
if ( scriptPubKey == fundingPubKey )
cp = CCinit(&C,EVAL_PRICES);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(cp,myaddr,mypk);
if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 )
{
if ( AddNormalinputs(mtx,mypk,amount+2*txfee,60) > 0 )
fprintf(stderr,"cant find fundingtxid\n");
return("");
}
if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken )
{
GetCCaddress1of2(cp,houseaddr,pricespk,planpk);
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,pricepk));
mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesOpRet('E',sbits,fundingtxid,hentropy,zeroid)));
if ( (inputs= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,60)) >= amount )
{
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(planpk)) << OP_CHECKSIG));
if ( inputs > amount+txfee )
CCchange = (inputs - amount);
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
// add addr2
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',bettoken,zeroid,0,Mypubkey())));
}
else
{
CCerror = "cant find enough bet inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
else
{
@@ -271,66 +338,106 @@ std::string PricesAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,in
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
else
{
CCerror = "only fund creator can add more funds (entropy)";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
return("");
}
std::string PricesBet(uint64_t txfee,uint256 pricesid,int64_t bet,int32_t odds)
std::string PricesBet(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount,int32_t leverage)
{
CMutableTransaction mtx; CScript fundingPubKey; CPubKey mypk,pricepk; int64_t funding,minbet,maxbet,maxodds; struct CCcontract_info *cp,C;
if ( bet < 0 )
CMutableTransaction mtx; struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vector<CPubKey>pubkeys;
if ( amount < 0 )
{
CCerror = "bet must be positive";
fprintf(stderr,"%s\n", CCerror.c_str() );
amount = -amount;
dir = -1;
} else dir = 1;
cp = CCinit(&C,EVAL_PRICES);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(cp,myaddr,mypk);
if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
return("");
}
if ( odds < 1 || odds > 9999 )
if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken )
{
CCerror = "odds must be between 1 and 9999";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( (cp= Pricesinit(fundingPubKey,pricesid,&C,txfee,mypk,pricepk,minbet,maxbet,maxodds)) == 0 )
return("");
if ( bet < minbet || bet > maxbet || odds > maxodds )
{
CCerror = strprintf("Price plan %s illegal bet %.8f: minbet %.8f maxbet %.8f or odds %d vs max.%d\n",planstr,(double)bet/COIN,(double)minbet/COIN,(double)maxbet/COIN,(int32_t)odds,(int32_t)maxodds);
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( (funding= PricesPlanFunds(cp,pricepk,pricesid)) >= 2*bet*odds+txfee )
{
if ( myIsutxo_spentinmempool(entropytxid,0) != 0 )
if ( leverage > maxleverage || leverage < 1 )
{
CCerror = "entropy txid is spent";
fprintf(stderr,"%s\n", CCerror.c_str() );
fprintf(stderr,"illegal leverage\n");
return("");
}
if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 )
GetCCaddress1of2(cp,houseaddr,pricespk,planpk);
GetCCaddress1of2(cp,exposureaddr,pricespk,pricespk);
if ( dir < 0 )
tokenid = shorttoken;
else tokenid = longtoken;
exposure = leverage * amount;
longexposure = CCtoken_balance(exposureaddr,longtoken);
shortexposure = CCtoken_balance(exposureaddr,shorttoken);
netexposure = (longexposure - shortexposure + exposure*dir);
if ( netexposure < 0 )
netexposure = -netexposure;
balance = CCtoken_balance(myaddr,bettoken) / COIN;
if ( balance < netexposure*9/10 ) // 10% extra room for dynamically closed bets in wrong direction
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,pricepk));
mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,pricepk));
mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesOpRet('B',pricesid)));
} else fprintf(stderr,"cant find enough normal inputs for %.8f, plan funding %.8f\n",(double)bet/COIN,(double)funding/COIN);
fprintf(stderr,"balance %lld < 90%% netexposure %lld, refuse bet\n",(long long)balance,(long long)netexposure);
return("");
}
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
{
if ( (inputs= AddTokensInputs(cp,mtx,houseaddr,tokenid,exposure,30)) >= exposure )
{
if ( (inputs2= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,30)) >= amount )
{
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk));
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,exposure,pricespk,pricespk));
if ( inputs > exposure+txfee )
CCchange = (inputs - exposure);
if ( inputs2 > amount+txfee )
CCchange2 = (inputs2 - amount);
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,CCchange,pricespk,planpk));
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange2,mypk));
// add addr2 and addr3
//return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesExtra('T',tokenid,bettoken,zeroid,dir*leverage)));
CScript opret;
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
else
{
fprintf(stderr,"cant find enough bettoken inputs\n");
return("");
}
}
else
{
fprintf(stderr,"cant find enough exposure inputs\n");
return("");
}
}
else
{
CCerror = "cant find enough inputsB";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
if ( entropyval == 0 && funding != 0 )
CCerror = "cant find price entropy inputs";
else CCerror = "cant find price input";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
std::string PricesBetFinish(int32_t *resultp,uint64_t txfee,uint256 pricesid,uint256 bettxid)
UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid)
{
UniValue result(UniValue::VOBJ);
// get height of bettxid
// get price and rekt
// get current height and price
// what about if rekt in the past?
return(result);
}
std::string PricesFinish(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid)
{
*resultp = -1;
CCerror = "couldnt find bettx or entropytx";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
#endif

View File

@@ -287,8 +287,12 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
return eval->Invalid("unlock tx vout.2 isnt 0");
preventCCvouts = 1;
break;
default:
fprintf(stderr,"illegal rewards funcid.(%c)\n",funcid);
return eval->Invalid("unexpected rewards funcid");
break;
}
}
} else return eval->Invalid("unexpected rewards missing funcid");
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
}
return(true);
@@ -325,15 +329,16 @@ static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t r
// 'L' vs 'F' and 'A'
int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs,uint64_t refsbits,uint256 reffundingtxid)
{
char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t numblocks,j,vout,n = 0; uint8_t funcid;
char coinaddr[64],str[65]; uint64_t threshold,sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t numblocks,j,vout,n = 0; uint8_t funcid;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/maxinputs;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < 1000000 )
if ( it->second.satoshis < threshold )
continue;
//fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
for (j=0; j<mtx.vin.size(); j++)

View File

@@ -114,6 +114,7 @@ bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
int64_t AddTriggersInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);

View File

@@ -82,7 +82,6 @@ extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
extern uint32_t ASSETCHAIN_INIT, ASSETCHAINS_MAGIC;
extern int32_t VERUS_BLOCK_POSUNITS, ASSETCHAINS_LWMAPOS, ASSETCHAINS_SAPLING, ASSETCHAINS_OVERWINTER;
extern uint64_t ASSETCHAINS_SUPPLY, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH;
extern std::string VERUS_CHEATCATCHER;
const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));

View File

@@ -1,177 +0,0 @@
/********************************************************************
* (C) 2018 Michael Toutonghi
*
* Distributed under the MIT software license, see the accompanying
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
*
* This supports code to catch nothing at stake cheaters who stake
* on multiple forks.
*
*/
#include "cc/StakeGuard.h"
#include "script/script.h"
#include "main.h"
#include "hash.h"
#include "cheatcatcher.h"
#include "streams.h"
using namespace std;
CCheatList cheatList;
boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
uint32_t CCheatList::Prune(uint32_t height)
{
uint32_t count = 0;
pair<multimap<const uint32_t, CTxHolder>::iterator, multimap<const uint32_t, CTxHolder>::iterator> range;
vector<CTxHolder *> toPrune;
if (height > 0 && NetworkUpgradeActive(height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING))
{
LOCK(cs_cheat);
for (auto it = orderedCheatCandidates.begin(); it != orderedCheatCandidates.end() && it->second.height <= height; it--)
{
toPrune.push_back(&it->second);
}
count = toPrune.size();
for (auto ptxHolder : toPrune)
{
Remove(*ptxHolder);
}
}
return count; // return how many removed
}
bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
bool CCheatList::IsHeightOrGreaterInList(uint32_t height)
{
auto range = orderedCheatCandidates.equal_range(height);
//printf("IsHeightOrGreaterInList: %s\n", range.second == orderedCheatCandidates.end() ? "false" : "true");
return (range.first != orderedCheatCandidates.end() || range.second != orderedCheatCandidates.end());
}
bool CCheatList::IsCheatInList(const CTransaction &tx, CTransaction *cheatTx)
{
// for a tx to be cheat, it needs to spend the same UTXO and be for a different prior block
// the list should be pruned before this call
// we return the first valid cheat we find
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
hw << tx.vin[0].prevout.hash;
hw << tx.vin[0].prevout.n;
uint256 utxo = hw.GetHash();
pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
CStakeParams p, s;
if (GetStakeParams(tx, p))
{
LOCK(cs_cheat);
range = indexedCheatCandidates.equal_range(utxo);
//printf("IsCheatInList - found candidates: %s\n", range.first == range.second ? "false" : "true");
for (auto it = range.first; it != range.second; it++)
{
CTransaction &cTx = it->second->tx;
//printf("cTx::opret : %s\n", cTx.vout[1].scriptPubKey.ToString().c_str());
// need both parameters to check
if (GetStakeParams(cTx, s))
{
if (p.prevHash != s.prevHash && s.blkHeight >= p.blkHeight)
{
*cheatTx = cTx;
return true;
}
}
}
}
return false;
}
bool CCheatList::IsUTXOInList(COutPoint _utxo, uint32_t height)
{
// for a tx to be cheat, it needs to spend the same UTXO and be for a different prior block
// the list should be pruned before this call
// we return the first valid cheat we find
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
hw << _utxo.hash;
hw << _utxo.n;
uint256 utxo = hw.GetHash();
pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
CStakeParams p, s;
LOCK(cs_cheat);
range = indexedCheatCandidates.equal_range(utxo);
for (auto it = range.first; it != range.second; it++)
{
CTransaction &cTx = it->second->tx;
//printf("cTx::opret : %s\n", cTx.vout[1].scriptPubKey.ToString().c_str());
// need both parameters to check
if (GetStakeParams(cTx, s))
{
if (s.blkHeight >= height)
{
return true;
}
}
}
return false;
}
bool CCheatList::Add(const CTxHolder &txh)
{
if (NetworkUpgradeActive(txh.height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING))
{
LOCK(cs_cheat);
auto it = orderedCheatCandidates.insert(pair<const uint32_t, CTxHolder>(txh.height, txh));
indexedCheatCandidates.insert(pair<const uint256, CTxHolder *>(txh.utxo, &it->second));
//printf("CCheatList::Add orderedCheatCandidates.size: %d, indexedCheatCandidates.size: %d\n", (int)orderedCheatCandidates.size(), (int)indexedCheatCandidates.size());
}
}
void CCheatList::Remove(const CTxHolder &txh)
{
// first narrow by source tx, then compare with tx hash
uint32_t count;
pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
vector<multimap<const uint256, CTxHolder *>::iterator> utxoPrune;
vector<multimap<const int32_t, CTxHolder>::iterator> heightPrune;
{
LOCK(cs_cheat);
range = indexedCheatCandidates.equal_range(txh.utxo);
for (auto it = range.first; it != range.second; it++)
{
uint256 hash = txh.tx.GetHash();
if (hash == it->second->tx.GetHash())
{
auto hrange = orderedCheatCandidates.equal_range(it->second->height);
for (auto hit = hrange.first; hit != hrange.second; hit++)
{
if (hit->second.tx.GetHash() == hash)
{
// add and remove them together
utxoPrune.push_back(it);
heightPrune.push_back(hit);
}
}
}
}
for (auto it : utxoPrune)
{
indexedCheatCandidates.erase(it);
}
for (auto it : heightPrune)
{
orderedCheatCandidates.erase(it);
}
}
}

View File

@@ -1,81 +0,0 @@
/********************************************************************
* (C) 2018 Michael Toutonghi
*
* Distributed under the MIT software license, see the accompanying
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
*
* This supports code to catch nothing at stake cheaters who stake
* on multiple forks.
*
*/
#ifndef CHEATCATCHER_H
#define CHEATCATCHER_H
#include <vector>
#include "streams.h"
#include "primitives/transaction.h"
#include "script/script.h"
#include "uint256.h"
#include <vector>
#include <map>
class CTxHolder
{
public:
uint256 utxo;
uint32_t height;
CTransaction tx;
CTxHolder(const CTransaction &_tx, uint32_t _height) : height(_height), tx(_tx) {
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
hw << tx.vin[0].prevout.hash;
hw << tx.vin[0].prevout.n;
utxo = hw.GetHash();
}
CTxHolder& operator=(const CTxHolder& txh)
{
utxo = txh.utxo;
height = txh.height;
tx = txh.tx;
}
};
class CCheatList
{
private:
std::multimap<const int32_t, CTxHolder> orderedCheatCandidates;
std::multimap<const uint256, CTxHolder *> indexedCheatCandidates;
CCriticalSection cs_cheat;
public:
CCheatList() {}
// prune all transactions in the list below height
uint32_t Prune(uint32_t height);
// check to see if a transaction that could be a cheat for the passed transaction is in our list
bool IsCheatInList(const CTransaction &tx, CTransaction *pcheatTx);
// checks if the out point is in the list
bool IsUTXOInList(COutPoint _utxo, uint32_t height);
// check to see if there are cheat candidates of the same or greater block height in list
bool IsHeightOrGreaterInList(uint32_t height);
// add a potential cheat transaction to the list. we do this for all stake transactions from orphaned stakes
bool Add(const CTxHolder &txh);
// remove a transaction from the the list
void Remove(const CTxHolder &txh);
};
extern CCheatList cheatList;
extern boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
#endif

View File

@@ -1,42 +0,0 @@
#!/bin/bash
set -x
source pubkey.txt
echo $pubkey
sleep 3
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"REVS\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"SUPERNET\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"DEX\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"PANGEA\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"JUMBLR\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"BET\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CRYPTO\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"HODL\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"MSHARK\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"BOTS\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"MGW\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"COQUI\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"WLC\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"KV\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CEAL\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"MESH\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"MNZ\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"AXO\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"ETOMIC\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"BTCH\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CHAIN\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"NINJA\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"OOT\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"BNTN\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"PRLPAY\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"DSEC\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"GLXT\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"EQL\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"ZILLA\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CHIPS\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"GAME\",\"freq\":5,\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"RFOX\",\"freq\":10,\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"VRSC\",\"freq\":10,\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"SEC\",\"pubkey\":\"$pubkey\"}"
curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CCL\",\"pubkey\":\"$pubkey\"}"

2
src/fiat/mgnx Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=MGNX $1 $2 $3 $4 $5 $6

2
src/fiat/pgt Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=PGT $1 $2 $3 $4 $5 $6

2
src/fiat/pirate Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=PIRATE $1 $2 $3 $4 $5 $6

View File

@@ -76,7 +76,6 @@ using namespace std;
extern void ThreadSendAlert();
extern int32_t KOMODO_LOADINGBLOCKS;
extern bool VERUS_MINTBLOCKS;
extern std::string VERUS_CHEATCATCHER;
ZCJoinSplit* pzcashParams = NULL;
@@ -1869,8 +1868,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
StartNode(threadGroup, scheduler);
VERUS_CHEATCATCHER = GetArg("-cheatcatcher", "");
#ifdef ENABLE_MINING
// Generate coins in the background
#ifdef ENABLE_WALLET

View File

@@ -40,7 +40,6 @@ uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256
static bool fCreateBlank;
static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
//
// This function returns either one of EXIT_ codes when it's expected to stop the process or

View File

@@ -112,7 +112,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char
errs++;
if ( fread(&MoMdepth,1,sizeof(MoMdepth),fp) != sizeof(MoMdepth) )
errs++;
if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
printf("%s load[%s.%d -> %s] NOTARIZED %d %s MoM.%s %d CCid.%u\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str(),MoM.ToString().c_str(),MoMdepth&0xffff,(MoMdepth>>16)&0xffff);
}
else
@@ -257,7 +257,7 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long
errs++;
if ( memread(&MoMdepth,sizeof(MoMdepth),filedata,&fpos,datalen) != sizeof(MoMdepth) )
errs++;
if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
printf("%s load[%s.%d -> %s] NOTARIZED %d %s MoM.%s %d CCid.%u\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str(),MoM.ToString().c_str(),MoMdepth&0xffff,(MoMdepth>>16)&0xffff);
}
else
@@ -851,7 +851,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
printf("%02x",scriptPubKey[k]);
printf(" scriptPubKey doesnt match any notary vini.%d of %d\n",j,numvins);
}
} else printf("cant get scriptPubKey for ht.%d txi.%d vin.%d\n",height,i,j);
} //else printf("cant get scriptPubKey for ht.%d txi.%d vin.%d\n",height,i,j);
}
numvalid = bitweight(signedmask);
if ( (((height < 90000 || (signedmask & 1) != 0) && numvalid >= KOMODO_MINRATIFY) ||

View File

@@ -389,7 +389,7 @@ int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heig
{
if ( (item= jobj(json,(char *)"result")) != 0 )
{
txid_confirmations = jint(item,(char *)"confirmations");
txid_confirmations = jint(item,(char *)"rawconfirmations");
if ( txid_confirmations > 0 && height > txid_confirmations )
txid_height = height - txid_confirmations;
else txid_height = height;
@@ -1099,18 +1099,33 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_
PoS stake must be without txfee and in the last tx in the block at vout[0]
*/
uint64_t komodo_commission(const CBlock *pblock)
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
uint64_t komodo_commission(const CBlock *pblock,int32_t height)
{
int32_t i,j,n=0,txn_count; uint64_t commission,total = 0;
int32_t i,j,n=0,txn_count; int64_t nSubsidy; uint64_t commission,total = 0;
txn_count = pblock->vtx.size();
for (i=0; i<txn_count; i++)
if ( ASSETCHAINS_FOUNDERS != 0 )
{
n = pblock->vtx[i].vout.size();
nSubsidy = GetBlockSubsidy(height,Params().GetConsensus());
fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION));
return((nSubsidy * ASSETCHAINS_COMMISSION) / COIN);
n = pblock->vtx[0].vout.size();
for (j=0; j<n; j++)
if ( j != 1 )
total += pblock->vtx[0].vout[j].nValue;
}
else
{
for (i=0; i<txn_count; i++)
{
//fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
if ( i != 0 || j != 1 )
total += pblock->vtx[i].vout[j].nValue;
n = pblock->vtx[i].vout.size();
for (j=0; j<n; j++)
{
//fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
if ( i != 0 || j != 1 )
total += pblock->vtx[i].vout[j].nValue;
}
}
}
//fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN));
@@ -1157,7 +1172,7 @@ int8_t komodo_segid(int32_t nocache,int32_t height)
return(segid);
}
int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
{
static uint8_t prevhashbuf[100]; static int32_t prevheight;
int32_t i;
@@ -1277,7 +1292,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh
arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc)
{
int32_t oldflag = 0;
int32_t oldflag = 0,dispflag = 0;
CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val;
*percPoSp = percPoS = 0;
if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
@@ -1296,23 +1311,23 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he
{
n++;
percPoS++;
if ( ASSETCHAINS_STAKED < 100 )
if ( dispflag != 0 && ASSETCHAINS_STAKED < 100 )
fprintf(stderr,"0");
}
else
{
if ( ASSETCHAINS_STAKED < 100 )
if ( dispflag != 0 && ASSETCHAINS_STAKED < 100 )
fprintf(stderr,"1");
sum += UintToArith256(pindex->GetBlockHash());
m++;
}
}
if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
if ( dispflag != 0 && ASSETCHAINS_STAKED < 100 && (i % 10) == 9 )
fprintf(stderr," %d, ",percPoS);
}
if ( m+n < 100 )
percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100;
if ( ASSETCHAINS_STAKED < 100 )
if ( dispflag != 0 && ASSETCHAINS_STAKED < 100 )
fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height);
*percPoSp = percPoS;
if ( m > 0 )
@@ -1325,12 +1340,10 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he
percPoS = 1;
if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget
{
//if ( oldflag != 0 )
// bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
if ( oldflag != 0 )
bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
else bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
if ( ASSETCHAINS_STAKED < 100 )
if ( dispflag != 0 && ASSETCHAINS_STAKED < 100 )
{
for (i=31; i>=24; i--)
fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
@@ -1348,7 +1361,6 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he
if ( oldflag != 0 )
{
bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc);
//bnTarget = (bnTarget * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc);
bnTarget = (bnTarget / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
}
else bnTarget = (ave / arith_uint256(goalperc * goalperc)) * arith_uint256(percPoS * percPoS * percPoS);
@@ -1360,7 +1372,7 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he
if ( bnTarget < ave )
bnTarget = ave;
}
if ( 1 )
if ( dispflag != 0 )
{
for (i=31; i>=24; i--)
fprintf(stderr,"%02x",((uint8_t *)&ave)[i]);
@@ -1446,7 +1458,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED);
if ( bhash < bnTarget )
{
fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
//fprintf(stderr,"ht.%d isPoS but meets PoW diff!\n",height);
isPoS = 0;
}
}
@@ -1459,7 +1471,6 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating);
bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig = true);
// for now, we will ignore slowFlag in the interest of keeping success/fail simpler for security purposes
bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
@@ -1496,11 +1507,10 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
{
bool validHash = (value != 0);
bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
bool newPOSEnforcement = enablePOSNonce && (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
uint256 rawHash;
arith_uint256 posHash;
if (validHash && newPOSEnforcement)
if (validHash && enablePOSNonce)
{
validHash = pblock->GetRawVerusPOSHash(rawHash, height);
posHash = UintToArith256(rawHash) / value;
@@ -1510,29 +1520,6 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
printf("ERROR: invalid nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n",
pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
}
// make sure prev block hash and block height are correct
CStakeParams p;
if (validHash && (validHash = GetStakeParams(pblock->vtx[txn_count-1], p)))
{
for (int i = 0; validHash && i < pblock->vtx[0].vout.size(); i++)
{
validHash = false;
if (ValidateMatchingStake(pblock->vtx[0], i, pblock->vtx[txn_count-1], validHash) && !validHash)
{
if ((p.prevHash == pblock->hashPrevBlock) && (int32_t)p.blkHeight == height)
{
validHash = true;
}
else
{
printf("ERROR: invalid block data for stake tx\nblkHash: %s\ntxBlkHash: %s\nblkHeight: %d, txBlkHeight: %d\n",
pblock->hashPrevBlock.GetHex().c_str(), p.prevHash.GetHex().c_str(), height, p.blkHeight);
validHash = false;
}
}
else validHash = false;
}
}
}
if (validHash)
{
@@ -1573,7 +1560,7 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
//printf("after nNonce: %s, height: %d\n", nonce.GetHex().c_str(), height);
//printf("POShash: %s\n\n", hash.GetHex().c_str());
if ((!newPOSEnforcement || posHash == hash) && hash <= target)
if (posHash == hash && hash <= target)
{
BlockMap::const_iterator it = mapBlockIndex.find(blkHash);
if ((it == mapBlockIndex.end()) ||
@@ -1616,48 +1603,30 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
}
}
if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) )
{
strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
if (newPOSEnforcement)
{
if (!strcmp(destaddr, voutaddr))
{
// allow delegation of stake, but require all ouputs to be
// crypto conditions
CStakeParams p;
// validatestake transaction sets the pubkey of the stake output
// if it has no override into the pubkey
if (ValidateStakeTransaction(pblock->vtx[txn_count-1], p, false))
{
COptCCParams cpp;
// loop through all outputs to make sure they are sent to the proper pubkey
isPOS = true;
for (auto vout : pblock->vtx[0].vout)
{
txnouttype tp;
std::vector<std::vector<unsigned char>> vvch = std::vector<std::vector<unsigned char>>();
// solve all outputs to check that destinations all go only to the pk
// specified in the stake params
if (!Solver(vout.scriptPubKey, tp, vvch) ||
tp != TX_CRYPTOCONDITION ||
vvch.size() < 2 ||
p.pk != CPubKey(vvch[1]))
{
isPOS = false;
break;
}
}
}
}
}
else if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
if ( !strcmp(destaddr,voutaddr) )
{
isPOS = true;
CTransaction &cbtx = pblock->vtx[0];
for (int i = 0; i < cbtx.vout.size(); i++)
{
if (CScriptExt::ExtractVoutDestination(cbtx, i, cbaddress))
{
strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
if (!strcmp(destaddr,cbaddr))
continue;
}
else
{
if (cbtx.vout[i].scriptPubKey.IsOpReturn())
continue;
isPOS = false;
break;
}
}
}
else
{
@@ -1681,17 +1650,39 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
{
int64_t checktoshis=0; uint8_t *script;
int64_t checktoshis=0; uint8_t *script,scripthex[8192]; int32_t scriptlen,matched = 0;
if ( ASSETCHAINS_COMMISSION != 0 )
{
checktoshis = komodo_commission(pblock);
if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 )
checktoshis = komodo_commission(pblock,height);
fprintf(stderr,"height.%d commission %.8f\n",height,(double)checktoshis/COIN);
/*if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 ) jl777: not sure why this was here
return(-1);
else if ( checktoshis != 0 )
else*/ if ( checktoshis != 0 )
{
script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
scriptlen = (int32_t)pblock->vtx[0].vout[1].scriptPubKey.size();
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
{
if ( ASSETCHAINS_SCRIPTPUB.size()/2 == scriptlen && scriptlen < sizeof(scripthex) )
{
decode_hex(scripthex,scriptlen,(char *)ASSETCHAINS_SCRIPTPUB.c_str());
if ( memcmp(scripthex,script,scriptlen) == 0 )
matched = scriptlen;
}
}
else if ( scriptlen == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) == 0 )
matched = 35;
else if ( scriptlen == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG && memcmp(script+3,ASSETCHAINS_OVERRIDE_PUBKEYHASH,20) == 0 )
matched = 25;
if ( matched == 0 )
{
int32_t i;
for (i=0; i<25; i++)
fprintf(stderr,"%02x",script[i]);
fprintf(stderr," payment to wrong pubkey scriptlen.%d, scriptpub[%d]\n",scriptlen,(int32_t)ASSETCHAINS_SCRIPTPUB.size()/2);
return(-1);
}
if ( pblock->vtx[0].vout[1].nValue != checktoshis )
{
fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue));

View File

@@ -10,5 +10,8 @@
#define IGUANA_MAXSCRIPTSIZE 10001
#define KOMODO_MAXMEMPOOLTIME 3600 // affects consensus
#define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9"
#define KOMODO_FIRSTFUNGIBLEID 100
extern uint8_t ASSETCHAINS_TXPOW;
#endif

View File

@@ -1382,8 +1382,9 @@ void komodo_passport_iteration()
}
if ( komodo_chainactive_timestamp() > lastinterest )
{
komodo_interestsum();
komodo_longestchain();
if ( ASSETCHAINS_SYMBOL[0] == 0 )
komodo_interestsum();
//komodo_longestchain();
lastinterest = komodo_chainactive_timestamp();
}
refsp = komodo_stateptr(symbol,dest);

View File

@@ -29,6 +29,7 @@ uint64_t komodo_paxtotal();
int32_t komodo_longestchain();
uint64_t komodo_maxallowed(int32_t baseid);
int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max);
bool pubkey2addr(char *destaddr,uint8_t *pubkey33);
pthread_mutex_t komodo_mutex;
@@ -46,13 +47,13 @@ int COINBASE_MATURITY = _COINBASE_MATURITY;//100;
int32_t KOMODO_MININGTHREADS = 0,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,KOMODO_CONNECTING = -1;
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1;
std::string VERUS_CHEATCATCHER, NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY;
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE;
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB;
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,ASSETCHAINS_FOUNDERS;
bool VERUS_MINTBLOCKS;
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096];
uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT;
uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT,KOMODO_DPOWCONFS = 1;
uint32_t ASSETCHAINS_MAGIC = 2387029918;
int64_t ASSETCHAINS_GENESISTXVAL = 5000000000;
@@ -94,7 +95,7 @@ uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10;
uint32_t KOMODO_INITDONE;
char KMDUSERPASS[8192],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771;
char KMDUSERPASS[8192+512+1],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771;
uint64_t PENDING_KOMODO_TX;
extern int32_t KOMODO_LOADINGBLOCKS;
unsigned int MAX_BLOCK_SIGOPS = 20000;

View File

@@ -117,7 +117,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value)
}
valueptr = &key[keylen];
fee = komodo_kvfee(flags,opretlen,keylen);
//printf("fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]);
//fprintf(stderr,"fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]);
if ( value >= fee )
{
coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(keylen)+sizeof(valuesize)+keylen+valuesize+1);

View File

@@ -197,6 +197,7 @@ const char *Notaries_elected1[][2] =
{"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" },
{"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" },
};
#define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9"
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp)
{
@@ -451,6 +452,21 @@ int32_t komodo_notarized_height(int32_t *prevMoMheightp,uint256 *hashp,uint256 *
}
}
int32_t komodo_dpowconfs(int32_t txheight,int32_t numconfs)
{
char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
if ( KOMODO_DPOWCONFS != 0 && txheight > 0 && numconfs > 0 && (sp= komodo_stateptr(symbol,dest)) != 0 )
{
if ( sp->NOTARIZED_HEIGHT > 0 )
{
if ( txheight < sp->NOTARIZED_HEIGHT )
return(numconfs);
else return(1);
}
}
return(numconfs);
}
int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip)
{
struct notarized_checkpoint *np = 0;

View File

@@ -1645,12 +1645,11 @@ uint64_t komodo_ac_block_subsidy(int nHeight)
}
extern int64_t MAX_MONEY;
extern std::string VERUS_CHEATCATCHER;
void komodo_args(char *argv0)
{
extern const char *Notaries_elected1[][2];
std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[256],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,baseid,len,n,extralen = 0;
std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,baseid,len,n,extralen = 0;
IS_KOMODO_NOTARY = GetBoolArg("-notary", false);
if ( GetBoolArg("-gen", false) != 0 )\
@@ -1762,9 +1761,12 @@ void komodo_args(char *argv0)
}
MAX_BLOCK_SIGOPS = 60000;
ASSETCHAINS_TXPOW = GetArg("-ac_txpow",0) & 3;
ASSETCHAINS_FOUNDERS = GetArg("-ac_founders",0) & 1;
ASSETCHAINS_SUPPLY = GetArg("-ac_supply",10);
ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0);
ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey","");
ASSETCHAINS_SCRIPTPUB = GetArg("-ac_script","");
if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 )
ASSETCHAINS_STAKED = 100;
@@ -1782,16 +1784,33 @@ void komodo_args(char *argv0)
{
ASSETCHAINS_OVERWINTER = GetArg("-ac_overwinter", ASSETCHAINS_SAPLING);
}
if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 && ASSETCHAINS_COMMISSION > 0 && ASSETCHAINS_COMMISSION <= 100000000 )
decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str());
else if ( ASSETCHAINS_COMMISSION != 0 )
if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 || ASSETCHAINS_SCRIPTPUB.size() > 1 )
{
ASSETCHAINS_COMMISSION = 0;
printf("ASSETCHAINS_COMMISSION needs an ASSETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n");
if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 )
{
decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str());
calc_rmd160_sha256(ASSETCHAINS_OVERRIDE_PUBKEYHASH,ASSETCHAINS_OVERRIDE_PUBKEY33,33);
}
if ( ASSETCHAINS_COMMISSION == 0 && ASSETCHAINS_FOUNDERS != 0 )
{
ASSETCHAINS_COMMISSION = 53846154; // maps to 35%
printf("ASSETCHAINS_COMMISSION defaulted to 35%% when founders reward active\n");
}
}
if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 )
else
{
if ( ASSETCHAINS_COMMISSION != 0 )
{
ASSETCHAINS_COMMISSION = 0;
printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n");
}
if ( ASSETCHAINS_FOUNDERS != 0 )
{
ASSETCHAINS_FOUNDERS = 0;
printf("ASSETCHAINS_FOUNDERS needs an ASETCHAINS_OVERRIDE_PUBKEY\n");
}
}
if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 )
{
printf("perc.%llu\n",(long long)ASSETCHAINS_COMMISSION);
@@ -1838,17 +1857,34 @@ void komodo_args(char *argv0)
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_LWMAPOS),(void *)&ASSETCHAINS_LWMAPOS);
}
val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6);
val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6) | ASSETCHAINS_TXPOW;
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val);
if ( ASSETCHAINS_FOUNDERS != 0 )
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_FOUNDERS),(void *)&ASSETCHAINS_FOUNDERS);
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
extralen += iguana_rwnum(1,&extraptr[extralen],(int32_t)ASSETCHAINS_SCRIPTPUB.size(),(void *)ASSETCHAINS_SCRIPTPUB.c_str());
}
addn = GetArg("-seednode","");
if ( strlen(addn.c_str()) > 0 )
ASSETCHAINS_SEED = 1;
strncpy(ASSETCHAINS_SYMBOL,name.c_str(),sizeof(ASSETCHAINS_SYMBOL)-1);
MAX_MONEY = komodo_max_money();
if ( (baseid = komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 )
{
//komodo_maxallowed(baseid);
printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN);
}
if ( ASSETCHAINS_CC >= KOMODO_FIRSTFUNGIBLEID && MAX_MONEY < 1000000LL*SATOSHIDEN )
MAX_MONEY = 1000000LL*SATOSHIDEN;
if ( MAX_MONEY <= 0 || MAX_MONEY > 1000000000LL*SATOSHIDEN )
MAX_MONEY = 1000000000LL*SATOSHIDEN;
//fprintf(stderr,"MAX_MONEY %llu %.8f\n",(long long)MAX_MONEY,(double)MAX_MONEY/SATOSHIDEN);
//printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN);
ASSETCHAINS_P2PPORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen);
while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 )
@@ -1865,6 +1901,11 @@ void komodo_args(char *argv0)
{
int32_t komodo_baseid(char *origbase);
extern int COINBASE_MATURITY;
if ( strcmp(ASSETCHAINS_SYMBOL,"KMD") == 0 )
{
fprintf(stderr,"cant have assetchain named KMD\n");
exit(0);
}
if ( (port= komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL)) != 0 )
ASSETCHAINS_RPCPORT = port;
else komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT + 1);
@@ -1933,11 +1974,20 @@ void komodo_args(char *argv0)
break;
}
}
int32_t dpowconfs = KOMODO_DPOWCONFS;
if ( ASSETCHAINS_SYMBOL[0] != 0 )
{
BITCOIND_RPCPORT = GetArg("-rpcport", ASSETCHAINS_RPCPORT);
//fprintf(stderr,"(%s) port.%u chain params initialized\n",ASSETCHAINS_SYMBOL,BITCOIND_RPCPORT);
if ( strcmp("PIRATE",ASSETCHAINS_SYMBOL) == 0 && ASSETCHAINS_HALVING[0] == 77777 )
{
ASSETCHAINS_HALVING[0] *= 5;
fprintf(stderr,"PIRATE halving changed to %d %.1f days\n",(int32_t)ASSETCHAINS_HALVING[0],(double)ASSETCHAINS_HALVING[0]/1440);
}
else if ( strcmp("VRSC",ASSETCHAINS_SYMBOL) == 0 )
dpowconfs = 0;
} else BITCOIND_RPCPORT = GetArg("-rpcport", BaseParams().RPCPort());
KOMODO_DPOWCONFS = GetArg("-dpowconfs",dpowconfs);
}
void komodo_nameset(char *symbol,char *dest,char *source)

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,6 @@
#include "tinyformat.h"
#include "txmempool.h"
#include "uint256.h"
#include "cheatcatcher.h"
#include <algorithm>
#include <exception>
@@ -184,11 +183,11 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
/** Unregister a network node */
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
/**
/**
* Process an incoming block. This only returns after the best known valid
* block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity!
*
*
* @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process.
@@ -647,7 +646,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
/**
* Check transaction inputs, and make sure any
* pay-to-script-hash transactions are evaluating IsStandard scripts
*
*
* Why bother? To avoid denial-of-service attacks; an attacker
* can submit a standard HASH... OP_EQUAL transaction,
* which will get accepted into blocks. The redemption
@@ -656,14 +655,14 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
*/
/**
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
* @return True if all inputs (scriptSigs) use only standard transaction forms
*/
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId);
/**
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent
* @see CTransaction::FetchInputs
@@ -672,7 +671,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx);
/**
* Count ECDSA signature operations in pay-to-script-hash inputs.
*
*
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
* @return maximum number of sigops required to validate this transaction's inputs
* @see CTransaction::FetchInputs
@@ -740,9 +739,9 @@ bool IsExpiredTx(const CTransaction &tx, int nBlockHeight);
*/
bool CheckFinalTx(const CTransaction &tx, int flags = -1);
/**
/**
* Closure representing one script verification
* Note that this stores references to the spending transaction
* Note that this stores references to the spending transaction
*/
class CScriptCheck
{

View File

@@ -10,7 +10,6 @@
#include "amount.h"
#include "chainparams.h"
#include "cc/StakeGuard.h"
#include "importcoin.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
@@ -124,7 +123,7 @@ extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGT
extern const char *ASSETCHAINS_ALGORITHMS[];
extern int32_t VERUS_MIN_STAKEAGE, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY;
extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB;
void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
@@ -135,7 +134,7 @@ int32_t komodo_pax_opreturn(int32_t height,uint8_t *opret,int32_t maxsize);
int32_t komodo_baseid(char *origbase);
int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag);
int64_t komodo_block_unlocktime(uint32_t nHeight);
uint64_t komodo_commission(const CBlock *block);
uint64_t komodo_commission(const CBlock *block,int32_t height);
int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig);
int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey &pk);
int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33);
@@ -237,94 +236,6 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
vector<TxPriority> vecPriority;
vecPriority.reserve(mempool.mapTx.size() + 1);
// check if we should add cheat transaction
CBlockIndex *ppast;
CTransaction cb;
int cheatHeight = nHeight - COINBASE_MATURITY < 1 ? 1 : nHeight - COINBASE_MATURITY;
if (cheatCatcher &&
sapling && chainActive.Height() > 100 &&
(ppast = chainActive[cheatHeight]) &&
ppast->IsVerusPOSBlock() &&
cheatList.IsHeightOrGreaterInList(cheatHeight))
{
// get the block and see if there is a cheat candidate for the stake tx
CBlock b;
if (!(fHavePruned && !(ppast->nStatus & BLOCK_HAVE_DATA) && ppast->nTx > 0) && ReadBlockFromDisk(b, ppast, 1))
{
CTransaction &stakeTx = b.vtx[b.vtx.size() - 1];
if (cheatList.IsCheatInList(stakeTx, &cheatTx))
{
// make and sign the cheat transaction to spend the coinbase to our address
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
uint32_t voutNum;
// get the first vout with value
for (voutNum = 0; voutNum < b.vtx[0].vout.size(); voutNum++)
{
if (b.vtx[0].vout[voutNum].nValue > 0)
break;
}
// send to the same pub key as the destination of this block reward
if (MakeCheatEvidence(mtx, b.vtx[0], voutNum, cheatTx))
{
extern CWallet *pwalletMain;
LOCK(pwalletMain->cs_wallet);
TransactionBuilder tb = TransactionBuilder(consensusParams, nHeight);
cb = b.vtx[0];
cbHash = cb.GetHash();
bool hasInput = false;
for (uint32_t i = 0; i < cb.vout.size(); i++)
{
// add the spends with the cheat
if (cb.vout[i].nValue > 0)
{
tb.AddTransparentInput(COutPoint(cbHash,i), cb.vout[0].scriptPubKey, cb.vout[0].nValue);
hasInput = true;
}
}
if (hasInput)
{
// this is a send from a t-address to a sapling address, which we don't have an ovk for.
// Instead, generate a common one from the HD seed. This ensures the data is
// recoverable, at least for us, while keeping it logically separate from the ZIP 32
// Sapling key hierarchy, which the user might not be using.
uint256 ovk;
HDSeed seed;
if (pwalletMain->GetHDSeed(seed)) {
ovk = ovkForShieldingFromTaddr(seed);
// send everything to Sapling address
tb.SendChangeTo(cheatCatcher.value(), ovk);
tb.AddOpRet(mtx.vout[mtx.vout.size() - 1].scriptPubKey);
cheatSpend = tb.Build();
}
}
}
}
}
}
if (cheatSpend)
{
cheatTx = cheatSpend.value();
std::list<CTransaction> removed;
mempool.removeConflicts(cheatTx, removed);
printf("Found cheating stake! Adding cheat spend for %.8f at block #%d, coinbase tx\n%s\n",
(double)cb.GetValueOut() / (double)COIN, nHeight, cheatSpend.value().vin[0].prevout.hash.GetHex().c_str());
// add to mem pool and relay
if (myAddtomempool(cheatTx))
{
RelayTransaction(cheatTx);
}
}
// now add transactions from the mem pool
for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
mi != mempool.mapTx.end(); ++mi)
@@ -573,9 +484,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
{
CAmount txfees;
// after Sapling, stake transactions have a fee, but it is recovered in the reward
// this ensures that a rebroadcast goes through quickly to begin staking again
txfees = sapling ? DEFAULT_STAKE_TXFEE : 0;
txfees = 0;
pblock->vtx.push_back(txStaked);
pblocktemplate->vTxFees.push_back(txfees);
@@ -596,27 +505,6 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
txNew.vout[0].nValue = GetBlockSubsidy(nHeight,consensusParams) + nFees;
// once we get to Sapling, enable CC StakeGuard for stake transactions
if (isStake && sapling)
{
// if there is a specific destination, use it
CTransaction stakeTx = pblock->vtx[pblock->vtx.size() - 1];
CStakeParams p;
if (ValidateStakeTransaction(stakeTx, p, false))
{
if (!p.pk.IsValid() || !MakeGuardedOutput(txNew.vout[0].nValue, p.pk, stakeTx, txNew.vout[0]))
{
fprintf(stderr,"CreateNewBlock: failed to make GuardedOutput on staking coinbase\n");
return 0;
}
}
else
{
fprintf(stderr,"CreateNewBlock: invalid stake transaction\n");
return 0;
}
}
txNew.nExpiryHeight = 0;
txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
@@ -647,17 +535,22 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
txNew.vout[1].scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK);
txNew.vout[1].nValue = 0;
} // timelocks and commissions are currently incompatible due to validation complexity of the combination
else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&pblocktemplate->block)) != 0 )
else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0 )
{
int32_t i; uint8_t *ptr;
txNew.vout.resize(2);
txNew.vout[1].nValue = commission;
txNew.vout[1].scriptPubKey.resize(35);
ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0];
ptr[0] = 33;
for (i=0; i<33; i++)
ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i];
ptr[34] = OP_CHECKSIG;
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
txNew.vout[1].scriptPubKey = CScript() << ParseHex(ASSETCHAINS_SCRIPTPUB);
else
{
txNew.vout[1].scriptPubKey.resize(35);
ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0];
ptr[0] = 33;
for (i=0; i<33; i++)
ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i];
ptr[34] = OP_CHECKSIG;
}
//printf("autocreate commision vout\n");
}
@@ -1455,7 +1348,7 @@ void static BitcoinMiner()
unsigned int n = chainparams.EquihashN();
unsigned int k = chainparams.EquihashK();
uint8_t *script; uint64_t total,checktoshis; int32_t i,j,gpucount=KOMODO_MAXGPUCOUNT,notaryid = -1;
uint8_t *script; uint64_t total; int32_t i,j,gpucount=KOMODO_MAXGPUCOUNT,notaryid = -1;
while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) )
{
sleep(1);
@@ -1648,7 +1541,7 @@ void static BitcoinMiner()
{
fprintf(stderr,"Mining when blockchain might not be in sync longest.%d vs %d\n",KOMODO_LONGESTCHAIN,Mining_height);
if ( KOMODO_LONGESTCHAIN != 0 && Mining_height >= KOMODO_LONGESTCHAIN )
KOMODO_INSYNC = 1;
KOMODO_INSYNC = Mining_height;
sleep(3);
}
// Hash state
@@ -1904,35 +1797,6 @@ void static BitcoinMiner()
void GenerateBitcoins(bool fGenerate, int nThreads)
#endif
{
// if we are supposed to catch stake cheaters, there must be a valid sapling parameter, we need it at
// initialization, and this is the first time we can get it. store the Sapling address here
extern boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
extern std::string VERUS_CHEATCATCHER;
libzcash::PaymentAddress addr = DecodePaymentAddress(VERUS_CHEATCATCHER);
if (VERUS_CHEATCATCHER.size() > 0 && IsValidPaymentAddress(addr))
{
try
{
cheatCatcher = boost::get<libzcash::SaplingPaymentAddress>(addr);
}
catch (...)
{
}
}
if (VERUS_CHEATCATCHER.size() > 0)
{
if (cheatCatcher == boost::none)
{
LogPrintf("ERROR: -cheatcatcher parameter is invalid Sapling payment address\n");
fprintf(stderr, "-cheatcatcher parameter is invalid Sapling payment address\n");
}
else
{
LogPrintf("Cheat Catcher active on %s\n", VERUS_CHEATCATCHER.c_str());
fprintf(stderr, "Cheat Catcher active on %s\n", VERUS_CHEATCATCHER.c_str());
}
}
static boost::thread_group* minerThreads = NULL;
if (nThreads < 0)

View File

@@ -472,30 +472,7 @@ CChainPower GetBlockProof(const CBlockIndex& block)
CBlockHeader header = block.GetBlockHeader();
// if POS block, add stake
if (!NetworkUpgradeActive(block.GetHeight(), Params().GetConsensus(), Consensus::UPGRADE_SAPLING) || !header.IsVerusPOSBlock())
{
return CChainPower(0, bnStakeTarget, (~bnWorkTarget / (bnWorkTarget + 1)) + 1);
}
else
{
bnStakeTarget.SetCompact(header.GetVerusPOSTarget(), &fNegative, &fOverflow);
if (fNegative || fOverflow || bnStakeTarget == 0)
return CChainPower(0);
// as the nonce has a fixed definition for a POS block, add the random amount of "work" from the nonce, so there will
// statistically always be a deterministic winner in POS
arith_uint256 aNonce;
// random amount of additional stake added is capped to 1/2 the current stake target
aNonce = UintToArith256(block.nNonce) | (bnStakeTarget << (uint64_t)1);
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
// as it's too large for a arith_uint256. However, as 2**256 is at least as large
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
// or ~bnTarget / (nTarget+1) + 1.
return CChainPower(0, ((~bnStakeTarget / (bnStakeTarget + 1)) + 1) + ((~aNonce / (aNonce + 1)) + 1),
(~bnWorkTarget / (bnWorkTarget + 1)) + 1);
}
return CChainPower(0, bnStakeTarget, (~bnWorkTarget / (bnWorkTarget + 1)) + 1);
}
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)

View File

@@ -33,6 +33,8 @@ using namespace std;
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
int32_t komodo_longestchain();
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
extern int32_t KOMODO_LONGESTCHAIN;
double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty)
{
@@ -118,7 +120,8 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
// Only report confirmations if the block is on the main chain
if (chainActive.Contains(blockindex))
confirmations = chainActive.Height() - blockindex->GetHeight() + 1;
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->GetHeight(),confirmations)));
result.push_back(Pair("rawconfirmations", confirmations));
result.push_back(Pair("height", blockindex->GetHeight()));
result.push_back(Pair("version", blockindex->nVersion));
result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex()));
@@ -150,7 +153,8 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan");
}
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->GetHeight(),confirmations)));
result.push_back(Pair("rawconfirmations", confirmations));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->GetHeight()));
result.push_back(Pair("version", block.nVersion));
@@ -267,7 +271,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
// Only report confirmations if the block is on the main chain
if (chainActive.Contains(blockindex))
confirmations = chainActive.Height() - blockindex->GetHeight() + 1;
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->GetHeight(),confirmations)));
result.push_back(Pair("rawconfirmations", confirmations));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->GetHeight()));
result.push_back(Pair("version", block.nVersion));
@@ -379,6 +384,18 @@ bool myIsutxo_spentinmempool(uint256 txid,int32_t vout)
return(false);
}
bool mytxid_inmempool(uint256 txid)
{
BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
{
const CTransaction &tx = e.GetTx();
const uint256 &hash = tx.GetHash();
if ( txid == hash )
return(true);
}
return(false);
}
UniValue mempoolToJSON(bool fVerbose = false)
{
if (fVerbose)
@@ -851,7 +868,7 @@ UniValue kvsearch(const UniValue& params, bool fHelp)
"}\n"
"\nExamples:\n"
+ HelpExampleCli("kvsearch", "examplekey")
+ HelpExampleRpc("kvsearch", "examplekey")
+ HelpExampleRpc("kvsearch", "\"examplekey\"")
);
LOCK(cs_main);
if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
@@ -1176,7 +1193,11 @@ UniValue gettxout(const UniValue& params, bool fHelp)
ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
ret.push_back(Pair("confirmations", 0));
else ret.push_back(Pair("confirmations", pindex->GetHeight() - coins.nHeight + 1));
else
{
ret.push_back(Pair("confirmations", komodo_dpowconfs(coins.nHeight,pindex->GetHeight() - coins.nHeight + 1)));
ret.push_back(Pair("rawconfirmations", pindex->GetHeight() - coins.nHeight + 1));
}
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
uint64_t interest; int32_t txheight; uint32_t locktime;
if ( (interest= komodo_accrued_interest(&txheight,&locktime,hash,n,coins.nHeight,coins.vout[n].nValue,(int32_t)pindex->GetHeight())) != 0 )
@@ -1333,7 +1354,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
if ( ASSETCHAINS_SYMBOL[0] == 0 ) {
progress = Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.LastTip());
} else {
int32_t longestchain = komodo_longestchain();
int32_t longestchain = KOMODO_LONGESTCHAIN;//komodo_longestchain();
progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0;
}
UniValue obj(UniValue::VOBJ);
@@ -1404,6 +1425,8 @@ struct CompareBlocksByHeight
}
};
#include <pthread.h>
UniValue getchaintips(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -1442,17 +1465,33 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
/* Build up a list of chain tips. We start with the list of all
known blocks, and successively remove blocks that appear as pprev
of another block. */
/*static pthread_mutex_t mutex; static int32_t didinit;
if ( didinit == 0 )
{
pthread_mutex_init(&mutex,NULL);
didinit = 1;
}
pthread_mutex_lock(&mutex);*/
std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
int32_t n = 0;
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
{
n++;
setTips.insert(item.second);
}
fprintf(stderr,"iterations getchaintips %d\n",n);
n = 0;
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
{
const CBlockIndex* pprev=0;
n++;
if ( item.second != 0 )
pprev = item.second->pprev;
if (pprev)
setTips.erase(pprev);
}
fprintf(stderr,"iterations getchaintips %d\n",n);
//pthread_mutex_unlock(&mutex);
// Always report the currently active tip.
setTips.insert(chainActive.LastTip());

View File

@@ -50,7 +50,9 @@ UniValue assetchainproof(const UniValue& params, bool fHelp)
UniValue crosschainproof(const UniValue& params, bool fHelp)
{
UniValue ret(UniValue::VOBJ);
//fprintf(stderr,"crosschainproof needs to be implemented\n");
return(ret);
}

View File

@@ -996,7 +996,7 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp)
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblocksubsidy", "1000")
+ HelpExampleRpc("getblockubsidy", "1000")
+ HelpExampleRpc("getblocksubsidy", "1000")
);
LOCK(cs_main);

View File

@@ -63,6 +63,7 @@ extern uint32_t ASSETCHAINS_MAGIC;
extern uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY,ASSETCHAINS_LASTERA;
extern int32_t ASSETCHAINS_LWMAPOS;
extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[];
extern std::string NOTARY_PUBKEY; extern uint8_t NOTARY_PUBKEY33[];
UniValue getinfo(const UniValue& params, bool fHelp)
{
@@ -125,9 +126,15 @@ UniValue getinfo(const UniValue& params, bool fHelp)
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(KOMODO_WALLETBALANCE))); //pwalletMain->GetBalance()
if ( ASSETCHAINS_SYMBOL[0] == 0 )
obj.push_back(Pair("interest", ValueFromAmount(KOMODO_INTERESTSUM))); //komodo_interestsum()
{
obj.push_back(Pair("interest", ValueFromAmount(KOMODO_INTERESTSUM)));
obj.push_back(Pair("balance", ValueFromAmount(KOMODO_WALLETBALANCE))); //pwalletMain->GetBalance()
}
else
{
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); //
}
}
#endif
//fprintf(stderr,"after wallet %u\n",(uint32_t)time(NULL));
@@ -162,16 +169,18 @@ UniValue getinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("pubkey", pubkeystr));
if ( KOMODO_LASTMINED != 0 )
obj.push_back(Pair("lastmined", KOMODO_LASTMINED));
} else if ( NOTARY_PUBKEY33[0] != 0 ) {
obj.push_back(Pair("pubkey", NOTARY_PUBKEY));
}
}
if ( ASSETCHAINS_CC != 0 )
obj.push_back(Pair("CCid", (int)ASSETCHAINS_CC));
obj.push_back(Pair("name", ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL));
obj.push_back(Pair("p2pport", ASSETCHAINS_P2PPORT));
obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT));
if ( ASSETCHAINS_SYMBOL[0] != 0 )
{
//obj.push_back(Pair("name", ASSETCHAINS_SYMBOL));
obj.push_back(Pair("p2pport", ASSETCHAINS_P2PPORT));
obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT));
obj.push_back(Pair("magic", (int)ASSETCHAINS_MAGIC));
obj.push_back(Pair("premine", ASSETCHAINS_SUPPLY));

View File

@@ -168,42 +168,51 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
int32_t KOMODO_LONGESTCHAIN;
int32_t komodo_longestchain()
{
static int32_t depth;
int32_t ht,n=0,num=0,maxheight=0,height = 0;
vector<CNodeStats> vstats;
if ( depth < 0 )
depth = 0;
if ( depth == 0 )
{
LOCK(cs_main);
CopyNodeStats(vstats);
depth++;
vector<CNodeStats> vstats;
{
//LOCK(cs_main);
CopyNodeStats(vstats);
}
BOOST_FOREACH(const CNodeStats& stats, vstats)
{
//fprintf(stderr,"komodo_longestchain iter.%d\n",n);
CNodeStateStats statestats;
bool fStateStats = GetNodeStateStats(stats.nodeid,statestats);
if ( statestats.nSyncHeight < 0 )
continue;
ht = 0;
if ( stats.nStartingHeight > ht )
ht = stats.nStartingHeight;
if ( statestats.nSyncHeight > ht )
ht = statestats.nSyncHeight;
if ( statestats.nCommonHeight > ht )
ht = statestats.nCommonHeight;
if ( maxheight == 0 || ht > maxheight*1.01 )
maxheight = ht, num = 1;
else if ( ht > maxheight*0.99 )
num++;
if ( ht > height )
height = ht;
}
depth--;
if ( num > (n >> 1) )
{
extern char ASSETCHAINS_SYMBOL[];
if ( 0 && height != KOMODO_LONGESTCHAIN )
fprintf(stderr,"set %s KOMODO_LONGESTCHAIN <- %d\n",ASSETCHAINS_SYMBOL,height);
KOMODO_LONGESTCHAIN = height;
return(height);
}
KOMODO_LONGESTCHAIN = 0;
}
BOOST_FOREACH(const CNodeStats& stats, vstats)
{
//fprintf(stderr,"komodo_longestchain iter.%d\n",n);
CNodeStateStats statestats;
bool fStateStats = GetNodeStateStats(stats.nodeid,statestats);
ht = 0;
if ( stats.nStartingHeight > ht )
ht = stats.nStartingHeight;
if ( statestats.nSyncHeight > ht )
ht = statestats.nSyncHeight;
if ( statestats.nCommonHeight > ht )
ht = statestats.nCommonHeight;
if ( maxheight == 0 || ht > maxheight*1.01 )
maxheight = ht, num = 1;
else if ( ht > maxheight*0.99 )
num++;
n++;
if ( ht > height )
height = ht;
}
if ( num > (n >> 1) )
{
extern char ASSETCHAINS_SYMBOL[];
if ( 0 && height != KOMODO_LONGESTCHAIN )
fprintf(stderr,"set %s KOMODO_LONGESTCHAIN <- %d\n",ASSETCHAINS_SYMBOL,height);
KOMODO_LONGESTCHAIN = height;
return(height);
}
KOMODO_LONGESTCHAIN = 0;
return(0);
return(KOMODO_LONGESTCHAIN);
}
UniValue addnode(const UniValue& params, bool fHelp)

View File

@@ -35,6 +35,7 @@
using namespace std;
extern char ASSETCHAINS_SYMBOL[];
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
{
@@ -274,7 +275,8 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
if (nConfirmations > 0) {
entry.push_back(Pair("height", nHeight));
entry.push_back(Pair("confirmations", nConfirmations));
entry.push_back(Pair("confirmations", komodo_dpowconfs(nHeight,nConfirmations)));
entry.push_back(Pair("rawconfirmations", nConfirmations));
entry.push_back(Pair("time", nBlockTime));
entry.push_back(Pair("blocktime", nBlockTime));
} else {
@@ -357,7 +359,9 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->GetHeight()));
entry.push_back(Pair("height", pindex->GetHeight()));
entry.push_back(Pair("rawconfirmations", 1 + chainActive.Height() - pindex->GetHeight()));
entry.push_back(Pair("confirmations", komodo_dpowconfs(pindex->GetHeight(),1 + chainActive.Height() - pindex->GetHeight())));
entry.push_back(Pair("time", pindex->GetBlockTime()));
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
}
@@ -543,7 +547,7 @@ int32_t gettxout_scriptPubKey(uint8_t *scriptPubKey,int32_t maxsize,uint256 txid
uint256 hashBlock;
if ( GetTransaction(txid,tx,hashBlock,false) == 0 )
return(-1);
else if ( n <= tx.vout.size() ) // vout.size() seems off by 1
else if ( n < tx.vout.size() )
{
ptr = (uint8_t *)&tx.vout[n].scriptPubKey[0];
m = tx.vout[n].scriptPubKey.size();
@@ -1155,35 +1159,65 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
// Use CTransaction for the constant parts of the
// transaction to avoid rehashing.
CMutableTransaction mergedTxsave = mergedTx;
int32_t txpow,numiters = 0;
const CTransaction txConst(mergedTx);
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
continue;
if ( (txpow = ASSETCHAINS_TXPOW) != 0 )
{
if ( txConst.IsCoinBase() != 0 )
{
if ( (txpow & 2) == 0 )
txpow == 0;
}
const CScript& prevPubKey = CCoinsViewCache::GetSpendFor(coins, txin);
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
}
UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
else
{
if ( (txpow & 1) == 0 )
txpow == 0;
}
}
while ( 1 )
{
if ( txpow != 0 )
mergedTx = mergedTxsave;
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
continue;
}
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
}
UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}
if ( txpow != 0 )
{
uint256 txid = mergedTx.GetHash();
if ( ((uint8_t *)&txid)[0] == 0 && ((uint8_t *)&txid)[31] == 0 )
break;
//fprintf(stderr,"%d: tmp txid.%s\n",numiters,txid.GetHex().c_str());
} else break;
numiters++;
}
if ( numiters > 0 )
fprintf(stderr,"ASSETCHAINS_TXPOW.%d txpow.%d numiters.%d for signature\n",ASSETCHAINS_TXPOW,txpow,numiters);
bool fComplete = vErrors.empty();
UniValue result(UniValue::VOBJ);

View File

@@ -249,7 +249,7 @@ void GenerateBitcoins(bool b, CWallet *pw);
UniValue stop(const UniValue& params, bool fHelp)
{
char buf[64];
char buf[66+128];
// Accept the deprecated and ignored 'detach' boolean argument
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -264,7 +264,7 @@ UniValue stop(const UniValue& params, bool fHelp)
// Shutdown will take long enough that the response should get back
StartShutdown();
sprintf(buf,"%s Komodo server stopping",ASSETCHAINS_SYMBOL);
sprintf(buf,"%s server stopping",ASSETCHAINS_SYMBOL[0] != 0 ? ASSETCHAINS_SYMBOL : "Komodo");
return buf;
}
@@ -361,7 +361,7 @@ static const CRPCCommand vRPCCommands[] =
#ifdef ENABLE_WALLET
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
#endif
/*
// auction
{ "auction", "auctionaddress", &auctionaddress, true },
@@ -388,17 +388,16 @@ static const CRPCCommand vRPCCommands[] =
{ "faucet", "faucetfund", &faucetfund, true },
{ "faucet", "faucetget", &faucetget, true },
{ "faucet", "faucetaddress", &faucetaddress, true },
// MofN
{ "MofN", "mofnaddress", &mofnaddress, true },
// Heir
{ "heir", "heiraddress", &heiraddress, true },
// Channels
{ "channels", "channelsaddress", &channelsaddress, true },
{ "channels", "channelsinfo", &channelsinfo, true },
{ "channels", "channelsopen", &channelsopen, true },
{ "channels", "channelspayment", &channelspayment, true },
{ "channels", "channelscollect", &channelscollect, true },
{ "channels", "channelsstop", &channelsstop, true },
{ "channels", "channelsclose", &channelsclose, true },
{ "channels", "channelsrefund", &channelsrefund, true },
// Oracles
@@ -410,19 +409,26 @@ static const CRPCCommand vRPCCommands[] =
{ "oracles", "oraclessubscribe", &oraclessubscribe, true },
{ "oracles", "oraclesdata", &oraclesdata, true },
{ "oracles", "oraclessamples", &oraclessamples, true },
// Prices
{ "prices", "pricesaddress", &pricesaddress, true },
{ "prices", "pricesaddress", &pricesaddress, true },
{ "prices", "priceslist", &priceslist, true },
{ "prices", "pricesinfo", &pricesinfo, true },
{ "prices", "pricescreate", &pricescreate, true },
{ "prices", "pricesaddfunding", &pricesaddfunding, true },
{ "prices", "pricesbet", &pricesbet, true },
{ "prices", "pricesstatus", &pricesstatus, true },
{ "prices", "pricesfinish", &pricesfinish, true },
// Pegs
{ "pegs", "pegsaddress", &pegsaddress, true },
// Triggers
{ "triggers", "triggersaddress", &triggersaddress, true },
// Payments
{ "payments", "paymentsaddress", &paymentsaddress, true },
// Gateways
{ "gateways", "gatewaysaddress", &gatewaysaddress, true },
{ "gateways", "gatewayslist", &gatewayslist, true },
@@ -432,7 +438,9 @@ static const CRPCCommand vRPCCommands[] =
{ "gateways", "gatewaysclaim", &gatewaysclaim, true },
{ "gateways", "gatewayswithdraw", &gatewayswithdraw, true },
{ "gateways", "gatewayspending", &gatewayspending, true },
{ "gateways", "gatewaysmultisig", &gatewaysmultisig, true },
{ "gateways", "gatewaysmarkdone", &gatewaysmarkdone, true },
{ "gateways", "gatewayspartialsign", &gatewayspartialsign, true },
// dice
{ "dice", "dicelist", &dicelist, true },
@@ -460,7 +468,7 @@ static const CRPCCommand vRPCCommands[] =
{ "tokens", "tokencancelask", &tokencancelask, true },
{ "tokens", "tokenfillask", &tokenfillask, true },
//{ "tokens", "tokenfillswap", &tokenfillswap, true },
*/
/* Address index */
{ "addressindex", "getaddressmempool", &getaddressmempool, true },
{ "addressindex", "getaddressutxos", &getaddressutxos, false },
@@ -524,6 +532,7 @@ static const CRPCCommand vRPCCommands[] =
{ "wallet", "sendmany", &sendmany, false },
{ "wallet", "sendtoaddress", &sendtoaddress, false },
{ "wallet", "setaccount", &setaccount, true },
{ "wallet", "setpubkey", &setpubkey, true },
{ "wallet", "settxfee", &settxfee, true },
{ "wallet", "signmessage", &signmessage, true },
{ "wallet", "walletlock", &walletlock, true },

View File

@@ -236,7 +236,8 @@ extern UniValue tokenfillbid(const UniValue& params, bool fHelp);
extern UniValue tokenask(const UniValue& params, bool fHelp);
extern UniValue tokencancelask(const UniValue& params, bool fHelp);
extern UniValue tokenfillask(const UniValue& params, bool fHelp);
extern UniValue mofnaddress(const UniValue& params, bool fHelp);
extern UniValue tokenconvert(const UniValue& params, bool fHelp);
extern UniValue heiraddress(const UniValue& params, bool fHelp);
extern UniValue channelsaddress(const UniValue& params, bool fHelp);
extern UniValue oraclesaddress(const UniValue& params, bool fHelp);
extern UniValue oracleslist(const UniValue& params, bool fHelp);
@@ -247,6 +248,13 @@ extern UniValue oraclessubscribe(const UniValue& params, bool fHelp);
extern UniValue oraclesdata(const UniValue& params, bool fHelp);
extern UniValue oraclessamples(const UniValue& params, bool fHelp);
extern UniValue pricesaddress(const UniValue& params, bool fHelp);
extern UniValue priceslist(const UniValue& params, bool fHelp);
extern UniValue pricesinfo(const UniValue& params, bool fHelp);
extern UniValue pricescreate(const UniValue& params, bool fHelp);
extern UniValue pricesaddfunding(const UniValue& params, bool fHelp);
extern UniValue pricesbet(const UniValue& params, bool fHelp);
extern UniValue pricesstatus(const UniValue& params, bool fHelp);
extern UniValue pricesfinish(const UniValue& params, bool fHelp);
extern UniValue pegsaddress(const UniValue& params, bool fHelp);
extern UniValue triggersaddress(const UniValue& params, bool fHelp);
extern UniValue paymentsaddress(const UniValue& params, bool fHelp);
@@ -259,12 +267,12 @@ extern UniValue gatewaysclaim(const UniValue& params, bool fHelp);
extern UniValue gatewayswithdraw(const UniValue& params, bool fHelp);
extern UniValue gatewayspending(const UniValue& params, bool fHelp);
extern UniValue gatewaysmarkdone(const UniValue& params, bool fHelp);
extern UniValue gatewaysmultisig(const UniValue& params, bool fHelp);
extern UniValue gatewayspartialsign(const UniValue& params, bool fHelp);
extern UniValue channelsinfo(const UniValue& params, bool fHelp);
extern UniValue channelsbind(const UniValue& params, bool fHelp);
extern UniValue channelsopen(const UniValue& params, bool fHelp);
extern UniValue channelspayment(const UniValue& params, bool fHelp);
extern UniValue channelscollect(const UniValue& params, bool fHelp);
extern UniValue channelsstop(const UniValue& params, bool fHelp);
extern UniValue channelsclose(const UniValue& params, bool fHelp);
extern UniValue channelsrefund(const UniValue& params, bool fHelp);
//extern UniValue tokenswapask(const UniValue& params, bool fHelp);
@@ -330,6 +338,7 @@ extern UniValue walletlock(const UniValue& params, bool fHelp);
extern UniValue encryptwallet(const UniValue& params, bool fHelp);
extern UniValue validateaddress(const UniValue& params, bool fHelp);
extern UniValue getinfo(const UniValue& params, bool fHelp);
extern UniValue setpubkey(const UniValue& params, bool fHelp);
extern UniValue getwalletinfo(const UniValue& params, bool fHelp);
extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
extern UniValue getnetworkinfo(const UniValue& params, bool fHelp);

View File

@@ -18,7 +18,8 @@
using namespace std;
typedef std::vector<unsigned char> valtype;
typedef vector<unsigned char> valtype;
extern uint8_t ASSETCHAINS_TXPOW;
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
@@ -48,10 +49,20 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
}
else
{
if (!key.Sign(hash, vchSig))
return false;
if ( ASSETCHAINS_TXPOW == 0 )
{
if (!key.Sign(hash, vchSig))
return false;
}
else
{
if (!key.Sign(hash, vchSig, rand()))
return false;
}
}
vchSig.push_back((unsigned char)nHashType);
return true;
}
@@ -97,11 +108,6 @@ CC *CCcond1(uint8_t evalcode,CPubKey pk)
return CCNewThreshold(2, {condCC, Sig});
}
// TODO: these are redundant and should be cleaned up to one file
std::string _StakeGuardAddr = "RCG8KwJNDVwpUBcdoa6AoHqHVJsA1uMYMR";
std::string _StakeGuardPubKey = "03166b7813a4855a88e9ef7340a692ef3c2decedfdc2c7563ec79537e89667d935";
std::string _StakeGuardWIF = "Uw7vRYHGKjyi1FaJ8Lv1USSuj7ntUti8fAhSDiCdbzuV6yDagaTn";
std::vector<CCcontract_info> &GetCryptoConditions()
{
static bool initialized = false;
@@ -110,14 +116,7 @@ std::vector<CCcontract_info> &GetCryptoConditions()
if (!initialized)
{
C.evalcode = EVAL_STAKEGUARD;
strcpy(C.unspendableCCaddr,_StakeGuardAddr.c_str());
strcpy(C.normaladdr,_StakeGuardAddr.c_str());
strcpy(C.CChexstr,_StakeGuardPubKey.c_str());
memcpy(C.CCpriv, DecodeSecret(_StakeGuardWIF).begin(),32);
vCC.push_back(C);
initialized = true;
// this should initialize any desired auto-signed crypto-conditions
}
return vCC;
}

View File

@@ -371,7 +371,7 @@ bool ExtractDestination(const CScript& _scriptPubKey, CTxDestination& addressRet
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid())
{
fprintf(stderr,"TX_PUBKEY invalid pubkey\n");
//fprintf(stderr,"TX_PUBKEY invalid pubkey\n");
return false;
}

View File

@@ -23,8 +23,6 @@ int32_t ASSETCHAINS_LWMAPOS = 0;
int32_t VERUS_BLOCK_POSUNITS = 1000;
int32_t ASSETCHAINS_OVERWINTER = 227520;
int32_t ASSETCHAINS_SAPLING = 227520;
boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
std::string VERUS_CHEATCATCHER = "";
unsigned int MAX_BLOCK_SIGOPS = 20000;

View File

@@ -54,6 +54,8 @@ const std::string ADDR_TYPE_SAPLING = "sapling";
extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
extern uint8_t ASSETCHAINS_PRIVATE;
uint32_t komodo_segid32(char *coinaddr);
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
int32_t komodo_isnotaryvout(char *coinaddr); // from ac_private chains only
int64_t nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
@@ -96,16 +98,18 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
{
//int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
int confirms = wtx.GetDepthInMainChain();
entry.push_back(Pair("confirmations", confirms));
entry.push_back(Pair("rawconfirmations", confirms));
if (wtx.IsCoinBase())
entry.push_back(Pair("generated", true));
if (confirms > 0)
{
entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)mapBlockIndex[wtx.hashBlock]->GetHeight(),confirms)));
entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
entry.push_back(Pair("blockindex", wtx.nIndex));
entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
}
} else entry.push_back(Pair("confirmations", confirms));
uint256 hash = wtx.GetHash();
entry.push_back(Pair("txid", hash.GetHex()));
UniValue conflicts(UniValue::VARR);
@@ -438,6 +442,8 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
int32_t komodo_isnotaryvout(char *coinaddr);
UniValue sendtoaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
@@ -468,8 +474,12 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
);
if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 )
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
{
if ( komodo_isnotaryvout((char *)params[0].get_str().c_str()) == 0 )
{
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
}
}
LOCK2(cs_main, pwalletMain->cs_wallet);
CTxDestination dest = DecodeDestination(params[0].get_str());
@@ -552,7 +562,7 @@ UniValue kvupdate(const UniValue& params, bool fHelp)
"}\n"
"\nExamples:\n"
+ HelpExampleCli("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
+ HelpExampleRpc("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
+ HelpExampleRpc("kvupdate", "\"examplekey\",\"examplevalue\",\"2\",\"examplepassphrase\"")
);
if (!EnsureWalletIsAvailable(fHelp))
return 0;
@@ -1268,13 +1278,13 @@ UniValue sendmany(const UniValue& params, bool fHelp)
" the number of addresses.\n"
"\nExamples:\n"
"\nSend two amounts to two different addresses:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\"") +
+ HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\":0.01,\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\":0.02}\"") +
"\nSend two amounts to two different addresses setting the confirmation and comment:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 6 \"testing\"") +
+ HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\":0.01,\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\":0.02}\" 6 \"testing\"") +
"\nSend two amounts to two different addresses, subtract fee from amount:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
+ HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\":0.01,\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\",\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\"]\"") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"")
+ HelpExampleRpc("sendmany", "\"\", {\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\":0.01,\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\":0.02}, 6, \"testing\"")
);
if ( ASSETCHAINS_PRIVATE != 0 )
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
@@ -1613,8 +1623,6 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
}
}
bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig = true);
void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
{
CAmount nFee;
@@ -1622,21 +1630,9 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
list<COutputEntry> listReceived;
list<COutputEntry> listSent;
CStakeParams p;
bool bIsStake = false;
bool bIsCoinbase = false;
bool bIsMint = false;
if (ValidateStakeTransaction(wtx, p, false))
{
bIsStake = true;
}
else
{
bIsCoinbase = wtx.IsCoinBase();
bIsMint = bIsCoinbase && wtx.vout.size() > 0 && wtx.vout[0].scriptPubKey.IsPayToCryptoCondition();
}
bool bIsCoinbase = wtx.IsCoinBase();
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, bIsStake ? ISMINE_ALLANDCHANGE : filter);
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
bool fAllAccounts = (strAccount == string("*"));
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
@@ -1651,7 +1647,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
entry.push_back(Pair("involvesWatchonly", true));
entry.push_back(Pair("account", strSentAccount));
MaybePushAddress(entry, s.destination);
entry.push_back(Pair("category", bIsStake ? "stake" : "send"));
entry.push_back(Pair("category", "send"));
entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
entry.push_back(Pair("vout", s.vout));
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
@@ -1694,11 +1690,11 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
entry.push_back(Pair("blockstomaturity", btm));
}
else
entry.push_back(Pair("category", bIsMint ? "mint" : "generate"));
entry.push_back(Pair("category", "generate"));
}
else
{
entry.push_back(Pair("category", bIsStake ? "stake" : "receive"));
entry.push_back(Pair("category", "receive"));
}
entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
@@ -2730,7 +2726,9 @@ UniValue listunspent(const UniValue& params, bool fHelp)
if (destinations.size() && (!fValidAddress || !destinations.count(address)))
continue;
UniValue entry(UniValue::VOBJ);
CAmount nValue = out.tx->vout[out.i].nValue;
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
UniValue entry(UniValue::VOBJ); int32_t txheight = 0;
entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
entry.push_back(Pair("vout", out.i));
entry.push_back(Pair("generated", out.tx->IsCoinBase()));
@@ -2748,13 +2746,12 @@ UniValue listunspent(const UniValue& params, bool fHelp)
entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
}
}
CAmount nValue = out.tx->vout[out.i].nValue;
entry.push_back(Pair("amount", ValueFromAmount(out.tx->vout[out.i].nValue)));
entry.push_back(Pair("amount", ValueFromAmount(nValue)));
if ( out.tx->nLockTime != 0 )
{
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *tipindex,*pindex = it->second;
uint64_t interest; uint32_t locktime; int32_t txheight;
uint64_t interest; uint32_t locktime;
if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
{
interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->GetHeight());
@@ -2763,19 +2760,21 @@ UniValue listunspent(const UniValue& params, bool fHelp)
}
//fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.LastTip(),locktime,txheight,pindex->GetHeight());
}
else if ( chainActive.LastTip() != 0 )
txheight = (chainActive.LastTip()->GetHeight() - out.nDepth - 1);
entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
entry.push_back(Pair("confirmations", out.nDepth));
entry.push_back(Pair("rawconfirmations",out.nDepth));
entry.push_back(Pair("confirmations",komodo_dpowconfs(txheight,out.nDepth)));
entry.push_back(Pair("spendable", out.fSpendable));
results.push_back(entry);
}
return results;
}
uint64_t komodo_interestsum()
{
#ifdef ENABLE_WALLET
if ( GetBoolArg("-disablewallet", false) == 0 )
if ( ASSETCHAINS_SYMBOL[0] == 0 && GetBoolArg("-disablewallet", false) == 0 )
{
uint64_t interest,sum = 0; int32_t txheight; uint32_t locktime;
vector<COutput> vecOutputs;
@@ -4114,7 +4113,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
}
}
else if ( ASSETCHAINS_PRIVATE != 0 )
else if ( ASSETCHAINS_PRIVATE != 0 && komodo_isnotaryvout((char *)address.c_str()) == 0 )
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
if (setAddress.count(address))
@@ -4950,13 +4949,16 @@ int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
extern std::string NOTARY_PUBKEY;
uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr);
int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout);
int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
{
set<CBitcoinAddress> setAddress; uint8_t *script,utxosig[128]; uint256 utxotxid; uint64_t utxovalue; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector<COutput> vecOutputs; uint32_t utxovout,eligible,earliest = 0; CScript best_scriptPubKey; bool fNegative,fOverflow;
bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr;
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
if (!EnsureWalletIsAvailable(0))
return 0;
const CKeyStore& keystore = *pwalletMain;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
@@ -5117,6 +5119,9 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
{
static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
if (!EnsureWalletIsAvailable(0))
return 0;
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
ratio = (mindiff / bnTarget);
@@ -5294,6 +5299,7 @@ int32_t ensure_CCrequirements()
#include "../cc/CCchannels.h"
#include "../cc/CCOracles.h"
#include "../cc/CCGateways.h"
#include "../cc/CCPrices.h"
UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey)
{
@@ -5330,9 +5336,73 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned ch
return(result);
}
bool pubkey2addr(char *destaddr,uint8_t *pubkey33);
UniValue setpubkey(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ);
if ( fHelp || params.size() != 1 )
throw runtime_error(
"setpubkey\n"
"\nSets the -pubkey if the daemon was not started with it, if it was already set, it returns the pubkey.\n"
"\nArguments:\n"
"1. \"pubkey\" (string) pubkey to set.\n"
"\nResult:\n"
" {\n"
" \"pubkey\" : \"pubkey\", (string) The pubkey\n"
" \"ismine\" : \"true/false\", (bool)\n"
" \"R-address\" : \"R address\", (string) The pubkey\n"
" }\n"
"\nExamples:\n"
+ HelpExampleCli("setpubkey", "02f7597468703c1c5c8465dd6d43acaae697df9df30bed21494d193412a1ea193e")
+ HelpExampleRpc("setpubkey", "02f7597468703c1c5c8465dd6d43acaae697df9df30bed21494d193412a1ea193e")
);
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
char Raddress[18];
uint8_t pubkey33[33];
extern uint8_t NOTARY_PUBKEY33[];
extern std::string NOTARY_PUBKEY;
if ( NOTARY_PUBKEY33[0] == 0 ) {
if (strlen(params[0].get_str().c_str()) == 66) {
decode_hex(pubkey33,33,(char *)params[0].get_str().c_str());
pubkey2addr((char *)Raddress,(uint8_t *)pubkey33);
if (strcmp("RRmWExvapDM9YbLT9X9xAyzDgxomYf63ng",Raddress) == 0) {
result.push_back(Pair("error", "pubkey entered is invalid."));
} else {
CBitcoinAddress address(Raddress);
bool isValid = address.IsValid();
if (isValid)
{
CTxDestination dest = address.Get();
string currentAddress = address.ToString();
result.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
result.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
#endif
}
NOTARY_PUBKEY = params[0].get_str();
decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str());
}
} else {
result.push_back(Pair("error", "pubkey is wrong length, must be 66 char hex string."));
}
} else {
result.push_back(Pair("error", "Can only set pubkey once, to change it you need to restart your daemon."));
}
result.push_back(Pair("pubkey", NOTARY_PUBKEY));
return result;
}
UniValue channelsaddress(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector<unsigned char> destpubkey; CPubKey pk,pk2; char destaddr[64];
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector<unsigned char> destpubkey; CPubKey pk,pk2; char destaddr[64];
cp = CCinit(&C,EVAL_CHANNELS);
if ( fHelp || params.size() != 1 )
throw runtime_error("channelsaddress destpubkey\n");
@@ -5345,6 +5415,15 @@ UniValue channelsaddress(const UniValue& params, bool fHelp)
result.push_back(Pair("otherpubkey", params[0].get_str()));
GetCCaddress1of2(cp,destaddr,pk,pk2);
result.push_back(Pair("channeladdress",destaddr));
if ( 0 )
{
int32_t i;
for (i=0; i<100; i++)
{
GetCCaddress1of2(cp,destaddr,pk,pk2);
fprintf(stderr,"i.%d %s\n",i,destaddr);
}
}
return(result);
}
@@ -5363,15 +5442,25 @@ UniValue oraclesaddress(const UniValue& params, bool fHelp)
UniValue pricesaddress(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C,*assetscp,C2; std::vector<unsigned char> pubkey; CPubKey mypk,planpk,pricespk; char myaddr[64],houseaddr[64],exposureaddr[64];
cp = CCinit(&C,EVAL_PRICES);
assetscp = CCinit(&C2,EVAL_PRICES);
if ( fHelp || params.size() > 1 )
throw runtime_error("pricesaddress [pubkey]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
if ( params.size() == 1 )
pubkey = ParseHex(params[0].get_str().c_str());
return(CCaddress(cp,(char *)"Prices",pubkey));
result = CCaddress(cp,(char *)"Prices",pubkey);
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(assetscp,myaddr,mypk);
GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk);
GetCCaddress1of2(assetscp,exposureaddr,pricespk,pricespk);
result.push_back(Pair("myaddr",myaddr)); // for holding my asssets
result.push_back(Pair("houseaddr",houseaddr)); // globally accessible house assets
result.push_back(Pair("exposureaddr",exposureaddr)); // tracking of exposure
return(result);
}
UniValue pegsaddress(const UniValue& params, bool fHelp)
@@ -5426,17 +5515,17 @@ UniValue gatewaysaddress(const UniValue& params, bool fHelp)
return(CCaddress(cp,(char *)"Gateways",pubkey));
}
UniValue mofnaddress(const UniValue& params, bool fHelp)
UniValue heiraddress(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
cp = CCinit(&C,EVAL_MOFN);
cp = CCinit(&C,EVAL_HEIR);
if ( fHelp || params.size() > 1 )
throw runtime_error("mofnaddress [pubkey]\n");
throw runtime_error("heiraddress [pubkey]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
if ( params.size() == 1 )
pubkey = ParseHex(params[0].get_str().c_str());
return(CCaddress(cp,(char *)"MofN",pubkey));
return(CCaddress(cp,(char *)"Heir",pubkey));
}
UniValue lottoaddress(const UniValue& params, bool fHelp)
@@ -5534,11 +5623,15 @@ UniValue tokenaddress(const UniValue& params, bool fHelp)
UniValue channelsinfo(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() != 0 )
throw runtime_error("channelsinfo\n");
uint256 opentxid;
if ( fHelp || params.size() > 1 )
throw runtime_error("channelsinfo [opentxid]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
return(ChannelsInfo());
opentxid=zeroid;
if (params.size() > 0 && !params[0].isNull() && !params[0].get_str().empty())
opentxid = Parseuint256((char *)params[0].get_str().c_str());
return(ChannelsInfo(opentxid));
}
UniValue channelsopen(const UniValue& params, bool fHelp)
@@ -5549,10 +5642,26 @@ UniValue channelsopen(const UniValue& params, bool fHelp)
throw runtime_error("channelsopen destpubkey numpayments payment\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
destpub = ParseHex(params[0].get_str().c_str());
if (destpub.size()!= 33)
{
ERR_RESULT("invalid destination pubkey");
return result;
}
numpayments = atoi(params[1].get_str().c_str());
if (numpayments <1)
{
ERR_RESULT("invalid number of payments, must be greater than 0");
return result;
}
payment = atol(params[2].get_str().c_str());
if (payment <1)
{
ERR_RESULT("invalid payment amount, must be greater than 0");
return result;
}
hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment);
if ( hex.size() > 0 )
{
@@ -5562,40 +5671,28 @@ UniValue channelsopen(const UniValue& params, bool fHelp)
return(result);
}
UniValue channelsstop(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex; uint256 origtxid;
cp = CCinit(&C,EVAL_CHANNELS);
if ( fHelp || params.size() != 2 )
throw runtime_error("channelsstop destpubkey origtxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
destpub = ParseHex(params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
hex = ChannelStop(0,pubkey2pk(destpub),origtxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt create channelsstop transaction");
return(result);
}
UniValue channelspayment(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,prevtxid; int32_t n; int64_t amount;
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,secret=zeroid; int32_t n; int64_t amount;
cp = CCinit(&C,EVAL_CHANNELS);
if ( fHelp || params.size() != 4 )
throw runtime_error("channelspayment prevtxid origtxid n amount\n");
if ( fHelp || params.size() != 2 )
throw runtime_error("channelspayment opentxid amount [secret]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
prevtxid = Parseuint256((char *)params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
n = atoi((char *)params[2].get_str().c_str());
amount = atoi((char *)params[3].get_str().c_str());
hex = ChannelPayment(0,prevtxid,origtxid,n,amount);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
opentxid = Parseuint256((char *)params[0].get_str().c_str());
amount = atoi((char *)params[1].get_str().c_str());
if (amount <1)
{
ERR_RESULT("invalid payment amount, must be greater than 0");
return result;
}
if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
{
secret = Parseuint256((char *)params[2].get_str().c_str());
}
hex = ChannelPayment(0,opentxid,amount,secret);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -5604,40 +5701,39 @@ UniValue channelspayment(const UniValue& params, bool fHelp)
return(result);
}
UniValue channelscollect(const UniValue& params, bool fHelp)
UniValue channelsclose(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,paytxid; int32_t n; int64_t amount;
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid;
cp = CCinit(&C,EVAL_CHANNELS);
if ( fHelp || params.size() != 4 )
throw runtime_error("channelscollect paytxid origtxid n amount\n");
if ( fHelp || params.size() != 1 )
throw runtime_error("channelsclose opentxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
paytxid = Parseuint256((char *)params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
n = atoi((char *)params[2].get_str().c_str());
amount = atoi((char *)params[3].get_str().c_str());
hex = ChannelCollect(0,paytxid,origtxid,n,amount);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
opentxid = Parseuint256((char *)params[0].get_str().c_str());
hex = ChannelClose(0,opentxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt create channelscollect transaction");
} else ERR_RESULT("couldnt create channelsclose transaction");
return(result);
}
UniValue channelsrefund(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,stoptxid;
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,closetxid;
cp = CCinit(&C,EVAL_CHANNELS);
if ( fHelp || params.size() != 2 )
throw runtime_error("channelsrefund stoptxid origtxid\n");
throw runtime_error("channelsrefund opentxid closetxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
LOCK(cs_main);
stoptxid = Parseuint256((char *)params[0].get_str().c_str());
origtxid = Parseuint256((char *)params[1].get_str().c_str());
hex = ChannelRefund(0,stoptxid,origtxid);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
opentxid = Parseuint256((char *)params[0].get_str().c_str());
closetxid = Parseuint256((char *)params[1].get_str().c_str());
hex = ChannelRefund(0,opentxid,closetxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -5856,6 +5952,8 @@ UniValue gatewaysbind(const UniValue& params, bool fHelp)
throw runtime_error("gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
tokenid = Parseuint256((char *)params[0].get_str().c_str());
oracletxid = Parseuint256((char *)params[1].get_str().c_str());
coin = params[2].get_str();
@@ -5887,6 +5985,8 @@ UniValue gatewaysdeposit(const UniValue& params, bool fHelp)
throw runtime_error("gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
height = atoi((char *)params[1].get_str().c_str());
coin = params[2].get_str();
@@ -5914,6 +6014,8 @@ UniValue gatewaysclaim(const UniValue& params, bool fHelp)
throw runtime_error("gatewaysclaim bindtxid coin deposittxid destpub amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
deposittxid = Parseuint256((char *)params[2].get_str().c_str());
@@ -5935,11 +6037,13 @@ UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
throw runtime_error("gatewayswithdraw bindtxid coin withdrawpub amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
coin = params[1].get_str();
withdrawpub = ParseHex(params[2].get_str());
amount = atof((char *)params[3].get_str().c_str()) * COIN;
hex = GatewaysWithdraw(0,bindtxid,coin,withdrawpub,amount);
hex = GatewaysWithdraw(0,bindtxid,coin,pubkey2pk(withdrawpub),amount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -5950,13 +6054,17 @@ UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
UniValue gatewaysmarkdone(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 withdrawtxid; std::string hex;
if ( fHelp || params.size() != 1 )
throw runtime_error("gatewaysmarkdone withdrawtxid\n");
UniValue result(UniValue::VOBJ); uint256 withdrawtxid,cointxid; std::string hex,coin;
if ( fHelp || params.size() != 3 )
throw runtime_error("gatewaysmarkdone withdrawtxid coin cointxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
withdrawtxid = Parseuint256((char *)params[0].get_str().c_str());
hex = GatewaysMarkdone(0,withdrawtxid);
coin = params[1].get_str();
cointxid = Parseuint256((char *)params[2].get_str().c_str());
hex = GatewaysMarkdone(0,withdrawtxid,coin,cointxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -5977,6 +6085,40 @@ UniValue gatewayspending(const UniValue& params, bool fHelp)
return(GatewaysPendingWithdraws(bindtxid,coin));
}
UniValue gatewaysmultisig(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; char *txidaddr;
if ( fHelp || params.size() != 1 )
throw runtime_error("gatewaysmultisig txidaddr\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txidaddr = (char *)params[0].get_str().c_str();
return(GatewaysMultisig(txidaddr));
}
UniValue gatewayspartialsign(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string coin,parthex,hex; uint256 txid;
if ( fHelp || params.size() != 3 )
throw runtime_error("gatewayspartialsign txidaddr refcoin hex\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txid = Parseuint256((char *)params[0].get_str().c_str());
coin = params[1].get_str();
parthex = params[2].get_str();
hex = GatewaysPartialSign(0,txid,coin,parthex);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex",hex));
} else ERR_RESULT("couldnt gatewaysmultisig");
return(result);
}
UniValue oracleslist(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() > 0 )
@@ -6004,8 +6146,11 @@ UniValue oraclesregister(const UniValue& params, bool fHelp)
throw runtime_error("oraclesregister oracletxid datafee\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txid = Parseuint256((char *)params[0].get_str().c_str());
datafee = atol((char *)params[1].get_str().c_str());
if ( (datafee= atol((char *)params[1].get_str().c_str())) == 0 )
datafee = atof((char *)params[1].get_str().c_str()) * COIN;
hex = OracleRegister(0,txid,datafee);
if ( hex.size() > 0 )
{
@@ -6022,6 +6167,8 @@ UniValue oraclessubscribe(const UniValue& params, bool fHelp)
throw runtime_error("oraclessubscribe oracletxid publisher amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txid = Parseuint256((char *)params[0].get_str().c_str());
pubkey = ParseHex(params[1].get_str().c_str());
amount = atof((char *)params[2].get_str().c_str()) * COIN;
@@ -6036,7 +6183,7 @@ UniValue oraclessubscribe(const UniValue& params, bool fHelp)
UniValue oraclessamples(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 txid,batontxid; int32_t num;
UniValue result(UniValue::VOBJ); uint256 txid,batontxid; int32_t num;
if ( fHelp || params.size() != 3 )
throw runtime_error("oraclessamples oracletxid batonutxo num\n");
if ( ensure_CCrequirements() < 0 )
@@ -6054,6 +6201,8 @@ UniValue oraclesdata(const UniValue& params, bool fHelp)
throw runtime_error("oraclesdata oracletxid hexstr\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txid = Parseuint256((char *)params[0].get_str().c_str());
data = ParseHex(params[1].get_str().c_str());
hex = OracleData(0,txid,data);
@@ -6092,6 +6241,24 @@ UniValue oraclescreate(const UniValue& params, bool fHelp)
ERR_RESULT("oracles format must be <= 4096 characters");
return(result);
}
// list of oracle valid formats from oracles.cpp -> oracle_format
const UniValue valid_formats[13] = {"s","S","d","D","c","C","t","T","i","I","l","L","h"};
const UniValue header_type = "Ihh";
// checking if oracle data type is valid
bool is_valid_format = false;
for ( int i = 0; i < 13; ++i ) {
if ( valid_formats[i].get_str() == format ) {
is_valid_format = true;
}
}
// additional check for special Ihh data type
if ( format == header_type.get_str() ) {
is_valid_format = true;
}
if ( !is_valid_format ) {
ERR_RESULT("oracles format not valid");
return(result);
}
hex = OracleCreate(0,name,description,format);
if ( hex.size() > 0 )
{
@@ -6190,6 +6357,156 @@ UniValue faucetget(const UniValue& params, bool fHelp)
return(result);
}
UniValue priceslist(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() > 0 )
throw runtime_error("priceslist\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
return(PricesList());
}
UniValue pricesinfo(const UniValue& params, bool fHelp)
{
uint256 fundingtxid;
if ( fHelp || params.size() != 1 )
throw runtime_error("pricesinfo fundingtxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
return(PricesInfo(fundingtxid));
}
UniValue pricescreate(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint64_t mode; int64_t funding; int32_t i,n,margin,maxleverage; std::string hex; uint256 oracletxid,longtoken,shorttoken,bettoken; std::vector<CPubKey> pubkeys; std::vector<uint8_t>pubkey;
if ( fHelp || params.size() < 8 )
throw runtime_error("pricescreate bettoken oracletxid margin mode longtoken shorttoken maxleverage funding N [pubkeys]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bettoken = Parseuint256((char *)params[0].get_str().c_str());
oracletxid = Parseuint256((char *)params[1].get_str().c_str());
margin = atof(params[2].get_str().c_str()) * 1000;
mode = atol(params[3].get_str().c_str());
longtoken = Parseuint256((char *)params[4].get_str().c_str());
shorttoken = Parseuint256((char *)params[5].get_str().c_str());
maxleverage = atol(params[6].get_str().c_str());
funding = atof(params[7].get_str().c_str()) * COIN;
n = atoi(params[8].get_str().c_str());
if ( n > 0 )
{
for (i=0; i<n; i++)
{
if ( params.size() < 9+i+1 )
throw runtime_error("not enough parameters for N pubkeys\n");
pubkey = ParseHex(params[9+i].get_str().c_str());
pubkeys.push_back(pubkey2pk(pubkey));
}
}
hex = PricesCreateFunding(0,bettoken,oracletxid,margin,mode,longtoken,shorttoken,maxleverage,funding,pubkeys);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create prices funding transaction");
}
return(result);
}
UniValue pricesaddfunding(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesaddfunding fundingtxid bettoken amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
amount = atof(params[2].get_str().c_str()) * COIN;
hex = PricesAddFunding(0,bettoken,fundingtxid,amount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesaddfunding transaction");
}
return(result);
}
UniValue pricesbet(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount; int32_t leverage;
if ( fHelp || params.size() != 4 )
throw runtime_error("pricesbet fundingtxid bettoken amount leverage\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
amount = atof(params[2].get_str().c_str()) * COIN;
leverage = atoi(params[3].get_str().c_str());
hex = PricesBet(0,bettoken,fundingtxid,amount,leverage);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesbet transaction");
}
return(result);
}
UniValue pricesstatus(const UniValue& params, bool fHelp)
{
uint256 fundingtxid,bettxid,bettoken;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesstatus fundingtxid bettoken bettxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
bettxid = Parseuint256((char *)params[2].get_str().c_str());
return(PricesStatus(0,bettoken,fundingtxid,bettxid));
}
UniValue pricesfinish(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 fundingtxid,bettxid,bettoken; std::string hex;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesfinish fundingtxid bettoken bettxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
bettxid = Parseuint256((char *)params[2].get_str().c_str());
hex = PricesFinish(0,bettoken,fundingtxid,bettxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesfinish transaction");
}
return(result);
}
UniValue dicefund(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,timeoutblocks; std::string hex; char *name;
@@ -6253,7 +6570,7 @@ UniValue diceaddfunds(const UniValue& params, bool fHelp)
UniValue dicebet(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid; int64_t amount,odds; char *name;
UniValue result(UniValue::VOBJ); std::string hex,error; uint256 fundingtxid; int64_t amount,odds; char *name;
if ( fHelp || params.size() != 4 )
throw runtime_error("dicebet name fundingtxid amount odds\n");
if ( ensure_CCrequirements() < 0 )
@@ -6271,11 +6588,12 @@ UniValue dicebet(const UniValue& params, bool fHelp)
}
if (amount > 0 && odds > 0) {
hex = DiceBet(0,name,fundingtxid,amount,odds);
RETURN_IF_ERROR(CCerror);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt create dice bet transaction. make sure your address has funds");
}
} else {
ERR_RESULT("amount and odds must be positive");
}
@@ -6284,7 +6602,7 @@ UniValue dicebet(const UniValue& params, bool fHelp)
UniValue dicefinish(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string hex; int32_t r;
UniValue result(UniValue::VOBJ); uint8_t funcid; char *name; uint256 entropyused,fundingtxid,bettxid; std::string hex; int32_t r,entropyvout;
if ( fHelp || params.size() != 3 )
throw runtime_error("dicefinish name fundingtxid bettxid\n");
if ( ensure_CCrequirements() < 0 )
@@ -6298,7 +6616,7 @@ UniValue dicefinish(const UniValue& params, bool fHelp)
}
fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
bettxid = Parseuint256((char *)params[2].get_str().c_str());
hex = DiceBetFinish(&r,0,name,fundingtxid,bettxid,1);
hex = DiceBetFinish(funcid,entropyused,entropyvout,&r,0,name,fundingtxid,bettxid,1,zeroid,-1);
if ( CCerror != "" )
{
ERR_RESULT(CCerror);
@@ -6306,13 +6624,20 @@ UniValue dicefinish(const UniValue& params, bool fHelp)
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
if ( funcid != 0 )
{
char funcidstr[2];
funcidstr[0] = funcid;
funcidstr[1] = 0;
result.push_back(Pair("funcid", funcidstr));
}
} else ERR_RESULT( "couldnt create dicefinish transaction");
return(result);
}
UniValue dicestatus(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string status; double winnings;
UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string status,error; double winnings;
if ( fHelp || (params.size() != 2 && params.size() != 3) )
throw runtime_error("dicestatus name fundingtxid bettxid\n");
if ( ensure_CCrequirements() < 0 )
@@ -6329,10 +6654,8 @@ UniValue dicestatus(const UniValue& params, bool fHelp)
if ( params.size() == 3 )
bettxid = Parseuint256((char *)params[2].get_str().c_str());
winnings = DiceStatus(0,name,fundingtxid,bettxid);
if (CCerror != "") {
ERR_RESULT(CCerror);
return result;
}
RETURN_IF_ERROR(CCerror);
result.push_back(Pair("result", "success"));
if ( winnings >= 0. )
{
@@ -6361,7 +6684,6 @@ UniValue dicestatus(const UniValue& params, bool fHelp)
UniValue dicelist(const UniValue& params, bool fHelp)
{
uint256 tokenid;
if ( fHelp || params.size() > 0 )
throw runtime_error("dicelist\n");
if ( ensure_CCrequirements() < 0 )
@@ -6510,6 +6832,42 @@ UniValue tokentransfer(const UniValue& params, bool fHelp)
return(result);
}
UniValue tokenconvert(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; int32_t evalcode; int64_t amount; uint256 tokenid;
if ( fHelp || params.size() != 4 )
throw runtime_error("tokenconvert evalcode tokenid pubkey amount\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
evalcode = atoi(params[0].get_str().c_str());
tokenid = Parseuint256((char *)params[1].get_str().c_str());
std::vector<unsigned char> pubkey(ParseHex(params[2].get_str().c_str()));
amount = atol(params[3].get_str().c_str());
if ( tokenid == zeroid )
{
ERR_RESULT("invalid tokenid");
return(result);
}
if ( amount <= 0 )
{
ERR_RESULT("amount must be positive");
return(result);
}
hex = AssetConvert(0,tokenid,pubkey,amount,evalcode);
if (amount > 0) {
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt convert tokens");
} else {
ERR_RESULT("amount must be positive");
}
return(result);
}
UniValue tokenbid(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); int64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid;
@@ -6759,6 +7117,9 @@ UniValue getbalance64(const UniValue& params, bool fHelp)
{
set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR),b(UniValue::VARR); CTxDestination address;
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
const CKeyStore& keystore = *pwalletMain;
CAmount nValues[64],nValues2[64],nValue,total,total2; int32_t i,segid;
if (!EnsureWalletIsAvailable(fHelp))

View File

@@ -23,7 +23,6 @@
#include "crypter.h"
#include "coins.h"
#include "zcash/zip32.h"
#include "cc/StakeGuard.h"
#include <assert.h>
@@ -1346,8 +1345,7 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult,
if (txout.fSpendable && (UintToArith256(txout.tx->GetVerusPOSHash(&(pBlock->nNonce), txout.i, nHeight, pastHash)) <= target) && (txout.nDepth >= VERUS_MIN_STAKEAGE))
{
if ((!pwinner || UintToArith256(curNonce) > UintToArith256(pBlock->nNonce)) &&
(Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) && (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH)) &&
!cheatList.IsUTXOInList(COutPoint(txout.tx->GetHash(), txout.i), nHeight <= 100 ? 1 : nHeight-100))
(Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) && (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH)))
{
//printf("Found PoS block\nnNonce: %s\n", pBlock->nNonce.GetHex().c_str());
pwinner = &txout;
@@ -1376,10 +1374,8 @@ int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNe
CBlockIndex *tipindex = chainActive.LastTip();
uint32_t stakeHeight = tipindex->GetHeight() + 1;
bool extendedStake = stakeHeight >= Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
if (!extendedStake)
pk = CPubKey();
pk = CPubKey();
bnTarget = lwmaGetNextPOSRequired(tipindex, Params().GetConsensus());
@@ -1398,7 +1394,7 @@ int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNe
const CKeyStore& keystore = *pwalletMain;
txNew.vin.resize(1);
txNew.vout.resize(1);
txfee = extendedStake ? DEFAULT_STAKE_TXFEE : 0;
txfee = 0;
txNew.vin[0].prevout.hash = stakeSource.GetHash();
txNew.vin[0].prevout.n = voutNum;
@@ -1411,62 +1407,10 @@ int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNe
else if (whichType == TX_PUBKEYHASH)
{
txNew.vout[0].scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(vSolutions[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
if (extendedStake && !pk.IsValid())
{
// we need a pubkey, so try to get one from the key ID, if not there, fail
if (!keystore.GetPubKey(CKeyID(uint160(vSolutions[0])), pk))
return 0;
}
}
else
return 0;
// if we are staking with the extended format, add the opreturn data required
if (extendedStake)
{
// set expiry to time out after 100 blocks, so we can remove the transaction if it orphans
txNew.nExpiryHeight = stakeHeight + 100;
uint256 srcBlock = uint256();
CBlockIndex *pSrcIndex;
txNew.vout.push_back(CTxOut());
CTxOut &txOut1 = txNew.vout[1];
txOut1.nValue = 0;
if (!GetTransaction(stakeSource.GetHash(), stakeSource, srcBlock))
return 0;
BlockMap::const_iterator it = mapBlockIndex.find(srcBlock);
if (it == mapBlockIndex.end() || (pSrcIndex = it->second) == 0)
return 0;
// !! DISABLE THIS FOR RELEASE: THIS MAKES A CHEAT TRANSACTION FOR EVERY STAKE FOR TESTING
//CMutableTransaction cheat;
//cheat = CMutableTransaction(txNew);
//printf("TESTING ONLY: THIS SHOULD NOT BE ENABLED FOR RELEASE - MAKING CHEAT TRANSACTION FOR TESTING\n");
//cheat.vout[1].scriptPubKey << OP_RETURN
// << CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, pSrcIndex->GetBlockHash(), pk).AsVector();
// !! DOWN TO HERE
txOut1.scriptPubKey << OP_RETURN
<< CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, tipindex->GetBlockHash(), pk).AsVector();
// !! DISABLE THIS FOR RELEASE: REMOVE THIS TOO
//nValue = cheat.vout[0].nValue = stakeSource.vout[voutNum].nValue - txfee;
//cheat.nLockTime = 0;
//CTransaction cheatConst(cheat);
//SignatureData cheatSig;
//if (!ProduceSignature(TransactionSignatureCreator(&keystore, &cheatConst, 0, nValue, SIGHASH_ALL), stakeSource.vout[voutNum].scriptPubKey, cheatSig, consensusBranchId))
// fprintf(stderr,"failed to create cheat test signature\n");
//else
//{
// uint8_t *ptr;
// UpdateTransaction(cheat,0,cheatSig);
// cheatList.Add(CTxHolder(CTransaction(cheat), tipindex->GetHeight() + 1));
//}
// !! DOWN TO HERE
}
nValue = txNew.vout[0].nValue = stakeSource.vout[voutNum].nValue - txfee;
txNew.nLockTime = 0;
@@ -3076,7 +3020,8 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
// Don't rebroadcast if newer than nTime:
if (wtx.nTimeReceived > nTime)
continue;
if ( (wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME) || wtx.hashBlock.IsNull() )
if ( (wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME) )
{
//LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
//vwtxh.push_back(wtx.GetHash());

View File

@@ -1473,5 +1473,6 @@ public:
SpendingKeyAddResult operator()(const libzcash::InvalidEncoding& no) const;
};
#define RETURN_IF_ERROR(CCerror) if ( CCerror != "" ) { ERR_RESULT(CCerror); return(result); }
#endif // BITCOIN_WALLET_WALLET_H