Merge branch 'FSM' into FSM
This commit is contained in:
@@ -36,7 +36,8 @@ LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
|
||||
endif
|
||||
if TARGET_DARWIN
|
||||
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
|
||||
else
|
||||
endif
|
||||
if TARGET_LINUX
|
||||
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
|
||||
endif
|
||||
|
||||
@@ -203,6 +204,7 @@ BITCOIN_CORE_H = \
|
||||
mruset.h \
|
||||
net.h \
|
||||
netbase.h \
|
||||
notaries_staked.h \
|
||||
noui.h \
|
||||
paymentdisclosure.h \
|
||||
paymentdisclosuredb.h \
|
||||
@@ -286,10 +288,12 @@ libbitcoin_server_a_SOURCES = \
|
||||
bloom.cpp \
|
||||
cc/eval.cpp \
|
||||
cc/import.cpp \
|
||||
cc/importgateway.cpp \
|
||||
cc/CCassetsCore.cpp \
|
||||
cc/CCcustom.cpp \
|
||||
cc/CCtx.cpp \
|
||||
cc/CCutils.cpp \
|
||||
cc/CCtokens.cpp \
|
||||
cc/assets.cpp \
|
||||
cc/faucet.cpp \
|
||||
cc/rewards.cpp \
|
||||
@@ -309,6 +313,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
chain.cpp \
|
||||
checkpoints.cpp \
|
||||
crosschain.cpp \
|
||||
crosschain_authority.cpp \
|
||||
crypto/haraka.h \
|
||||
crypto/haraka_portable.h \
|
||||
crypto/verus_hash.h \
|
||||
@@ -323,6 +328,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
metrics.h \
|
||||
miner.cpp \
|
||||
net.cpp \
|
||||
notaries_staked.cpp \
|
||||
noui.cpp \
|
||||
notarisationdb.cpp \
|
||||
paymentdisclosure.cpp \
|
||||
@@ -383,6 +389,8 @@ libbitcoin_wallet_a_SOURCES = \
|
||||
transaction_builder.cpp \
|
||||
wallet/rpcdisclosure.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
cc/CCtokens.cpp \
|
||||
cc/CCassetsCore.cpp \
|
||||
cc/CCassetstx.cpp \
|
||||
cc/CCtx.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
@@ -483,6 +491,8 @@ libbitcoin_common_a_SOURCES = \
|
||||
script/sign.cpp \
|
||||
script/standard.cpp \
|
||||
transaction_builder.cpp \
|
||||
cc/CCtokensOpRet.cpp \
|
||||
cc/CCutilbits.cpp \
|
||||
$(BITCOIN_CORE_H) \
|
||||
$(LIBZCASH_H)
|
||||
|
||||
@@ -570,6 +580,16 @@ komodod_LDADD += \
|
||||
$(LIBVERUS_PORTABLE_CRYPTO) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
if TARGET_DARWIN
|
||||
komodod_LDADD += libcc.dylib $(LIBSECP256K1)
|
||||
endif
|
||||
if TARGET_WINDOWS
|
||||
komodod_LDADD += libcc.dll $(LIBSECP256K1)
|
||||
endif
|
||||
if TARGET_LINUX
|
||||
komodod_LDADD += libcc.so $(LIBSECP256K1)
|
||||
endif
|
||||
|
||||
if ENABLE_PROTON
|
||||
komodod_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS)
|
||||
endif
|
||||
|
||||
3
src/ac/ilien
Executable file
3
src/ac/ilien
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=ILN $1 $2 $3 $4 $5 $6
|
||||
|
||||
2
src/ac/iln
Executable file
2
src/ac/iln
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=ILN $1 $2 $3 $4 $5 $6
|
||||
2
src/ac/ksb
Executable file
2
src/ac/ksb
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=KSB $1 $2 $3 $4 $5 $6
|
||||
2
src/ac/morty
Executable file
2
src/ac/morty
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=MORTY $1 $2 $3 $4 $5 $6
|
||||
2
src/ac/our
Executable file
2
src/ac/our
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=OUR $1 $2 $3 $4 $5 $6
|
||||
2
src/ac/rick
Executable file
2
src/ac/rick
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=RICK $1 $2 $3 $4 $5 $6
|
||||
2
src/ac/vote2019
Executable file
2
src/ac/vote2019
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=VOTE2019 $1 $2 $3 $4 $5 $6
|
||||
@@ -64,13 +64,10 @@
|
||||
"ac_name": "MESH",
|
||||
"ac_supply": "1000007"
|
||||
},
|
||||
{
|
||||
"ac_name": "MNZ",
|
||||
"ac_supply": "257142858"
|
||||
},
|
||||
{
|
||||
"ac_name": "AXO",
|
||||
"ac_supply": "200000000"
|
||||
"ac_supply": "200000000",
|
||||
"ac_ccactivate": "130000"
|
||||
},
|
||||
{
|
||||
"ac_name": "ETOMIC",
|
||||
@@ -182,7 +179,7 @@
|
||||
"190.114.254.104"
|
||||
]
|
||||
},
|
||||
{
|
||||
{
|
||||
"ac_name": "DION",
|
||||
"ac_supply": "3900000000",
|
||||
"ac_reward": "22260000000",
|
||||
@@ -192,5 +189,79 @@
|
||||
"addnode": [
|
||||
"51.75.124.34"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"ac_name": "KMDICE",
|
||||
"ac_supply": "10500000",
|
||||
"ac_reward": "2500000000",
|
||||
"ac_halving": "210000",
|
||||
"ac_cc": "2",
|
||||
"addressindex": "1",
|
||||
"spentindex": "1",
|
||||
"addnode": [
|
||||
"144.76.217.232"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ac_name": "ZEX",
|
||||
"ac_founders": "1",
|
||||
"ac_reward": "13000000000",
|
||||
"ac_halving": "525600",
|
||||
"ac_cc": "2",
|
||||
"ac_pubkey": "039d4a50cc70d1184e462a22edb3b66385da97cc8059196f8305c184a3e21440af",
|
||||
"addnode": [
|
||||
"5.9.102.210"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ac_name": "KSB",
|
||||
"ac_supply": "1000000000",
|
||||
"ac_end": "1",
|
||||
"ac_public": "1",
|
||||
"addnode": [
|
||||
"37.187.225.231"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ac_name": "OUR",
|
||||
"ac_reward": "1478310502",
|
||||
"ac_halving": "525600",
|
||||
"ac_cc": "42",
|
||||
"ac_supply": "100000000",
|
||||
"ac_perc": "77700",
|
||||
"ac_staked": "93",
|
||||
"ac_pubkey": "02652a3f3e00b3a1875a918314f0bac838d6dd189a346fa623f5efe9541ac0b98c",
|
||||
"ac_public": "1",
|
||||
"addnode": [
|
||||
"51.255.195.65",
|
||||
"217.182.129.38",
|
||||
"37.187.225.231"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ac_name": "ILN",
|
||||
"ac_supply": "10000000000",
|
||||
"ac_cc": "2",
|
||||
"addnode": ["51.75.122.83"]
|
||||
},
|
||||
{
|
||||
"ac_name": "RICK",
|
||||
"ac_supply": "90000000000",
|
||||
"ac_reward": "100000000",
|
||||
"ac_cc": "3",
|
||||
"addnode": ["138.201.136.145"]
|
||||
},
|
||||
{
|
||||
"ac_name": "MORTY",
|
||||
"ac_supply": "90000000000",
|
||||
"ac_reward": "100000000",
|
||||
"ac_cc": "3",
|
||||
"addnode": ["138.201.136.145"]
|
||||
},
|
||||
{
|
||||
"ac_name": "VOTE2019",
|
||||
"ac_supply": "123651638",
|
||||
"ac_public": "1",
|
||||
"addnode": ["95.213.238.98"]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -20,8 +20,7 @@ echo $pubkey
|
||||
./komodod -pubkey=$pubkey -ac_name=KV -ac_supply=1000000 -addnode=78.47.196.146 $1 &
|
||||
./komodod -pubkey=$pubkey -ac_name=CEAL -ac_supply=366666666 -addnode=78.47.196.146 $1 &
|
||||
./komodod -pubkey=$pubkey -ac_name=MESH -ac_supply=1000007 -addnode=78.47.196.146 $1 &
|
||||
./komodod -pubkey=$pubkey -ac_name=MNZ -ac_supply=257142858 -addnode=51.15.138.138 $1 &
|
||||
./komodod -pubkey=$pubkey -ac_name=AXO -ac_supply=200000000 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=AXO -ac_supply=200000000 -ac_ccactivate=130000 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=ETOMIC -ac_supply=100000000 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=BTCH -ac_supply=20998641 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=BEER -ac_supply=100000000 -addnode=78.47.196.146 &
|
||||
@@ -44,3 +43,10 @@ echo $pubkey
|
||||
./komodod -pubkey=$pubkey -ac_name=PGT -ac_supply=10000000 -ac_end=1 -addnode=190.114.254.104 &
|
||||
./komodod -pubkey=$pubkey -ac_name=KMDICE -ac_supply=10500000 -ac_reward=2500000000 -ac_halving=210000 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=144.76.217.232 &
|
||||
./komodod -pubkey=$pubkey -ac_name=DION -ac_supply=3900000000 -ac_reward=22260000000 -ac_staked=100 -ac_cc=1 -ac_end=4300000000 -addnode=51.75.124.34 &
|
||||
./komodod -pubkey=$pubkey -ac_name=ZEX -ac_cc=2 -ac_founders=1 -ac_halving=525600 -ac_reward=13000000000 -ac_pubkey=039d4a50cc70d1184e462a22edb3b66385da97cc8059196f8305c184a3e21440af -addnode=5.9.102.210 &
|
||||
./komodod -pubkey=$pubkey -ac_name=KSB -ac_supply=1000000000 -ac_end=1 -ac_public=1 -addnode=37.187.225.231 &
|
||||
./komodod -pubkey=$pubkey -ac_name=OUR -ac_reward=1478310502 -ac_halving=525600 -ac_cc=42 -ac_supply=100000000 -ac_perc=77700 -ac_staked=93 -ac_pubkey=02652a3f3e00b3a1875a918314f0bac838d6dd189a346fa623f5efe9541ac0b98c -ac_public=1 -addnode=51.255.195.65 -addnode=217.182.129.38 -addnode=37.187.225.231 &
|
||||
./komodod -pubkey=$pubkey -ac_name=ILN -ac_supply=10000000000 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=51.75.122.83 &
|
||||
./komodod -pubkey=$pubkey -ac_name=RICK -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 &
|
||||
./komodod -pubkey=$pubkey -ac_name=MORTY -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 &
|
||||
./komodod -pubkey=$pubkey -ac_name=VOTE2019 -ac_supply=123651638 -ac_public=1 -addnode=95.213.238.98 &
|
||||
|
||||
@@ -296,13 +296,13 @@ CTxDestination CBitcoinAddress::Get() const
|
||||
return CNoDestination();
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const
|
||||
bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const
|
||||
{
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
} else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) {
|
||||
memcpy(&hashBytes, &vchData[0], 20);
|
||||
type = 1;
|
||||
ccflag ? type = 3 : type = 1;
|
||||
return true;
|
||||
} else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) {
|
||||
memcpy(&hashBytes, &vchData[0], 20);
|
||||
@@ -336,6 +336,84 @@ bool CBitcoinAddress::IsScript() const
|
||||
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::Set(const CKeyID& id)
|
||||
{
|
||||
SetData(base58Prefixes[0], &id, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::Set(const CPubKey& key)
|
||||
{
|
||||
CKeyID id = key.GetID();
|
||||
SetData(base58Prefixes[0], &id, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::Set(const CScriptID& id)
|
||||
{
|
||||
SetData(base58Prefixes[1], &id, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::Set(const CTxDestination& dest)
|
||||
{
|
||||
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::IsValid() const
|
||||
{
|
||||
bool fCorrectSize = vchData.size() == 20;
|
||||
bool fKnownVersion = vchVersion == base58Prefixes[0] ||
|
||||
vchVersion == base58Prefixes[1];
|
||||
return fCorrectSize && fKnownVersion;
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::GetKeyID(CKeyID& keyID) const
|
||||
{
|
||||
if (!IsValid() || vchVersion != base58Prefixes[0])
|
||||
return false;
|
||||
uint160 id;
|
||||
memcpy(&id, &vchData[0], 20);
|
||||
keyID = CKeyID(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
CTxDestination CCustomBitcoinAddress::Get() const
|
||||
{
|
||||
if (!IsValid())
|
||||
return CNoDestination();
|
||||
uint160 id;
|
||||
memcpy(&id, &vchData[0], 20);
|
||||
if (vchVersion == base58Prefixes[0])
|
||||
return CKeyID(id);
|
||||
else if (vchVersion == base58Prefixes[1])
|
||||
return CScriptID(id);
|
||||
else
|
||||
return CNoDestination();
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const
|
||||
{
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
} else if (vchVersion == base58Prefixes[0]) {
|
||||
memcpy(&hashBytes, &vchData[0], 20);
|
||||
ccflag ? type = 3 : type = 1;
|
||||
return true;
|
||||
} else if (vchVersion == base58Prefixes[1]) {
|
||||
memcpy(&hashBytes, &vchData[0], 20);
|
||||
type = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCustomBitcoinAddress::IsScript() const
|
||||
{
|
||||
return IsValid() && vchVersion == base58Prefixes[1];
|
||||
}
|
||||
|
||||
void CBitcoinSecret::SetKey(const CKey& vchSecret)
|
||||
{
|
||||
assert(vchSecret.IsValid());
|
||||
|
||||
33
src/base58.h
33
src/base58.h
@@ -130,9 +130,9 @@ public:
|
||||
*/
|
||||
class CBitcoinAddress : public CBase58Data {
|
||||
public:
|
||||
bool Set(const CKeyID &id);
|
||||
bool Set(const CPubKey &key);
|
||||
bool Set(const CScriptID &id);
|
||||
virtual bool Set(const CKeyID &id);
|
||||
virtual bool Set(const CPubKey &key);
|
||||
virtual bool Set(const CScriptID &id);
|
||||
bool Set(const CTxDestination &dest);
|
||||
bool IsValid() const;
|
||||
bool IsValid(const CChainParams ¶ms) const;
|
||||
@@ -147,7 +147,32 @@ public:
|
||||
CTxDestination Get() const;
|
||||
bool GetKeyID(CKeyID &keyID) const;
|
||||
bool GetKeyID_NoCheck(CKeyID& keyID) const;
|
||||
bool GetIndexKey(uint160& hashBytes, int& type) const;
|
||||
bool GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const;
|
||||
bool IsScript() const;
|
||||
};
|
||||
|
||||
class CCustomBitcoinAddress : public CBitcoinAddress {
|
||||
std::vector<unsigned char> base58Prefixes[2];
|
||||
public:
|
||||
bool Set(const CKeyID &id);
|
||||
bool Set(const CPubKey &key);
|
||||
bool Set(const CScriptID &id);
|
||||
bool Set(const CTxDestination &dest);
|
||||
bool IsValid() const;
|
||||
|
||||
CCustomBitcoinAddress() {}
|
||||
CCustomBitcoinAddress(const CTxDestination &dest,uint8_t taddr,uint8_t pubkey_prefix,uint8_t script_prefix)
|
||||
{
|
||||
if (taddr!=0) base58Prefixes[0].push_back(taddr);
|
||||
base58Prefixes[0].push_back(pubkey_prefix);
|
||||
base58Prefixes[1].push_back(script_prefix);
|
||||
Set(dest);
|
||||
}
|
||||
|
||||
CTxDestination Get() const;
|
||||
bool GetKeyID(CKeyID &keyID) const;
|
||||
bool GetKeyID_NoCheck(CKeyID& keyID) const;
|
||||
bool GetIndexKey(uint160& hashBytes, int& type, bool ccflag) const;
|
||||
bool IsScript() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,27 +59,46 @@ static bool fDaemon;
|
||||
#include "komodo_defs.h"
|
||||
#define KOMODO_ASSETCHAIN_MAXLEN 65
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern int32_t ASSETCHAINS_BLOCKTIME;
|
||||
extern uint64_t ASSETCHAINS_CBOPRET;
|
||||
void komodo_passport_iteration();
|
||||
uint64_t komodo_interestsum();
|
||||
int32_t komodo_longestchain();
|
||||
void komodo_cbopretupdate(int32_t forceflag);
|
||||
|
||||
void WaitForShutdown(boost::thread_group* threadGroup)
|
||||
{
|
||||
bool fShutdown = ShutdownRequested();
|
||||
int32_t i; bool fShutdown = ShutdownRequested();
|
||||
// Tell the main threads to shutdown.
|
||||
if ( ASSETCHAINS_CBOPRET != 0 )
|
||||
komodo_pricesinit();
|
||||
while (!fShutdown)
|
||||
{
|
||||
//fprintf(stderr,"call passport iteration\n");
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
{
|
||||
komodo_passport_iteration();
|
||||
MilliSleep(10000);
|
||||
for (i=0; i<10; i++)
|
||||
{
|
||||
fShutdown = ShutdownRequested();
|
||||
if ( fShutdown != 0 )
|
||||
break;
|
||||
MilliSleep(1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//komodo_interestsum();
|
||||
//komodo_longestchain();
|
||||
MilliSleep(20000);
|
||||
if ( ASSETCHAINS_CBOPRET != 0 )
|
||||
komodo_cbopretupdate(0);
|
||||
for (i=0; i<=ASSETCHAINS_BLOCKTIME/5; i++)
|
||||
{
|
||||
fShutdown = ShutdownRequested();
|
||||
if ( fShutdown != 0 )
|
||||
break;
|
||||
MilliSleep(1000);
|
||||
}
|
||||
}
|
||||
fShutdown = ShutdownRequested();
|
||||
}
|
||||
@@ -94,7 +113,8 @@ void WaitForShutdown(boost::thread_group* threadGroup)
|
||||
//
|
||||
// Start
|
||||
//
|
||||
extern int32_t IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,ASSETCHAIN_INIT;
|
||||
extern int32_t IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY;
|
||||
extern uint32_t ASSETCHAIN_INIT;
|
||||
extern std::string NOTARY_PUBKEY;
|
||||
int32_t komodo_is_issuer();
|
||||
void komodo_passport_iteration();
|
||||
|
||||
@@ -212,7 +212,7 @@ bool FaucetExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
|
||||
|
||||
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)
|
||||
int64_t AddFaucetInputs(struct CCcontract_infoCC_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
|
||||
|
||||
std::string FaucetGet(uint64_t txfee)
|
||||
|
||||
|
||||
@@ -18,23 +18,23 @@
|
||||
#define CC_GATEWAYS_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "../merkleblock.h"
|
||||
|
||||
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
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 GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4);
|
||||
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,CPubKey withdrawpub,int64_t amount);
|
||||
std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex);
|
||||
std::string GatewaysCompleteSigning(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex);
|
||||
std::string GatewaysMarkDone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin);
|
||||
UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin);
|
||||
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin);
|
||||
UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin);
|
||||
UniValue GatewaysMultisig(char *txidaddr);
|
||||
|
||||
|
||||
// CCcustom
|
||||
UniValue GatewaysInfo(uint256 bindtxid);
|
||||
UniValue GatewaysExternalAddress(uint256 bindtxid,CPubKey pubkey);
|
||||
UniValue GatewaysDumpPrivKey(uint256 bindtxid,CKey privkey);
|
||||
UniValue GatewaysList();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,12 +18,20 @@
|
||||
#define CC_HEIR_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "CCtokens.h"
|
||||
|
||||
#define EVAL_HEIR 0xea
|
||||
//#define EVAL_HEIR 0xea
|
||||
|
||||
bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
// CCcustom
|
||||
UniValue HeirInfo();
|
||||
class CoinHelper;
|
||||
class TokenHelper;
|
||||
|
||||
UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo);
|
||||
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid);
|
||||
UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
|
||||
UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
|
||||
UniValue HeirInfo(uint256 fundingtxid);
|
||||
UniValue HeirList();
|
||||
|
||||
#endif
|
||||
|
||||
38
src/cc/CCImportGateway.h
Normal file
38
src/cc/CCImportGateway.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef CC_IMPORTGATEWAY_H
|
||||
#define CC_IMPORTGATEWAY_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
// CCcustom
|
||||
bool ImportGatewayValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn);
|
||||
bool ImportGatewayExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
|
||||
std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4);
|
||||
std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t burnvout,std::string rawburntx,std::vector<uint8_t>proof,CPubKey destpub);
|
||||
std::string ImportGatewayWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount);
|
||||
std::string ImportGatewayPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex);
|
||||
std::string ImportGatewayCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex);
|
||||
std::string ImportGatewayMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin);
|
||||
UniValue ImportGatewayPendingDeposits(uint256 bindtxid,std::string refcoin);
|
||||
UniValue ImportGatewayPendingWithdraws(uint256 bindtxid,std::string refcoin);
|
||||
UniValue ImportGatewayProcessedWithdraws(uint256 bindtxid,std::string refcoin);
|
||||
UniValue ImportGatewayExternalAddress(uint256 bindtxid,CPubKey pubkey);
|
||||
UniValue ImportGatewayDumpPrivKey(uint256 bindtxid,CKey key);
|
||||
UniValue ImportGatewayList();
|
||||
UniValue ImportGatewayInfo(uint256 bindtxid);
|
||||
#endif
|
||||
@@ -14,10 +14,30 @@
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef CC_TRIGGERS_H
|
||||
#define CC_TRIGGERS_H
|
||||
#ifndef CC_MARMARA_H
|
||||
#define CC_MARMARA_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "../komodo_cJSON.h"
|
||||
|
||||
#define MARMARA_GROUPSIZE 60
|
||||
#define MARMARA_MINLOCK (1440 * 3 * 30)
|
||||
#define MARMARA_MAXLOCK (1440 * 24 * 30)
|
||||
#define MARMARA_VINS 16
|
||||
#define EVAL_MARMARA 0xef
|
||||
|
||||
extern uint8_t ASSETCHAINS_MARMARA;
|
||||
uint64_t komodo_block_prg(uint32_t nHeight);
|
||||
int32_t MarmaraGetcreatetxid(uint256 &createtxid,uint256 txid);
|
||||
int32_t MarmaraGetbatontxid(std::vector<uint256> &creditloop,uint256 &batontxid,uint256 txid);
|
||||
UniValue MarmaraCreditloop(uint256 txid);
|
||||
UniValue MarmaraSettlement(uint64_t txfee,uint256 batontxid);
|
||||
UniValue MarmaraLock(uint64_t txfee,int64_t amount,int32_t height);
|
||||
|
||||
UniValue MarmaraPoolPayout(uint64_t txfee,int32_t firstheight,double perc,char *jsonstr); // [[pk0, shares0], [pk1, shares1], ...]
|
||||
UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::string currency,int32_t matures,uint256 batontxid,bool automaticflag);
|
||||
UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t amount,std::string currency,int32_t matures,uint256 approvaltxid,uint256 batontxid);
|
||||
UniValue MarmaraInfo(CPubKey refpk,int32_t firstheight,int32_t lastheight,int64_t minamount,int64_t maxamount,std::string currency);
|
||||
|
||||
bool MarmaraValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
|
||||
@@ -19,9 +19,16 @@
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define PAYMENTS_TXFEE 10000
|
||||
|
||||
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
// CCcustom
|
||||
UniValue PaymentsInfo();
|
||||
UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,17 +18,33 @@
|
||||
#define CC_PRICES_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
int32_t komodo_priceget(int64_t *buf64,int32_t ind,int32_t height,int32_t numblocks);
|
||||
|
||||
#define PRICES_DAYWINDOW ((3600*24/ASSETCHAINS_BLOCKTIME) + 1)
|
||||
#define PRICES_TXFEE 10000
|
||||
#define PRICES_MAXLEVERAGE 777
|
||||
#define PRICES_SMOOTHWIDTH 1
|
||||
#define KOMODO_MAXPRICES 2048 // must be power of 2 and less than 8192
|
||||
#define KOMODO_PRICEMASK (~(KOMODO_MAXPRICES - 1))
|
||||
#define PRICES_WEIGHT (KOMODO_MAXPRICES * 1)
|
||||
#define PRICES_MULT (KOMODO_MAXPRICES * 2)
|
||||
#define PRICES_DIV (KOMODO_MAXPRICES * 3)
|
||||
#define PRICES_INV (KOMODO_MAXPRICES * 4)
|
||||
#define PRICES_MDD (KOMODO_MAXPRICES * 5)
|
||||
#define PRICES_MMD (KOMODO_MAXPRICES * 6)
|
||||
#define PRICES_MMM (KOMODO_MAXPRICES * 7)
|
||||
#define PRICES_DDD (KOMODO_MAXPRICES * 8)
|
||||
|
||||
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
// CCcustom
|
||||
UniValue PricesBet(uint64_t txfee,int64_t amount,int16_t leverage,std::vector<std::string> synthetic);
|
||||
UniValue PricesAddFunding(uint64_t txfee,uint256 bettxid,int64_t amount);
|
||||
UniValue PricesSetcostbasis(uint64_t txfee,uint256 bettxid);
|
||||
UniValue PricesRekt(uint64_t txfee,uint256 bettxid,int32_t rektheight);
|
||||
UniValue PricesCashout(uint64_t txfee,uint256 bettxid);
|
||||
UniValue PricesInfo(uint256 bettxid,int32_t refheight);
|
||||
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
|
||||
|
||||
@@ -29,13 +29,10 @@
|
||||
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
// CCassetsCore
|
||||
//CTxOut MakeAssetsVout(CAmount nValue,CPubKey pk);
|
||||
CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description);
|
||||
CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey);
|
||||
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
|
||||
uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey);
|
||||
vscript_t EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
|
||||
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
|
||||
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx);
|
||||
int64_t IsAssetvout(int32_t maxAssetExactAmountDepth, struct CCcontract_info *cp, Eval* eval, int64_t &price,std::vector<uint8_t> &origpubkey,const CTransaction& tx,int32_t v,uint256 refassetid);
|
||||
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid);
|
||||
bool ValidateBidRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
|
||||
bool ValidateAskRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
|
||||
bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
|
||||
@@ -44,18 +41,18 @@ bool SetAskFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValu
|
||||
bool SetSwapFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice);
|
||||
int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid);
|
||||
int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid);
|
||||
bool AssetExactAmounts(int32_t maxDepth, struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid);
|
||||
//bool AssetExactAmounts(bool doValidateTx, struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid, std::vector<CTransaction> &ccVinsTxs);
|
||||
bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid);
|
||||
|
||||
// CCassetstx
|
||||
int64_t GetAssetBalance(CPubKey pk,uint256 tokenid);
|
||||
int64_t AddAssetInputs(CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
|
||||
UniValue AssetOrders(uint256 tokenid);
|
||||
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);
|
||||
//int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); // --> GetTokenBalance()
|
||||
int64_t AddAssetInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 assetid, int64_t total, int32_t maxinputs);
|
||||
|
||||
UniValue AssetOrders(uint256 tokenid, CPubKey pubkey, uint8_t additionalEvalCode);
|
||||
//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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
Yes, this is quite confusing...
|
||||
|
||||
In ValudateAssetRemainder the naming convention is nValue is the coin/asset with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or assets, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits.
|
||||
In ValidateAssetRemainder the naming convention is nValue is the coin/asset with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or assets, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits.
|
||||
|
||||
We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it.
|
||||
*/
|
||||
@@ -43,17 +43,17 @@ bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64
|
||||
int64_t unitprice,recvunitprice,newunitprice=0;
|
||||
if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
|
||||
fprintf(stderr,"ValidateAssetRemainder() orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
|
||||
return(false);
|
||||
}
|
||||
else if ( totalunits != (remaining_units + paidunits) )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_units %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_units + paidunits),(long long)remaining_units,(long long)paidunits);
|
||||
fprintf(stderr,"ValidateAssetRemainder() totalunits %llu != %llu (remaining_units %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_units + paidunits),(long long)remaining_units,(long long)paidunits);
|
||||
return(false);
|
||||
}
|
||||
else if ( orig_nValue != (remaining_nValue + received_nValue) )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
|
||||
fprintf(stderr,"ValidateAssetRemainder() orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
@@ -68,10 +68,10 @@ bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64
|
||||
newunitprice = (remaining_nValue / remaining_units);
|
||||
if ( recvunitprice < unitprice )
|
||||
{
|
||||
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
|
||||
fprintf(stderr,"ValidateAssetRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
|
||||
return(false);
|
||||
}
|
||||
fprintf(stderr,"orig %llu total %llu, recv %llu paid %llu,recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(long long)orig_nValue,(long long)totalunits,(long long)received_nValue,(long long)paidunits,(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
|
||||
fprintf(stderr,"ValidateAssetRemainder() orig %llu total %llu, recv %llu paid %llu,recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(long long)orig_nValue,(long long)totalunits,(long long)received_nValue,(long long)paidunits,(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t
|
||||
paidunits = totalunits;
|
||||
received_nValue = orig_nValue;
|
||||
remaining_units = 0;
|
||||
fprintf(stderr,"totally filled!\n");
|
||||
fprintf(stderr,"SetBidFillamounts() bid order totally filled!\n");
|
||||
return(true);
|
||||
}
|
||||
remaining_units = (totalunits - paidunits);
|
||||
@@ -100,7 +100,7 @@ bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t
|
||||
if ( unitprice > 0 && received_nValue > 0 && received_nValue <= orig_nValue )
|
||||
{
|
||||
remaining_nValue = (orig_nValue - received_nValue);
|
||||
printf("total.%llu - paid.%llu, remaining %llu <- %llu (%llu - %llu)\n",(long long)totalunits,(long long)paidunits,(long long)remaining_nValue,(long long)(orig_nValue - received_nValue),(long long)orig_nValue,(long long)received_nValue);
|
||||
printf("SetBidFillamounts() total.%llu - paid.%llu, remaining %llu <- %llu (%llu - %llu)\n",(long long)totalunits,(long long)paidunits,(long long)remaining_nValue,(long long)(orig_nValue - received_nValue),(long long)orig_nValue,(long long)received_nValue);
|
||||
return(ValidateBidRemainder(remaining_units,remaining_nValue,orig_nValue,received_nValue,paidunits,totalunits));
|
||||
} else return(false);
|
||||
}
|
||||
@@ -118,14 +118,14 @@ bool SetAskFillamounts(int64_t &received_assetoshis,int64_t &remaining_nValue,in
|
||||
paid_nValue = total_nValue;
|
||||
received_assetoshis = orig_assetoshis;
|
||||
remaining_nValue = 0;
|
||||
fprintf(stderr,"totally filled!\n");
|
||||
fprintf(stderr,"SetAskFillamounts() ask order totally filled!\n");
|
||||
return(true);
|
||||
}
|
||||
remaining_nValue = (total_nValue - paid_nValue);
|
||||
dunitprice = ((double)total_nValue / orig_assetoshis);
|
||||
received_assetoshis = (paid_nValue / dunitprice);
|
||||
fprintf(stderr,"remaining_nValue %.8f (%.8f - %.8f)\n",(double)remaining_nValue/COIN,(double)total_nValue/COIN,(double)paid_nValue/COIN);
|
||||
fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
|
||||
fprintf(stderr,"SetAskFillamounts() remaining_nValue %.8f (%.8f - %.8f)\n",(double)remaining_nValue/COIN,(double)total_nValue/COIN,(double)paid_nValue/COIN);
|
||||
fprintf(stderr,"SetAskFillamounts() unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
|
||||
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
|
||||
{
|
||||
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
|
||||
@@ -138,17 +138,17 @@ bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,
|
||||
int64_t unitprice,recvunitprice,newunitprice=0;
|
||||
if ( orig_assetoshis == 0 || received_assetoshis == 0 || paid_nValue == 0 || total_nValue == 0 )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis == %llu || received_assetoshis == %llu || paid_nValue == %llu || total_nValue == %llu\n",(long long)orig_assetoshis,(long long)received_assetoshis,(long long)paid_nValue,(long long)total_nValue);
|
||||
fprintf(stderr,"ValidateAssetRemainder() orig_assetoshis == %llu || received_assetoshis == %llu || paid_nValue == %llu || total_nValue == %llu\n",(long long)orig_assetoshis,(long long)received_assetoshis,(long long)paid_nValue,(long long)total_nValue);
|
||||
return(false);
|
||||
}
|
||||
else if ( total_nValue != (remaining_nValue + paid_nValue) )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: total_nValue %llu != %llu (remaining_nValue %llu + %llu paid_nValue)\n",(long long)total_nValue,(long long)(remaining_nValue + paid_nValue),(long long)remaining_nValue,(long long)paid_nValue);
|
||||
fprintf(stderr,"ValidateAssetRemainder() total_nValue %llu != %llu (remaining_nValue %llu + %llu paid_nValue)\n",(long long)total_nValue,(long long)(remaining_nValue + paid_nValue),(long long)remaining_nValue,(long long)paid_nValue);
|
||||
return(false);
|
||||
}
|
||||
else if ( orig_assetoshis != (remaining_assetoshis + received_assetoshis) )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_assetoshis,(long long)(remaining_assetoshis - received_assetoshis),(long long)remaining_assetoshis,(long long)received_assetoshis);
|
||||
fprintf(stderr,"ValidateAssetRemainder() orig_assetoshis %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_assetoshis,(long long)(remaining_assetoshis - received_assetoshis),(long long)remaining_assetoshis,(long long)received_assetoshis);
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
@@ -159,10 +159,10 @@ bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,
|
||||
newunitprice = (remaining_nValue / remaining_assetoshis);
|
||||
if ( recvunitprice < unitprice )
|
||||
{
|
||||
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
|
||||
fprintf(stderr,"ValidateAskRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
|
||||
return(false);
|
||||
}
|
||||
fprintf(stderr,"got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
|
||||
fprintf(stderr,"ValidateAskRemainder() got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
@@ -172,7 +172,7 @@ bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetosh
|
||||
int64_t remaining_assetoshis; double dunitprice;
|
||||
if ( total_assetoshis2 == 0 )
|
||||
{
|
||||
fprintf(stderr,"total_assetoshis2.0 origsatoshis.%llu paid_assetoshis2.%llu\n",(long long)orig_assetoshis,(long long)paid_assetoshis2);
|
||||
fprintf(stderr,"SetSwapFillamounts() total_assetoshis2.0 origsatoshis.%llu paid_assetoshis2.%llu\n",(long long)orig_assetoshis,(long long)paid_assetoshis2);
|
||||
received_assetoshis = remaining_assetoshis2 = paid_assetoshis2 = 0;
|
||||
return(false);
|
||||
}
|
||||
@@ -181,14 +181,14 @@ bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetosh
|
||||
paid_assetoshis2 = total_assetoshis2;
|
||||
received_assetoshis = orig_assetoshis;
|
||||
remaining_assetoshis2 = 0;
|
||||
fprintf(stderr,"totally filled!\n");
|
||||
fprintf(stderr,"SetSwapFillamounts() swap order totally filled!\n");
|
||||
return(true);
|
||||
}
|
||||
remaining_assetoshis2 = (total_assetoshis2 - paid_assetoshis2);
|
||||
dunitprice = ((double)total_assetoshis2 / orig_assetoshis);
|
||||
received_assetoshis = (paid_assetoshis2 / dunitprice);
|
||||
fprintf(stderr,"remaining_assetoshis2 %llu (%llu - %llu)\n",(long long)remaining_assetoshis2/COIN,(long long)total_assetoshis2/COIN,(long long)paid_assetoshis2/COIN);
|
||||
fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
|
||||
fprintf(stderr,"SetSwapFillamounts() remaining_assetoshis2 %llu (%llu - %llu)\n",(long long)remaining_assetoshis2/COIN,(long long)total_assetoshis2/COIN,(long long)paid_assetoshis2/COIN);
|
||||
fprintf(stderr,"SetSwapFillamounts() unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
|
||||
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
|
||||
{
|
||||
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
|
||||
@@ -201,17 +201,17 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6
|
||||
int64_t unitprice,recvunitprice,newunitprice=0;
|
||||
if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
|
||||
fprintf(stderr,"ValidateAssetRemainder() orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
|
||||
return(false);
|
||||
}
|
||||
else if ( totalunits != (remaining_price + paidunits) )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_price %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_price + paidunits),(long long)remaining_price,(long long)paidunits);
|
||||
fprintf(stderr,"ValidateAssetRemainder() totalunits %llu != %llu (remaining_price %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_price + paidunits),(long long)remaining_price,(long long)paidunits);
|
||||
return(false);
|
||||
}
|
||||
else if ( orig_nValue != (remaining_nValue + received_nValue) )
|
||||
{
|
||||
fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
|
||||
fprintf(stderr,"ValidateAssetRemainder() orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
@@ -222,46 +222,51 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6
|
||||
newunitprice = (remaining_nValue * COIN) / remaining_price;
|
||||
if ( recvunitprice < unitprice )
|
||||
{
|
||||
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
|
||||
fprintf(stderr,"ValidateAssetRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
|
||||
return(false);
|
||||
}
|
||||
fprintf(stderr,"recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
|
||||
fprintf(stderr,"ValidateAssetRemainder() recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
/* use EncodeTokenCreateOpRet instead:
|
||||
CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_ASSETS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description);
|
||||
return(opret);
|
||||
}
|
||||
*/
|
||||
|
||||
CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey)
|
||||
vscript_t EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_ASSETS;
|
||||
assetid = revuint256(assetid);
|
||||
switch ( funcid )
|
||||
vscript_t vopret;
|
||||
uint8_t evalcode = EVAL_ASSETS;
|
||||
|
||||
switch ( assetFuncId )
|
||||
{
|
||||
case 't': case 'x': case 'o':
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid);
|
||||
//case 't': this cannot be here
|
||||
case 'x': case 'o':
|
||||
vopret = /*<< OP_RETURN <<*/ E_MARSHAL(ss << evalcode << assetFuncId);
|
||||
break;
|
||||
case 's': case 'b': case 'S': case 'B':
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << price << origpubkey);
|
||||
vopret = /*<< OP_RETURN <<*/ E_MARSHAL(ss << evalcode << assetFuncId << price << origpubkey);
|
||||
break;
|
||||
case 'E': case 'e':
|
||||
assetid2 = revuint256(assetid2);
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << assetid2 << price << origpubkey);
|
||||
vopret = /*<< OP_RETURN <<*/ E_MARSHAL(ss << evalcode << assetFuncId << assetid2 << price << origpubkey);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"EncodeOpRet: illegal funcid.%02x\n",funcid);
|
||||
opret << OP_RETURN;
|
||||
fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId);
|
||||
//opret << OP_RETURN;
|
||||
break;
|
||||
}
|
||||
return(opret);
|
||||
return(vopret);
|
||||
}
|
||||
|
||||
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description)
|
||||
/* it is for compatibility, do not use this for new contracts (use DecodeTokenCreateOpRet)
|
||||
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t evalcode,funcid,*script;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
@@ -272,190 +277,216 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &or
|
||||
return(true);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
} */
|
||||
|
||||
uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey)
|
||||
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t funcid=0,*script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
memset(&assetid,0,sizeof(assetid));
|
||||
memset(&assetid2,0,sizeof(assetid2));
|
||||
price = 0;
|
||||
if ( script != 0 && script[0] == EVAL_ASSETS )
|
||||
{
|
||||
funcid = script[1];
|
||||
//fprintf(stderr,"decode.[%c]\n",funcid);
|
||||
switch ( funcid )
|
||||
vscript_t vopretAssets; //, vopretAssetsStripped;
|
||||
uint8_t *script, funcId = 0, assetsFuncId = 0, dummyEvalCode, dummyAssetFuncId;
|
||||
uint256 dummyTokenid;
|
||||
std::vector<CPubKey> voutPubkeysDummy;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
tokenid = zeroid;
|
||||
assetid2 = zeroid;
|
||||
price = 0;
|
||||
assetsEvalCode = 0;
|
||||
assetsFuncId = 0;
|
||||
|
||||
// First - decode token opret:
|
||||
funcId = DecodeTokenOpRet(scriptPubKey, dummyEvalCode, tokenid, voutPubkeysDummy, oprets);
|
||||
GetOpretBlob(oprets, OPRETID_ASSETSDATA, vopretAssets);
|
||||
|
||||
LOGSTREAM((char *)"ccassets", CCLOG_DEBUG2, stream << "DecodeAssetTokenOpRet() from DecodeTokenOpRet returned funcId=" << (int)funcId << std::endl);
|
||||
|
||||
if (funcId == 0 || vopretAssets.size() < 2) {
|
||||
LOGSTREAM((char *)"ccassets", CCLOG_INFO, stream << "DecodeAssetTokenOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretAssets.size()=" << vopretAssets.size() << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
//if (!E_UNMARSHAL(vopretAssets, { ss >> vopretAssetsStripped; })) { //strip string size
|
||||
// std::cerr << "DecodeAssetTokenOpRet() could not unmarshal vopretAssetsStripped" << std::endl;
|
||||
// return (uint8_t)0;
|
||||
//}
|
||||
|
||||
// additional check to prevent crash
|
||||
if (vopretAssets.size() >= 2) {
|
||||
|
||||
assetsEvalCode = vopretAssets.begin()[0];
|
||||
assetsFuncId = vopretAssets.begin()[1];
|
||||
|
||||
LOGSTREAM((char *)"ccassets", CCLOG_DEBUG2, stream << "DecodeAssetTokenOpRet() assetsEvalCode=" << (int)assetsEvalCode << " funcId=" << (char)(funcId ? funcId : ' ') << " assetsFuncId=" << (char)(assetsFuncId ? assetsFuncId : ' ') << std::endl);
|
||||
|
||||
if (assetsEvalCode == EVAL_ASSETS)
|
||||
{
|
||||
case 'c': return(funcid);
|
||||
break;
|
||||
case 't': case 'x': case 'o':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid) != 0 )
|
||||
//fprintf(stderr,"DecodeAssetTokenOpRet() decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId);
|
||||
switch (assetsFuncId)
|
||||
{
|
||||
case 'x': case 'o':
|
||||
if (vopretAssets.size() == 2) // no data after 'evalcode assetFuncId' allowed
|
||||
{
|
||||
assetid = revuint256(assetid);
|
||||
return(funcid);
|
||||
return(assetsFuncId);
|
||||
}
|
||||
break;
|
||||
case 's': case 'b': case 'S': case 'B':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> price; ss >> origpubkey) != 0 )
|
||||
if (E_UNMARSHAL(vopretAssets, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0)
|
||||
{
|
||||
assetid = revuint256(assetid);
|
||||
//fprintf(stderr,"got price %llu\n",(long long)price);
|
||||
return(funcid);
|
||||
//fprintf(stderr,"DecodeAssetTokenOpRet() got price %llu\n",(long long)price);
|
||||
return(assetsFuncId);
|
||||
}
|
||||
break;
|
||||
case 'E': case 'e':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
|
||||
if (E_UNMARSHAL(vopretAssets, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0)
|
||||
{
|
||||
//fprintf(stderr,"got price %llu\n",(long long)price);
|
||||
assetid = revuint256(assetid);
|
||||
//fprintf(stderr,"DecodeAssetTokenOpRet() got price %llu\n",(long long)price);
|
||||
assetid2 = revuint256(assetid2);
|
||||
return(funcid);
|
||||
return(assetsFuncId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n",funcid);
|
||||
funcid = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(funcid);
|
||||
|
||||
LOGSTREAM((char *)"ccassets", CCLOG_INFO, stream << "DecodeAssetTokenOpRet() no asset's payload or incorrect assets funcId or evalcode" << " funcId=" << (int)funcId << " vopretAssets.size()=" << vopretAssets.size() << " assetsEvalCode=" << assetsEvalCode << " assetsFuncId=" << assetsFuncId << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// extract sell/buy owner's pubkey from the opret
|
||||
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx)
|
||||
{
|
||||
uint256 assetid,assetid2;
|
||||
if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 )
|
||||
uint8_t evalCode;
|
||||
|
||||
if ( tx.vout.size() > 0 && DecodeAssetTokenOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey) != 0 )
|
||||
return(true);
|
||||
else return(false);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx)
|
||||
|
||||
// Calculate seller/buyer's dest cc address from ask/bid tx funcid
|
||||
bool GetAssetorigaddrs(struct CCcontract_info *cp, char *origCCaddr, char *origNormalAddr, const CTransaction& vintx)
|
||||
{
|
||||
uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector<uint8_t> origpubkey; CScript script;
|
||||
n = tx.vout.size();
|
||||
if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
|
||||
uint256 assetid, assetid2;
|
||||
int64_t price,nValue=0;
|
||||
int32_t n;
|
||||
uint8_t vintxFuncId;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
CScript script;
|
||||
uint8_t evalCode;
|
||||
|
||||
n = vintx.vout.size();
|
||||
if( n == 0 || (vintxFuncId = DecodeAssetTokenOpRet(vintx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 )
|
||||
return(false);
|
||||
if ( GetCCaddress(cp,CCaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 )
|
||||
|
||||
bool bGetCCaddr = false;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
if (vintxFuncId == 's' || vintxFuncId == 'S') {
|
||||
// bGetCCaddr = GetCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey));
|
||||
cpTokens->additionalTokensEvalcode2 = cp->additionalTokensEvalcode2; // add non-fungible if present
|
||||
bGetCCaddr = GetTokensCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey)); // tokens to single-eval token or token+nonfungible
|
||||
}
|
||||
else if (vintxFuncId == 'b' || vintxFuncId == 'B') {
|
||||
cpTokens->additionalTokensEvalcode2 = cp->additionalTokensEvalcode2; // add non-fungible if present
|
||||
bGetCCaddr = GetTokensCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey)); // tokens to single-eval token or token+nonfungible
|
||||
}
|
||||
else {
|
||||
std::cerr << "GetAssetorigaddrs incorrect vintx funcid=" << (char)(vintxFuncId?vintxFuncId:' ') << std::endl;
|
||||
return false;
|
||||
}
|
||||
if( bGetCCaddr && Getscriptaddress(origNormalAddr, CScript() << origpubkey << OP_CHECKSIG))
|
||||
return(true);
|
||||
else return(false);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
// Checks if the vout is a really Asset CC vout
|
||||
// if maxAssetExactAmountDepth > 0, it also validates the vin transaction itself:
|
||||
// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx
|
||||
int64_t IsAssetvout(int32_t maxAssetExactAmountDepth, struct CCcontract_info *cp, Eval* eval, int64_t &price,std::vector<uint8_t> &origpubkey,const CTransaction& tx,int32_t v,uint256 refassetid)
|
||||
int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *origCCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
|
||||
{
|
||||
uint256 assetid,assetid2; int64_t nValue=0; int32_t n; uint8_t funcid;
|
||||
uint256 hashBlock;
|
||||
uint256 assetid, assetid2;
|
||||
int64_t tmpprice;
|
||||
std::vector<uint8_t> tmporigpubkey;
|
||||
uint8_t evalCode;
|
||||
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) // maybe check address too?
|
||||
{
|
||||
char destaddr[64], unspendableAddr[64];
|
||||
|
||||
if (maxAssetExactAmountDepth > 0) {
|
||||
//validate all tx
|
||||
int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0;
|
||||
std::vector<CTransaction> ccVinsTxs;
|
||||
|
||||
//std::cerr << "IsAssetvout() validate=yes" << std::endl;
|
||||
const bool validateVinTxs = false;
|
||||
bool isEqualAmounts = AssetExactAmounts(maxAssetExactAmountDepth, cp, myCCVinsAmount, 0, myCCVoutsAmount, eval, tx, refassetid);
|
||||
|
||||
// if ccInputs != ccOutputs and it is not the tokenbase tx means it is possibly fake tx (dimxy):
|
||||
if (!isEqualAmounts && refassetid != tx.GetHash()) { // checking that this is the true tokenbase tx, by verifying that funcid=c, is done further in this function (dimxy)
|
||||
std::cerr << "IsAssetvout() detected bad tx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
origaddr[0] = destaddr[0] = origCCaddr[0] = 0;
|
||||
|
||||
uint8_t funcid = 0;
|
||||
if (tx.vout.size() > 0) {
|
||||
uint256 assetid, assetid2;
|
||||
int64_t tmpprice;
|
||||
std::vector<uint8_t> tmporigpubkey;
|
||||
uint8_t evalCode;
|
||||
|
||||
n = tx.vout.size();
|
||||
if (v >= n - 1) { // just moved this up (dimxy)
|
||||
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
|
||||
return(0);
|
||||
}
|
||||
nValue = tx.vout[v].nValue;
|
||||
funcid = DecodeAssetTokenOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey);
|
||||
}
|
||||
|
||||
// fprintf(stderr,"IsAssetvout() CC vout v.%d of n=%d amount=%.8f\n",v,n,(double)nValue/COIN);
|
||||
|
||||
if ( (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"IsAssetvout() null decodeopret v.%d\n",v);
|
||||
return(0);
|
||||
}
|
||||
else if ( funcid == 'c' )
|
||||
{
|
||||
if (refassetid == tx.GetHash() && v == 0) {
|
||||
std::cerr << "isAssetVout() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " returning nValue=" << nValue << std::endl;
|
||||
return(nValue);
|
||||
}
|
||||
}
|
||||
else if ( (funcid == 'b' || funcid == 'B') && v == 0 ) // critical! 'b'/'B' vout0 is NOT asset
|
||||
return(0);
|
||||
else if ( funcid != 'E' )
|
||||
{
|
||||
if ( assetid == refassetid )
|
||||
{
|
||||
fprintf(stderr,"IsAssetvout() returning %.8f\n",(double)nValue/COIN);
|
||||
return(nValue);
|
||||
}
|
||||
}
|
||||
else if ( funcid == 'E' )
|
||||
{
|
||||
if ( v < 2 && assetid == refassetid )
|
||||
return(nValue);
|
||||
else if ( v == 2 && assetid2 == refassetid )
|
||||
return(nValue);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"Isassetvout: normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
|
||||
{
|
||||
uint256 hashBlock; char destaddr[64];
|
||||
origaddr[0] = destaddr[0] = CCaddr[0] = 0;
|
||||
if ( tx.vin.size() < 2 )
|
||||
if( tx.vin.size() < 2 )
|
||||
return eval->Invalid("not enough for CC vins");
|
||||
else if ( tx.vin[vini].prevout.n != 0 )
|
||||
else if( tx.vin[vini].prevout.n != 0 )
|
||||
return eval->Invalid("vin1 needs to be buyvin.vout[0]");
|
||||
else if ( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
else if( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash, vinTx,hashBlock) == 0 )
|
||||
{
|
||||
int32_t z;
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&tx.vin[vini].prevout.hash)[z]);
|
||||
fprintf(stderr," vini.%d\n",vini);
|
||||
std::cerr << "AssetValidateCCvin() cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl;
|
||||
return eval->Invalid("always should find CCvin, but didnt");
|
||||
}
|
||||
else if ( Getscriptaddress(destaddr,vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 )
|
||||
// check source cc unspendable cc address:
|
||||
// if fillSell or cancelSell --> should spend tokens from dual-eval token-assets unspendable addr
|
||||
else if( (funcid == 'S' || funcid == 'x') &&
|
||||
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
|
||||
!GetTokensCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
|
||||
strcmp(destaddr, unspendableAddr) != 0))
|
||||
{
|
||||
fprintf(stderr,"%s vs %s\n",destaddr,(char *)cp->unspendableCCaddr);
|
||||
return eval->Invalid("invalid vin AssetsCCaddr");
|
||||
fprintf(stderr,"AssetValidateCCvin() cc addr %s is not dual token-evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
|
||||
return eval->Invalid("invalid vin assets CCaddr");
|
||||
}
|
||||
// if fillBuy or cancelBuy --> should spend coins from asset unspendable addr
|
||||
else if ((funcid == 'B' || funcid == 'o') &&
|
||||
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
|
||||
!GetCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
|
||||
strcmp(destaddr, unspendableAddr) != 0))
|
||||
{
|
||||
fprintf(stderr, "AssetValidateCCvin() cc addr %s is not evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
|
||||
return eval->Invalid("invalid vin assets CCaddr");
|
||||
}
|
||||
// end of check source unspendable cc address
|
||||
//else if ( vinTx.vout[0].nValue < 10000 )
|
||||
// return eval->Invalid("invalid dust for buyvin");
|
||||
else if ( GetAssetorigaddrs(cp,CCaddr,origaddr,vinTx) == 0 )
|
||||
// get user dest cc and normal addresses:
|
||||
else if( GetAssetorigaddrs(cp, origCCaddr, origaddr, vinTx) == 0 )
|
||||
return eval->Invalid("couldnt get origaddr for buyvin");
|
||||
fprintf(stderr,"Got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
|
||||
|
||||
//fprintf(stderr,"AssetValidateCCvin() got %.8f to origaddr.(%s)\n", (double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
|
||||
|
||||
if ( vinTx.vout[0].nValue == 0 )
|
||||
return eval->Invalid("null value CCvin");
|
||||
|
||||
return(vinTx.vout[0].nValue);
|
||||
}
|
||||
|
||||
int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid)
|
||||
{
|
||||
CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid;
|
||||
CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode;
|
||||
|
||||
CCaddr[0] = origaddr[0] = 0;
|
||||
if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
|
||||
return(0);
|
||||
|
||||
// validate locked coins on Assets vin[1]
|
||||
if ( (nValue= AssetValidateCCvin(cp, eval, CCaddr, origaddr, tx, 1, vinTx)) == 0 )
|
||||
return(0);
|
||||
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("invalid normal vout0 for buyvin");
|
||||
else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' &&
|
||||
vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'?
|
||||
return eval->Invalid("invalid normal vout1 for buyvin");
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr);
|
||||
if ( vinTx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,assetid,assetid2,tmpprice,tmporigpubkey)) != 'b' && funcid != 'B' )
|
||||
if ( vinTx.vout.size() > 0 && funcid != 'b' && funcid != 'B' )
|
||||
return eval->Invalid("invalid opreturn for buyvin");
|
||||
else if ( refassetid != assetid )
|
||||
return eval->Invalid("invalid assetid for buyvin");
|
||||
@@ -469,88 +500,151 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr
|
||||
int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid)
|
||||
{
|
||||
CTransaction vinTx; int64_t nValue,assetoshis;
|
||||
fprintf(stderr,"AssetValidateSellvin\n");
|
||||
if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
|
||||
//fprintf(stderr,"AssetValidateSellvin()\n");
|
||||
if ( (nValue = AssetValidateCCvin(cp, eval, CCaddr, origaddr, tx, 1, vinTx)) == 0 )
|
||||
return(0);
|
||||
if ( (assetoshis= IsAssetvout(1, cp, NULL, tmpprice,tmporigpubkey,vinTx,0,assetid)) == 0 )
|
||||
if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey, vinTx, 0, assetid)) == 0 )
|
||||
return eval->Invalid("invalid missing CC vout0 for sellvin");
|
||||
else return(assetoshis);
|
||||
else
|
||||
return(assetoshis);
|
||||
}
|
||||
|
||||
|
||||
// overload with additional params for deep tx validation (dimxy)
|
||||
bool AssetExactAmounts(int maxDepth, struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid)
|
||||
// validates opret for asset tx:
|
||||
bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &price, std::vector<uint8_t> &origpubkey) {
|
||||
|
||||
uint256 assetidOpret, assetidOpret2;
|
||||
uint8_t funcid, evalCode;
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
int32_t n = tx.vout.size();
|
||||
|
||||
if ((funcid = DecodeAssetTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0)
|
||||
{
|
||||
std::cerr << "ValidateAssetOpret() DecodeAssetTokenOpRet returned funcId=0 for opret from txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return(false);
|
||||
}
|
||||
/* it is now on token level:
|
||||
else if (funcid == 'c')
|
||||
{
|
||||
if (assetid != zeroid && assetid == tx.GetHash() && v == 0) {
|
||||
//std::cerr << "ValidateAssetOpret() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
else if (funcid == 't') // TODO: check if this new block does not influence IsAssetVout
|
||||
{
|
||||
//std::cerr << "ValidateAssetOpret() assetid=" << assetid.GetHex() << " assetIdOpret=" << assetidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
if (assetid != zeroid && assetid == assetidOpret) {
|
||||
//std::cerr << "ValidateAssetOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl;
|
||||
return(true);
|
||||
}
|
||||
} */
|
||||
//else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset
|
||||
// return(false);
|
||||
else if (funcid != 'E')
|
||||
{
|
||||
if (assetid != zeroid && assetidOpret == assetid)
|
||||
{
|
||||
//std::cerr << "ValidateAssetOpret() returns true for not 'E', funcid=" << (char)funcid << std::endl;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
else if (funcid == 'E') // NOTE: not implemented yet!
|
||||
{
|
||||
if (v < 2 && assetid != zeroid && assetidOpret == assetid)
|
||||
return(true);
|
||||
else if (v == 2 && assetid != zeroid && assetidOpret2 == assetid)
|
||||
return(true);
|
||||
}
|
||||
|
||||
//std::cerr << "ValidateAssetOpret() return false funcid=" << (char)funcid << " assetid=" << assetid.GetHex() << " assetIdOpret=" << assetidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks if the vout is a really Asset CC vout
|
||||
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid)
|
||||
{
|
||||
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;
|
||||
|
||||
maxDepth--;
|
||||
//std::cerr << "IsAssetvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for assetid=" << refassetid.GetHex() << std::endl;
|
||||
|
||||
for (i=starti; i<numvins; i++)
|
||||
{
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
//std::cerr << "AssetExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
|
||||
// we are really not inside validation! -- dimxy
|
||||
if ( (eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)) )
|
||||
{
|
||||
fprintf(stderr,"AssetExactAmounts() cannot read vintx i.%d starti.%d numvins.%d\n", i,starti,numvins);
|
||||
return (!eval) ? false : eval->Invalid("always should find vin, but didnt");
|
||||
|
||||
} // false means 'don't go deeper' -- dimxy
|
||||
else if ( (assetoshis= IsAssetvout( maxDepth, cp, eval, tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"AssetExactAmounts() 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,"AssetExactAmounts() vin%d assetoshis=%llu special case, ",i,(long long)assetoshis);
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
int32_t n = tx.vout.size();
|
||||
// just check boundaries:
|
||||
if (v >= n - 1) { // just moved this up (dimxy)
|
||||
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here
|
||||
{
|
||||
// moved opret checking to this new reusable func (dimxy):
|
||||
const bool valOpret = ValidateAssetOpret(tx, v, refassetid, price, origpubkey);
|
||||
//std::cerr << "IsAssetvout() ValidateAssetOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl;
|
||||
if (valOpret) {
|
||||
//std::cerr << "IsAssetvout() ValidateAssetOpret returned true, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
|
||||
if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid )
|
||||
flag = 1;
|
||||
else flag = 0;
|
||||
//fprintf(stderr,"IsAssetvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str());
|
||||
}
|
||||
//fprintf(stderr,"IsAssetvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
for (i=0; i<numvouts; i++)
|
||||
{ // 'false' means 'dont go deep' -- dimxy
|
||||
if ( (assetoshis= IsAssetvout(maxDepth, cp, eval, tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"AssetExactAmounts() vout%d assetoshis=%llu, ",i,(long long)assetoshis);
|
||||
outputs += assetoshis;
|
||||
}
|
||||
// Note: account it only if this is 'transfer' tx -- dimxy
|
||||
else if ( flag != 0 && tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
assetoshis = tx.vout[i].nValue;
|
||||
fprintf(stderr,"AssetExactAmounts() vout%d assetoshis=%llu special case, ",i,(long long)assetoshis);
|
||||
outputs += assetoshis;
|
||||
}
|
||||
}
|
||||
// sets cc inputs vs cc outputs and ensures they are equal:
|
||||
bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid)
|
||||
{
|
||||
CTransaction vinTx; uint256 hashBlock, id, id2; int32_t flag; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
|
||||
int32_t numvins = tx.vin.size();
|
||||
int32_t numvouts = tx.vout.size();
|
||||
inputs = outputs = 0;
|
||||
|
||||
//std::cerr << "AssetExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
struct CCcontract_info *cpTokens, C;
|
||||
|
||||
if ( inputs != outputs )
|
||||
{
|
||||
std::cerr << "AssetExactAmounts() incorrect inputs=" << (double)inputs / COIN << " vs outputs=" << (double)outputs/COIN << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return(false);
|
||||
}
|
||||
else return(true);
|
||||
cpTokens = CCinit(&C, EVAL_TOKENS);
|
||||
|
||||
for (int32_t i = 0; i<numvins; i++)
|
||||
{ // only tokens are relevant!!
|
||||
if (/*(*cpAssets->ismyvin)(tx.vin[i].scriptSig)*/ (*cpTokens->ismyvin)(tx.vin[i].scriptSig) ) // || IsVinAllowed(tx.vin[i].scriptSig) != 0)
|
||||
{
|
||||
//std::cerr << indentStr << "AssetExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
|
||||
// we are not inside the validation code -- dimxy
|
||||
if ((eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)))
|
||||
{
|
||||
std::cerr << "AssetCalcAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl;
|
||||
return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt");
|
||||
}
|
||||
else {
|
||||
// validate vouts of vintx
|
||||
//std::cerr << indentStr << "AssetExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl;
|
||||
//assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, vinTx, tx.vin[i].prevout.n, assetid);
|
||||
std::vector<uint8_t> vopretExtra;
|
||||
std::vector<CPubKey> vinPubkeysEmpty;
|
||||
|
||||
// TODO: maybe we do not need call to IsTokensVout here, cause we've already selected token vins
|
||||
assetoshis = IsTokensvout(false, false, cpTokens, NULL, vinTx, tx.vin[i].prevout.n, assetid);
|
||||
if (assetoshis != 0)
|
||||
{
|
||||
//std::cerr << "AssetCalcAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl;
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < numvouts-1; i++)
|
||||
{
|
||||
assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, tx, i, assetid);
|
||||
if (assetoshis != 0)
|
||||
{
|
||||
//std::cerr << "AssetCalcAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl;
|
||||
outputs += assetoshis;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "AssetCalcAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
|
||||
/* we do not verify inputs == outputs here,
|
||||
it's now done in Tokens */
|
||||
return(true);
|
||||
}
|
||||
|
||||
// overload for existing calls of this function (dimxy)
|
||||
/*bool AssetExactAmounts(struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid) {
|
||||
std::vector<CTransaction> ccVinsTxs;
|
||||
|
||||
return AssetExactAmounts(true, cp, inputs, starti, outputs, eval, tx, assetid);
|
||||
}*/
|
||||
|
||||
@@ -14,181 +14,150 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCassets.h"
|
||||
#include "CCtokens.h"
|
||||
|
||||
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 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;
|
||||
if ( j != mtx.vin.size() )
|
||||
continue;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey);
|
||||
if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
|
||||
continue;
|
||||
fprintf(stderr,"AddAssetInputs() check destaddress=%s vout amount=%.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN);
|
||||
if ( (nValue= IsAssetvout(1, cp, NULL, price,origpubkey,vintx,vout,assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
nValue = it->second.satoshis;
|
||||
totalinputs += nValue;
|
||||
//std::cerr << "AddAssetInputs() adding input nValue=" << nValue << std::endl;
|
||||
n++;
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "AddAssetInputs() found totalinputs=" << totalinputs << std::endl;
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
int64_t GetAssetBalance(CPubKey pk,uint256 tokenid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
return(AddAssetInputs(cp,mtx,pk,tokenid,0,0));
|
||||
}
|
||||
|
||||
UniValue AssetInfo(uint256 assetid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description; char str[67],numstr[65];
|
||||
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find assetid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","cant find assetid"));
|
||||
return(result);
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
|
||||
{
|
||||
fprintf(stderr,"assetid isnt assetcreation txid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","assetid isnt assetcreation txid"));
|
||||
}
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("tokenid",uint256_str(str,assetid)));
|
||||
result.push_back(Pair("owner",pubkey33_str(str,origpubkey.data())));
|
||||
result.push_back(Pair("name",name));
|
||||
result.push_back(Pair("supply",vintx.vout[0].nValue));
|
||||
result.push_back(Pair("description",description));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue AssetList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description; char str[65];
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
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 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 )
|
||||
{
|
||||
result.push_back(uint256_str(str,txid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue AssetOrders(uint256 refassetid)
|
||||
UniValue AssetOrders(uint256 refassetid, CPubKey pk, uint8_t additionalEvalCode)
|
||||
{
|
||||
static uint256 zero;
|
||||
int64_t price; uint256 txid,hashBlock,assetid,assetid2; std::vector<uint8_t> origpubkey; CTransaction vintx; UniValue result(UniValue::VARR); std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; uint8_t funcid; char numstr[32],funcidstr[16],origaddr[64],assetidstr[65]; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
SetCCunspents(unspentOutputs,(char *)cp->unspendableCCaddr);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
UniValue result(UniValue::VARR);
|
||||
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
auto addOrders = [&](struct CCcontract_info *cp, std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it)
|
||||
{
|
||||
uint256 txid, hashBlock, assetid, assetid2;
|
||||
int64_t price;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
CTransaction ordertx;
|
||||
uint8_t funcid, evalCode;
|
||||
char numstr[32], funcidstr[16], origaddr[64], origtokenaddr[64], assetidstr[65];
|
||||
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() checking txid=" << txid.GetHex() << std::endl);
|
||||
if ( GetTransaction(txid, ordertx, hashBlock, false) != 0 )
|
||||
{
|
||||
if ( vintx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey)) != 0 )
|
||||
// for logging: funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey);
|
||||
if (ordertx.vout.size() > 0 && (funcid = DecodeAssetTokenOpRet(ordertx.vout[ordertx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
|
||||
{
|
||||
if ( refassetid != zero && assetid != refassetid )
|
||||
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() checking ordertx.vout.size()=" << ordertx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl);
|
||||
|
||||
if (refassetid != zero && assetid == refassetid ||
|
||||
pk != CPubKey() && pk == pubkey2pk(origpubkey) && (funcid == 'S' || funcid == 's'))
|
||||
{
|
||||
//int32_t z;
|
||||
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&txid)[z]);
|
||||
//fprintf(stderr," txid\n");
|
||||
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&assetid)[z]);
|
||||
//fprintf(stderr," assetid\n");
|
||||
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&refassetid)[z]);
|
||||
//fprintf(stderr," refassetid\n");
|
||||
continue;
|
||||
}
|
||||
if ( vintx.vout[it->first.index].nValue == 0 )
|
||||
continue;
|
||||
UniValue item(UniValue::VOBJ);
|
||||
funcidstr[0] = funcid;
|
||||
funcidstr[1] = 0;
|
||||
item.push_back(Pair("funcid", funcidstr));
|
||||
item.push_back(Pair("txid", uint256_str(assetidstr,txid)));
|
||||
item.push_back(Pair("vout", (int64_t)it->first.index));
|
||||
if ( funcid == 'b' || funcid == 'B' )
|
||||
{
|
||||
sprintf(numstr,"%.8f",(double)vintx.vout[it->first.index].nValue/COIN);
|
||||
item.push_back(Pair("amount",numstr));
|
||||
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
|
||||
item.push_back(Pair("bidamount",numstr));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(numstr,"%llu",(long long)vintx.vout[it->first.index].nValue);
|
||||
item.push_back(Pair("amount",numstr));
|
||||
sprintf(numstr,"%llu",(long long)vintx.vout[0].nValue);
|
||||
item.push_back(Pair("askamount",numstr));
|
||||
}
|
||||
if ( origpubkey.size() == 33 )
|
||||
{
|
||||
GetCCaddress(cp,origaddr,pubkey2pk(origpubkey));
|
||||
item.push_back(Pair("origaddress",origaddr));
|
||||
}
|
||||
if ( assetid != zeroid )
|
||||
item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid)));
|
||||
if ( assetid2 != zeroid )
|
||||
item.push_back(Pair("otherid",uint256_str(assetidstr,assetid2)));
|
||||
if ( price > 0 )
|
||||
{
|
||||
if ( funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e' )
|
||||
|
||||
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() it->first.index=" << it->first.index << " ordertx.vout[it->first.index].nValue=" << ordertx.vout[it->first.index].nValue << std::endl);
|
||||
if (ordertx.vout[it->first.index].nValue == 0) {
|
||||
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() order with value=0 skipped" << std::endl);
|
||||
return;
|
||||
}
|
||||
|
||||
UniValue item(UniValue::VOBJ);
|
||||
|
||||
funcidstr[0] = funcid;
|
||||
funcidstr[1] = 0;
|
||||
item.push_back(Pair("funcid", funcidstr));
|
||||
item.push_back(Pair("txid", uint256_str(assetidstr, txid)));
|
||||
item.push_back(Pair("vout", (int64_t)it->first.index));
|
||||
if (funcid == 'b' || funcid == 'B')
|
||||
{
|
||||
sprintf(numstr,"%.8f",(double)price / COIN);
|
||||
item.push_back(Pair("totalrequired", numstr));
|
||||
sprintf(numstr,"%.8f",(double)price / (COIN * vintx.vout[0].nValue));
|
||||
item.push_back(Pair("price", numstr));
|
||||
sprintf(numstr, "%.8f", (double)ordertx.vout[it->first.index].nValue / COIN);
|
||||
item.push_back(Pair("amount", numstr));
|
||||
sprintf(numstr, "%.8f", (double)ordertx.vout[0].nValue / COIN);
|
||||
item.push_back(Pair("bidamount", numstr));
|
||||
}
|
||||
else
|
||||
{
|
||||
item.push_back(Pair("totalrequired", (int64_t)price));
|
||||
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue / (price * COIN));
|
||||
item.push_back(Pair("price",numstr));
|
||||
sprintf(numstr, "%llu", (long long)ordertx.vout[it->first.index].nValue);
|
||||
item.push_back(Pair("amount", numstr));
|
||||
sprintf(numstr, "%llu", (long long)ordertx.vout[0].nValue);
|
||||
item.push_back(Pair("askamount", numstr));
|
||||
}
|
||||
if (origpubkey.size() == 33)
|
||||
{
|
||||
GetCCaddress(cp, origaddr, pubkey2pk(origpubkey));
|
||||
item.push_back(Pair("origaddress", origaddr));
|
||||
GetTokensCCaddress(cpTokens, origtokenaddr, pubkey2pk(origpubkey));
|
||||
item.push_back(Pair("origtokenaddress", origtokenaddr));
|
||||
|
||||
}
|
||||
if (assetid != zeroid)
|
||||
item.push_back(Pair("tokenid", uint256_str(assetidstr, assetid)));
|
||||
if (assetid2 != zeroid)
|
||||
item.push_back(Pair("otherid", uint256_str(assetidstr, assetid2)));
|
||||
if (price > 0)
|
||||
{
|
||||
if (funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e')
|
||||
{
|
||||
sprintf(numstr, "%.8f", (double)price / COIN);
|
||||
item.push_back(Pair("totalrequired", numstr));
|
||||
sprintf(numstr, "%.8f", (double)price / (COIN * ordertx.vout[0].nValue));
|
||||
item.push_back(Pair("price", numstr));
|
||||
}
|
||||
else
|
||||
{
|
||||
item.push_back(Pair("totalrequired", (int64_t)price));
|
||||
sprintf(numstr, "%.8f", (double)ordertx.vout[0].nValue / (price * COIN));
|
||||
item.push_back(Pair("price", numstr));
|
||||
}
|
||||
}
|
||||
result.push_back(item);
|
||||
LOGSTREAM("ccassets", CCLOG_DEBUG1, stream << "addOrders() added order funcId=" << (char)(funcid ? funcid : ' ') << " it->first.index=" << it->first.index << " ordertx.vout[it->first.index].nValue=" << ordertx.vout[it->first.index].nValue << " tokenid=" << assetid.GetHex() << std::endl);
|
||||
}
|
||||
result.push_back(item);
|
||||
//fprintf(stderr,"func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputsTokens, unspentOutputsDualEvalTokens, unspentOutputsCoins;
|
||||
|
||||
char assetsUnspendableAddr[64];
|
||||
GetCCaddress(cpAssets, assetsUnspendableAddr, GetUnspendable(cpAssets, NULL));
|
||||
SetCCunspents(unspentOutputsCoins, assetsUnspendableAddr,true);
|
||||
|
||||
char assetsTokensUnspendableAddr[64];
|
||||
std::vector<uint8_t> vopretNonfungible;
|
||||
if (refassetid != zeroid) {
|
||||
GetNonfungibleData(refassetid, vopretNonfungible);
|
||||
if (vopretNonfungible.size() > 0)
|
||||
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
|
||||
}
|
||||
GetTokensCCaddress(cpAssets, assetsTokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
|
||||
SetCCunspents(unspentOutputsTokens, assetsTokensUnspendableAddr,true);
|
||||
|
||||
// tokenbids:
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itCoins = unspentOutputsCoins.begin();
|
||||
itCoins != unspentOutputsCoins.end();
|
||||
itCoins++)
|
||||
addOrders(cpAssets, itCoins);
|
||||
|
||||
// tokenasks:
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itTokens = unspentOutputsTokens.begin();
|
||||
itTokens != unspentOutputsTokens.end();
|
||||
itTokens++)
|
||||
addOrders(cpAssets, itTokens);
|
||||
|
||||
if (additionalEvalCode != 0) { //this would be mytokenorders
|
||||
char assetsDualEvalTokensUnspendableAddr[64];
|
||||
|
||||
// try also dual eval tokenasks (and we do not need bids):
|
||||
cpAssets->additionalTokensEvalcode2 = additionalEvalCode;
|
||||
GetTokensCCaddress(cpAssets, assetsDualEvalTokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
|
||||
SetCCunspents(unspentOutputsDualEvalTokens, assetsDualEvalTokensUnspendableAddr,true);
|
||||
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itDualEvalTokens = unspentOutputsDualEvalTokens.begin();
|
||||
itDualEvalTokens != unspentOutputsDualEvalTokens.end();
|
||||
itDualEvalTokens++)
|
||||
addOrders(cpAssets, itDualEvalTokens);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
|
||||
// not used (use TokenCreate instead)
|
||||
/* std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
@@ -213,9 +182,10 @@ std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetCreateOpRet('c',Mypubkey(),name,description)));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
|
||||
} */
|
||||
|
||||
// not used (use TokenTransfer instead)
|
||||
/* std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
|
||||
@@ -230,11 +200,11 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
{
|
||||
/*n = outputs.size();
|
||||
if ( n == amounts.size() )
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
total += amounts[i];*/
|
||||
//n = outputs.size();
|
||||
//if ( n == amounts.size() )
|
||||
//{
|
||||
// for (i=0; i<n; i++)
|
||||
// total += amounts[i];
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
|
||||
{
|
||||
@@ -254,9 +224,10 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
|
||||
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
|
||||
}
|
||||
return("");
|
||||
}
|
||||
} */
|
||||
|
||||
std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
|
||||
// deprecated
|
||||
/* std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
|
||||
@@ -281,76 +252,128 @@ std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> dest
|
||||
} 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)
|
||||
// rpc tokenbid implementation, locks 'bidamount' coins for the 'pricetotal' of tokens
|
||||
std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description;
|
||||
if ( bidamount < 0 || pricetotal < 0 )
|
||||
CPubKey mypk;
|
||||
struct CCcontract_info *cpAssets, C;
|
||||
uint256 hashBlock;
|
||||
CTransaction vintx;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
std::string name,description;
|
||||
int64_t inputs;
|
||||
|
||||
std::cerr << "CreateBuyOffer() bidamount=" << bidamount << " numtokens(pricetotal)=" << pricetotal << std::endl;
|
||||
|
||||
if (bidamount < 0 || pricetotal < 0)
|
||||
{
|
||||
fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal);
|
||||
fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n", (long long)bidamount, (long long)pricetotal);
|
||||
return("");
|
||||
}
|
||||
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
|
||||
if (GetTransaction(assetid, vintx, hashBlock, false) == 0)
|
||||
{
|
||||
fprintf(stderr,"cant find assetid\n");
|
||||
return("");
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
|
||||
if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, origpubkey, name, description) == 0)
|
||||
{
|
||||
fprintf(stderr,"assetid isnt assetcreation txid\n");
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
|
||||
cpAssets = CCinit(&C,EVAL_ASSETS); // NOTE: assets here!
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,bidamount+txfee,64) > 0 )
|
||||
|
||||
if ((inputs = AddNormalinputs(mtx, mypk, bidamount+(2*txfee), 64)) > 0)
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount,GetUnspendable(cp,0)));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('b',assetid,zeroid,pricetotal,Mypubkey())));
|
||||
std::cerr << "CreateBuyOffer() inputs=" << inputs << std::endl;
|
||||
if (inputs < bidamount+txfee) {
|
||||
std::cerr << "CreateBuyOffer(): insufficient coins to make buy offer" << std::endl;
|
||||
CCerror = strprintf("insufficient coins to make buy offer");
|
||||
return ("");
|
||||
}
|
||||
|
||||
CPubKey unspendableAssetsPubkey = GetUnspendable(cpAssets, 0);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendableAssetsPubkey));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk));
|
||||
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
|
||||
|
||||
return FinalizeCCTx(0, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys, // TODO: actually this tx is not 'tokens', maybe it is better not to have token opret here but only asset opret.
|
||||
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey())))); // But still such token opret should not make problems because no token eval in these vouts
|
||||
}
|
||||
CCerror = strprintf("no coins found to make buy offer");
|
||||
return("");
|
||||
}
|
||||
|
||||
// rpc tokenask implementation, locks 'askamount' tokens for the 'pricetotal'
|
||||
std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
|
||||
CPubKey mypk;
|
||||
uint64_t mask;
|
||||
int64_t inputs, CCchange;
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
|
||||
//std::cerr << "CreateSell() askamount=" << askamount << " pricetotal=" << pricetotal << std::endl;
|
||||
|
||||
if ( askamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
if (askamount < 0 || pricetotal < 0) {
|
||||
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS); // NOTE: for signing
|
||||
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
|
||||
{
|
||||
std::vector<uint8_t> vopretNonfungible;
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
|
||||
// add single-eval tokens (or non-fungible tokens):
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS); // NOTE: adding inputs only from EVAL_TOKENS cc
|
||||
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60, vopretNonfungible)) > 0)
|
||||
{
|
||||
if (inputs < askamount) {
|
||||
//askamount = inputs;
|
||||
//was: askamount = inputs;
|
||||
std::cerr << "CreateSell(): insufficient tokens for ask" << std::endl;
|
||||
CCerror = strprintf("insufficient tokens for ask");
|
||||
return ("");
|
||||
}
|
||||
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
|
||||
if ( inputs > askamount )
|
||||
// if this is non-fungible tokens:
|
||||
if( !vopretNonfungible.empty() )
|
||||
// set its evalcode
|
||||
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
|
||||
|
||||
CPubKey unspendableAssetsPubkey = GetUnspendable(cpAssets, NULL);
|
||||
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, cpAssets->additionalTokensEvalcode2, askamount, unspendableAssetsPubkey));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker (seems, it is not for tokenorders)
|
||||
if (inputs > askamount)
|
||||
CCchange = (inputs - askamount);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
|
||||
if (CCchange != 0)
|
||||
// change to single-eval or non-fungible token vout (although for non-fungible token change currently is not possible)
|
||||
mtx.vout.push_back(MakeTokensCC1vout((cpAssets->additionalTokensEvalcode2) ? cpAssets->additionalTokensEvalcode2 : EVAL_TOKENS, CCchange, mypk));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(unspendableAssetsPubkey);
|
||||
|
||||
return FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()))));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "need some assets to place ask\n");
|
||||
fprintf(stderr, "need some tokens to place ask\n");
|
||||
}
|
||||
}
|
||||
else { // dimxy added 'else', because it was misleading message before
|
||||
@@ -359,197 +382,401 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
|
||||
return("");
|
||||
}
|
||||
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
|
||||
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
fprintf(stderr,"asset swaps disabled\n");
|
||||
return("");
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
|
||||
if ( askamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
cp = CCinit(&C, EVAL_ASSETS);
|
||||
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
|
||||
/*if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
|
||||
{
|
||||
if ( inputs < askamount )
|
||||
askamount = inputs;
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
|
||||
if ( inputs > askamount )
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
if (inputs < askamount) {
|
||||
//was: askamount = inputs;
|
||||
std::cerr << "CreateSwap(): insufficient tokens for ask" << std::endl;
|
||||
CCerror = strprintf("insufficient tokens for ask");
|
||||
return ("");
|
||||
}
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
CPubKey unspendablePubkey = GetUnspendable(cp, 0);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, unspendablePubkey));
|
||||
|
||||
if (inputs > askamount)
|
||||
CCchange = (inputs - askamount);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
if ( assetid2 == zeroid )
|
||||
opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey());
|
||||
else
|
||||
{
|
||||
opret = EncodeAssetOpRet('e',assetid,assetid2,pricetotal,Mypubkey());
|
||||
}
|
||||
if (CCchange != 0)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk));
|
||||
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
|
||||
|
||||
if (assetid2 == zeroid) {
|
||||
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()));
|
||||
}
|
||||
else {
|
||||
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('e', assetid2, pricetotal, Mypubkey()));
|
||||
}
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "need some assets to place ask\n");
|
||||
}
|
||||
} */
|
||||
}
|
||||
else { // dimxy added 'else', because it was misleading message before
|
||||
fprintf(stderr,"need some native coins to place ask\n");
|
||||
}
|
||||
|
||||
return("");
|
||||
}
|
||||
} ////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
|
||||
// unlocks coins
|
||||
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
CTransaction vintx; uint64_t mask;
|
||||
uint256 hashBlock; int64_t bidamount;
|
||||
CPubKey mypk; struct CCcontract_info *cpAssets, C;
|
||||
uint8_t funcid,dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
|
||||
|
||||
cpAssets = CCinit(&C, EVAL_ASSETS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
|
||||
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
std::vector<uint8_t> vopretNonfungible;
|
||||
GetNonfungibleData(assetid, vopretNonfungible);
|
||||
|
||||
bidamount = vintx.vout[0].nValue;
|
||||
mtx.vin.push_back(CTxIn(bidtxid,0,CScript()));
|
||||
mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets
|
||||
|
||||
if((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
|
||||
{
|
||||
if (funcid == 's') mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b'
|
||||
else if (funcid=='S') mtx.vin.push_back(CTxIn(bidtxid, 3, CScript())); // spend marker if funcid='B'
|
||||
}
|
||||
|
||||
mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('o',assetid,zeroid,0,Mypubkey())));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys; // should be empty, no token vouts
|
||||
|
||||
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('o', zeroid, 0, Mypubkey())))));
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
//unlocks tokens
|
||||
std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
CTransaction vintx; uint64_t mask;
|
||||
uint256 hashBlock; int64_t askamount;
|
||||
CPubKey mypk;
|
||||
struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
|
||||
uint8_t funcid, dummyEvalCode;
|
||||
uint256 dummyAssetid, dummyAssetid2;
|
||||
int64_t dummyPrice;
|
||||
std::vector<uint8_t> dummyOrigpubkey;
|
||||
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
|
||||
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
std::vector<uint8_t> vopretNonfungible;
|
||||
GetNonfungibleData(assetid, vopretNonfungible);
|
||||
|
||||
askamount = vintx.vout[0].nValue;
|
||||
mtx.vin.push_back(CTxIn(asktxid,0,CScript()));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,mypk));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('x',assetid,zeroid,0,Mypubkey())));
|
||||
mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
|
||||
|
||||
if ((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
|
||||
{
|
||||
if (funcid == 's')
|
||||
mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s'
|
||||
else if (funcid=='S')
|
||||
mtx.vin.push_back(CTxIn(asktxid, 3, CScript())); // marker if funcid='S'
|
||||
}
|
||||
|
||||
if (vopretNonfungible.size() > 0)
|
||||
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
|
||||
|
||||
mtx.vout.push_back(MakeTokensCC1vout(cpAssets->additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : cpAssets->additionalTokensEvalcode2, askamount, mypk)); // one-eval token vout
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(mypk);
|
||||
|
||||
// this is only for unspendable addresses:
|
||||
//CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress
|
||||
|
||||
uint8_t unspendableAssetsPrivkey[32];
|
||||
char unspendableAssetsAddr[64];
|
||||
// init assets 'unspendable' privkey and pubkey
|
||||
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
|
||||
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
|
||||
|
||||
// add additional eval-tokens unspendable assets privkey:
|
||||
CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
|
||||
|
||||
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('x', zeroid, 0, Mypubkey())))));
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
//send tokens, receive coins:
|
||||
std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction vintx; uint256 hashBlock; CPubKey mypk; std::vector<uint8_t> origpubkey; int32_t bidvout=0; uint64_t mask; int64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0; struct CCcontract_info *cp,C;
|
||||
if ( fillamount < 0 )
|
||||
CTransaction vintx;
|
||||
uint256 hashBlock;
|
||||
CPubKey mypk;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
int32_t bidvout=0;
|
||||
uint64_t mask;
|
||||
int64_t origprice, bidamount, paid_amount, remaining_required, inputs, CCchange=0;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
|
||||
if (fillamount < 0)
|
||||
{
|
||||
fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount);
|
||||
fprintf(stderr,"negative fillamount %lld\n", (long long)fillamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
|
||||
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
bidamount = vintx.vout[bidvout].nValue;
|
||||
SetAssetOrigpubkey(origpubkey,origprice,vintx);
|
||||
mtx.vin.push_back(CTxIn(bidtxid,bidvout,CScript()));
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,fillamount,60)) > 0 )
|
||||
SetAssetOrigpubkey(origpubkey, origprice, vintx);
|
||||
|
||||
mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); // Coins on Assets unspendable
|
||||
|
||||
std::vector<uint8_t> vopretNonfungible;
|
||||
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60, vopretNonfungible)) > 0)
|
||||
{
|
||||
if ( inputs < fillamount )
|
||||
fillamount = inputs;
|
||||
SetBidFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice);
|
||||
if ( inputs > fillamount )
|
||||
if (inputs < fillamount) {
|
||||
std::cerr << "FillBuyOffer(): insufficient tokens to fill buy offer" << std::endl;
|
||||
CCerror = strprintf("insufficient tokens to fill buy offer");
|
||||
return ("");
|
||||
}
|
||||
|
||||
SetBidFillamounts(paid_amount, remaining_required, bidamount, fillamount, origprice);
|
||||
|
||||
uint8_t additionalTokensEvalcode2 = 0;
|
||||
if (vopretNonfungible.size() > 0)
|
||||
additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
|
||||
|
||||
if (inputs > fillamount)
|
||||
CCchange = (inputs - fillamount);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount - paid_amount,GetUnspendable(cp,0)));
|
||||
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,fillamount,pubkey2pk(origpubkey)));
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
fprintf(stderr,"remaining %llu -> origpubkey\n",(long long)remaining_required);
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('B',assetid,zeroid,remaining_required,origpubkey)));
|
||||
} else return("dont have any assets to fill bid\n");
|
||||
|
||||
uint8_t unspendableAssetsPrivkey[32];
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
|
||||
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder
|
||||
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal
|
||||
mtx.vout.push_back(MakeTokensCC1vout(additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : additionalTokensEvalcode2, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the originator
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, origpubkey)); // vout3 marker to origpubkey
|
||||
|
||||
if (CCchange != 0)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout4 change in single-eval tokens
|
||||
|
||||
fprintf(stderr,"FillBuyOffer() remaining %llu -> origpubkey\n", (long long)remaining_required);
|
||||
|
||||
char unspendableAssetsAddr[64];
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
|
||||
|
||||
// add additional unspendable addr from Assets:
|
||||
CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
|
||||
|
||||
// token vout verification pubkeys:
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(pubkey2pk(origpubkey));
|
||||
|
||||
return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey)))));
|
||||
} else return("dont have any assets to fill bid");
|
||||
}
|
||||
}
|
||||
return("no normal coins left");
|
||||
}
|
||||
|
||||
std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits)
|
||||
|
||||
// send coins, receive tokens
|
||||
std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 asktxid, int64_t fillunits)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction vintx,filltx; uint256 hashBlock; CPubKey mypk; std::vector<uint8_t> origpubkey; double dprice; uint64_t mask; int32_t askvout=0; int64_t received_assetoshis,total_nValue,orig_assetoshis,paid_nValue,remaining_nValue,inputs,CCchange=0; struct CCcontract_info *cp,C;
|
||||
if ( fillunits < 0 )
|
||||
CTransaction vintx,filltx;
|
||||
uint256 hashBlock;
|
||||
CPubKey mypk;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
double dprice;
|
||||
uint64_t mask = 0;
|
||||
int32_t askvout = 0;
|
||||
int64_t received_assetoshis, total_nValue, orig_assetoshis, paid_nValue, remaining_nValue, inputs, CCchange=0;
|
||||
//struct CCcontract_info *cpTokens, tokensC;
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
|
||||
if (fillunits < 0)
|
||||
{
|
||||
CCerror = strprintf("negative fillunits %lld\n",(long long)fillunits);
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
if ( assetid2 != zeroid )
|
||||
if (assetid2 != zeroid)
|
||||
{
|
||||
CCerror = "asset swaps disabled";
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
std::vector<uint8_t> vopretNonfungible;
|
||||
uint8_t additionalTokensEvalcode2 = 0;
|
||||
GetNonfungibleData(assetid, vopretNonfungible);
|
||||
if (vopretNonfungible.size() > 0)
|
||||
additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
|
||||
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
|
||||
//if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
|
||||
//{
|
||||
//mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
orig_assetoshis = vintx.vout[askvout].nValue;
|
||||
SetAssetOrigpubkey(origpubkey,total_nValue,vintx);
|
||||
SetAssetOrigpubkey(origpubkey, total_nValue, vintx);
|
||||
dprice = (double)total_nValue / orig_assetoshis;
|
||||
paid_nValue = dprice * fillunits;
|
||||
mtx.vin.push_back(CTxIn(asktxid,askvout,CScript()));
|
||||
if ( assetid2 != zeroid )
|
||||
inputs = AddAssetInputs(cp,mtx,mypk,assetid2,paid_nValue,60);
|
||||
|
||||
if (assetid2 != zeroid) {
|
||||
inputs = 0; // = AddAssetInputs(cpAssets, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet
|
||||
}
|
||||
else
|
||||
{
|
||||
inputs = AddNormalinputs(mtx,mypk,paid_nValue,60);
|
||||
inputs = AddNormalinputs(mtx, mypk, 2 * txfee + paid_nValue, 60); // Better to use single AddNormalinputs() to allow payment if user has only single utxo with normal funds
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
}
|
||||
if ( inputs > 0 )
|
||||
if (inputs > 0)
|
||||
{
|
||||
if ( inputs < paid_nValue )
|
||||
paid_nValue = inputs;
|
||||
if ( assetid2 != zeroid )
|
||||
SetSwapFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
|
||||
else SetAskFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue);
|
||||
if ( assetid2 != zeroid && inputs > paid_nValue )
|
||||
if (inputs < paid_nValue) {
|
||||
std::cerr << "FillSell(): insufficient coins to fill sell" << std::endl;
|
||||
CCerror = strprintf("insufficient coins to fill sell");
|
||||
return ("");
|
||||
}
|
||||
|
||||
// cc vin should be after normal vin
|
||||
mtx.vin.push_back(CTxIn(asktxid, askvout, CScript()));
|
||||
|
||||
if (assetid2 != zeroid)
|
||||
SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); //not implemented correctly yet
|
||||
else
|
||||
SetAskFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue);
|
||||
|
||||
if (assetid2 != zeroid && inputs > paid_nValue)
|
||||
CCchange = (inputs - paid_nValue);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,orig_assetoshis - received_assetoshis,GetUnspendable(cp,0)));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,received_assetoshis,mypk));
|
||||
if ( assetid2 != zeroid )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,paid_nValue,origpubkey));
|
||||
else mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG));
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet(assetid2!=zeroid?'E':'S',assetid,assetid2,remaining_nValue,origpubkey)));
|
||||
|
||||
// vout.0 tokens remainder to unspendable cc addr:
|
||||
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, additionalTokensEvalcode2, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL)));
|
||||
//vout.1 purchased tokens to self token single-eval or dual-eval token+nonfungible cc addr:
|
||||
mtx.vout.push_back(MakeTokensCC1vout(additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : additionalTokensEvalcode2, received_assetoshis, mypk));
|
||||
|
||||
if (assetid2 != zeroid) {
|
||||
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl;
|
||||
// TODO: change MakeCC1vout appropriately when implementing:
|
||||
//mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //vout.2 tokens... (swap is not implemented yet)
|
||||
}
|
||||
else {
|
||||
//std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl;
|
||||
mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins to tokens seller's normal addr
|
||||
}
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,txfee,origpubkey)); //vout.3 marker to origpubkey
|
||||
|
||||
// not implemented
|
||||
if (CCchange != 0) {
|
||||
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (CCchange)" << std::endl;
|
||||
// TODO: change MakeCC1vout appropriately when implementing:
|
||||
//mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr (swap not implemented)
|
||||
}
|
||||
|
||||
uint8_t unspendableAssetsPrivkey[32];
|
||||
char unspendableAssetsAddr[64];
|
||||
// init assets 'unspendable' privkey and pubkey
|
||||
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
|
||||
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
|
||||
|
||||
// add additional eval-tokens unspendable assets privkey:
|
||||
CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
|
||||
|
||||
// vout verification pubkeys:
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(mypk);
|
||||
|
||||
cpAssets->additionalTokensEvalcode2 = additionalTokensEvalcode2;
|
||||
|
||||
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, origpubkey)))));
|
||||
} else {
|
||||
CCerror = strprintf("filltx not enough utxos");
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
return("");
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define CHANNELS_MAXPAYMENTS 1000
|
||||
|
||||
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 ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 tokenid);
|
||||
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);
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "CCMarmara.h"
|
||||
#include "CCPayments.h"
|
||||
#include "CCGateways.h"
|
||||
#include "CCtokens.h"
|
||||
#include "CCImportGateway.h"
|
||||
|
||||
/*
|
||||
CCcustom has most of the functions that need to be extended to create a new CC contract.
|
||||
@@ -62,7 +64,6 @@ const char *AssetsCCaddr = "RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6";
|
||||
const char *AssetsNormaladdr = "RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u";
|
||||
char AssetsCChexstr[67] = { "02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702" };
|
||||
uint8_t AssetsCCpriv[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 };
|
||||
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
@@ -74,7 +75,6 @@ const char *FaucetCCaddr = "R9zHrofhRbub7ER77B7NrVch3A63R39GuC";
|
||||
const char *FaucetNormaladdr = "RKQV4oYs4rvxAWx1J43VnT73rSTVtUeckk";
|
||||
char FaucetCChexstr[67] = { "03682b255c40d0cde8faee381a1a50bbb89980ff24539cb8518e294d3a63cefe12" };
|
||||
uint8_t FaucetCCpriv[32] = { 0xd4, 0x4f, 0xf2, 0x31, 0x71, 0x7d, 0x28, 0x02, 0x4b, 0xc7, 0xdd, 0x71, 0xa0, 0x39, 0xc4, 0xbe, 0x1a, 0xfe, 0xeb, 0xc2, 0x46, 0xda, 0x76, 0xf8, 0x07, 0x53, 0x3d, 0x96, 0xb4, 0xca, 0xa0, 0xe9 };
|
||||
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
@@ -222,8 +222,87 @@ uint8_t GatewaysCCpriv[32] = { 0xf7, 0x4b, 0x5b, 0xa2, 0x7a, 0x5e, 0x9c, 0xda, 0
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
// Tokens
|
||||
#define FUNCNAME IsTokensInput
|
||||
#define EVALCODE EVAL_TOKENS
|
||||
const char *TokensCCaddr = "RAMvUfoyURBRxAdVeTMHxn3giJZCFWeha2";
|
||||
const char *TokensNormaladdr = "RCNgAngYAdrfzujYyPgfbjCGNVQZzCgTad";
|
||||
char TokensCChexstr[67] = { "03e6191c70c9c9a28f9fd87089b9488d0e6c02fb629df64979c9cdb6b2b4a68d95" };
|
||||
uint8_t TokensCCpriv[32] = { 0x1d, 0x0d, 0x0d, 0xce, 0x2d, 0xd2, 0xe1, 0x9d, 0xf5, 0xb6, 0x26, 0xd5, 0xad, 0xa0, 0xf0, 0x0a, 0xdd, 0x7a, 0x72, 0x7d, 0x17, 0x35, 0xb5, 0xe3, 0x2c, 0x6c, 0xa9, 0xa2, 0x03, 0x16, 0x4b, 0xcf };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
#define FUNCNAME IsCClibInput
|
||||
#define EVALCODE EVAL_FIRSTUSER
|
||||
const char *CClibNormaladdr = "RVVeUg43rNcq3mZFnvZ8yqagyzqFgUnq4u";
|
||||
char CClibCChexstr[67] = { "032447d97655da079729dc024c61088ea415b22f4c15d4810ddaf2069ac6468d2f" };
|
||||
uint8_t CClibCCpriv[32] = { 0x57, 0xcf, 0x49, 0x71, 0x7d, 0xb4, 0x15, 0x1b, 0x4f, 0x98, 0xc5, 0x45, 0x8d, 0x26, 0x52, 0x4b, 0x7b, 0xe9, 0xbd, 0x55, 0xd8, 0x20, 0xd6, 0xc4, 0x82, 0x0f, 0xf5, 0xec, 0x6c, 0x1c, 0xa0, 0xc0 };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
// ImportGateway
|
||||
#define FUNCNAME IsImportGatewayInput
|
||||
#define EVALCODE EVAL_IMPORTGATEWAY
|
||||
const char *ImportGatewayCCaddr = "RXJT6CRAXHFuQ2UjqdxMj7EfrayF6UJpzZ";
|
||||
const char *ImportGatewayNormaladdr = "RNFRho63Ddz1Rh2eGPETykrU4fA8r67S4Y";
|
||||
char ImportGatewayCChexstr[67] = { "0397231cfe04ea32d5fafb2206773ec9fba6e15c5a4e86064468bca195f7542714" };
|
||||
uint8_t ImportGatewayCCpriv[32] = { 0x65, 0xef, 0x27, 0xeb, 0x3d, 0xb0, 0xb4, 0xae, 0x0f, 0xbc, 0x77, 0xdb, 0xf8, 0x40, 0x48, 0x90, 0x52, 0x20, 0x9e, 0x45, 0x3b, 0x49, 0xd8, 0x97, 0x60, 0x8c, 0x27, 0x4c, 0x59, 0x46, 0xe1, 0xdf };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode)
|
||||
{
|
||||
CPubKey pk; int32_t i; uint8_t pub33[33],check33[33],hash[32]; char CCaddr[64],checkaddr[64],str[67];
|
||||
cp->evalcode = evalcode;
|
||||
cp->ismyvin = IsCClibInput;
|
||||
memcpy(cp->CCpriv,CClibCCpriv,32);
|
||||
if ( evalcode == EVAL_FIRSTUSER ) // eventually make a hashchain for each evalcode
|
||||
{
|
||||
strcpy(cp->CChexstr,CClibCChexstr);
|
||||
decode_hex(pub33,33,cp->CChexstr);
|
||||
pk = buf2pk(pub33);
|
||||
Getscriptaddress(cp->normaladdr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
|
||||
if ( strcmp(cp->normaladdr,CClibNormaladdr) != 0 )
|
||||
fprintf(stderr,"CClib_initcp addr mismatch %s vs %s\n",cp->normaladdr,CClibNormaladdr);
|
||||
GetCCaddress(cp,cp->unspendableCCaddr,pk);
|
||||
if ( priv2addr(checkaddr,check33,cp->CCpriv) != 0 )
|
||||
{
|
||||
if ( buf2pk(check33) == pk && strcmp(checkaddr,cp->normaladdr) == 0 )
|
||||
{
|
||||
//fprintf(stderr,"verified evalcode.%d %s %s\n",cp->evalcode,checkaddr,pubkey33_str(str,pub33));
|
||||
return(0);
|
||||
} else fprintf(stderr,"CClib_initcp mismatched privkey -> addr %s vs %s\n",checkaddr,cp->normaladdr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=EVAL_FIRSTUSER; i<evalcode; i++)
|
||||
{
|
||||
vcalc_sha256(0,hash,cp->CCpriv,32);
|
||||
memcpy(cp->CCpriv,hash,32);
|
||||
}
|
||||
if ( priv2addr(cp->normaladdr,pub33,cp->CCpriv) != 0 )
|
||||
{
|
||||
pk = buf2pk(pub33);
|
||||
for (i=0; i<33; i++)
|
||||
sprintf(&cp->CChexstr[i*2],"%02x",pub33[i]);
|
||||
cp->CChexstr[i*2] = 0;
|
||||
GetCCaddress(cp,cp->unspendableCCaddr,pk);
|
||||
//printf("evalcode.%d initialized\n",evalcode);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
|
||||
{
|
||||
// important to clear because not all members are always initialized!
|
||||
memset(cp, '\0', sizeof(*cp));
|
||||
|
||||
cp->evalcode = evalcode;
|
||||
switch ( evalcode )
|
||||
{
|
||||
@@ -347,6 +426,27 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
|
||||
cp->validate = GatewaysValidate;
|
||||
cp->ismyvin = IsGatewaysInput;
|
||||
break;
|
||||
|
||||
case EVAL_TOKENS:
|
||||
strcpy(cp->unspendableCCaddr, TokensCCaddr);
|
||||
strcpy(cp->normaladdr, TokensNormaladdr);
|
||||
strcpy(cp->CChexstr, TokensCChexstr);
|
||||
memcpy(cp->CCpriv, TokensCCpriv, 32);
|
||||
cp->validate = TokensValidate;
|
||||
cp->ismyvin = IsTokensInput;
|
||||
break;
|
||||
case EVAL_IMPORTGATEWAY:
|
||||
strcpy(cp->unspendableCCaddr, ImportGatewayCCaddr);
|
||||
strcpy(cp->normaladdr, ImportGatewayNormaladdr);
|
||||
strcpy(cp->CChexstr, ImportGatewayCChexstr);
|
||||
memcpy(cp->CCpriv, ImportGatewayCCpriv, 32);
|
||||
cp->validate = ImportGatewayValidate;
|
||||
cp->ismyvin = IsImportGatewayInput;
|
||||
break;
|
||||
default:
|
||||
if ( CClib_initcp(cp,evalcode) < 0 )
|
||||
return(0);
|
||||
break;
|
||||
}
|
||||
return(cp);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ one other technical note is that komodod has the insight-explorer extensions bui
|
||||
#include <cryptoconditions.h>
|
||||
#include "../script/standard.h"
|
||||
#include "../base58.h"
|
||||
#include "../key.h"
|
||||
#include "../core_io.h"
|
||||
#include "../script/sign.h"
|
||||
#include "../wallet/wallet.h"
|
||||
@@ -50,19 +51,45 @@ one other technical note is that komodod has the insight-explorer extensions bui
|
||||
#include "../komodo_defs.h"
|
||||
#include "../utlist.h"
|
||||
#include "../uthash.h"
|
||||
#include "merkleblock.h"
|
||||
|
||||
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE,KOMODO_DEALERNODE;
|
||||
extern uint32_t ASSETCHAINS_CC;
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
extern std::string CCerror;
|
||||
#define CC_BURNPUBKEY "02deaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead"
|
||||
#define CC_MAXVINS 1024
|
||||
|
||||
#define SMALLVAL 0.000000000000001
|
||||
#define SATOSHIDEN ((uint64_t)100000000L)
|
||||
#define dstr(x) ((double)(x) / SATOSHIDEN)
|
||||
|
||||
#ifndef _BITS256
|
||||
#define _BITS256
|
||||
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;
|
||||
#endif
|
||||
|
||||
#include "../komodo_cJSON.h"
|
||||
|
||||
// token opret additional data block ids:
|
||||
enum opretid : uint8_t {
|
||||
// cc contracts data:
|
||||
OPRETID_NONFUNGIBLEDATA = 0x11,
|
||||
OPRETID_ASSETSDATA = 0x12,
|
||||
OPRETID_GATEWAYSDATA = 0x13,
|
||||
OPRETID_CHANNELSDATA = 0x14,
|
||||
OPRETID_HEIRDATA = 0x15,
|
||||
OPRETID_ROGUEGAMEDATA = 0x16,
|
||||
|
||||
// non cc contract data:
|
||||
OPRETID_FIRSTNONCCDATA = 0x80,
|
||||
OPRETID_BURNDATA = 0x80,
|
||||
OPRETID_IMPORTDATA = 0x81
|
||||
};
|
||||
|
||||
// find opret blob by opretid
|
||||
inline bool GetOpretBlob(const std::vector<std::pair<uint8_t, std::vector<uint8_t>>> &oprets, uint8_t id, std::vector<uint8_t> &vopret) {
|
||||
vopret.clear();
|
||||
for(auto p : oprets) if (p.first == id) { vopret = p.second; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CC_utxo
|
||||
{
|
||||
@@ -84,12 +111,32 @@ struct CC_meta
|
||||
|
||||
struct CCcontract_info
|
||||
{
|
||||
char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64],unspendableaddr3[64];
|
||||
uint8_t CCpriv[32],unspendablepriv2[32],unspendablepriv3[32];
|
||||
CPubKey unspendablepk2,unspendablepk3;
|
||||
bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn);
|
||||
bool (*ismyvin)(CScript const& scriptSig);
|
||||
uint8_t evalcode,evalcode2,evalcode3,didinit;
|
||||
// this is for spending from 'unspendable' CC address
|
||||
uint8_t evalcode;
|
||||
uint8_t additionalTokensEvalcode2; // this is for making three-eval-token vouts (EVAL_TOKENS + evalcode + additionalEvalcode2)
|
||||
char unspendableCCaddr[64], CChexstr[72], normaladdr[64];
|
||||
uint8_t CCpriv[32];
|
||||
|
||||
// this for 1of2 keys coins cryptocondition (for this evalcode)
|
||||
// NOTE: only one evalcode is allowed at this time
|
||||
char coins1of2addr[64];
|
||||
CPubKey coins1of2pk[2]; uint8_t coins1of2priv[32];
|
||||
|
||||
// the same for tokens 1of2 keys cc
|
||||
char tokens1of2addr[64];
|
||||
CPubKey tokens1of2pk[2];
|
||||
|
||||
// this is for spending from two additional 'unspendable' CC addresses of other eval codes
|
||||
// (that is, for spending from several cc contract 'unspendable' addresses):
|
||||
uint8_t unspendableEvalcode2, unspendableEvalcode3; // changed evalcodeN to unspendableEvalcodeN for not mixing up with additionalEvalcodeN
|
||||
char unspendableaddr2[64], unspendableaddr3[64];
|
||||
uint8_t unspendablepriv2[32], unspendablepriv3[32];
|
||||
CPubKey unspendablepk2, unspendablepk3;
|
||||
|
||||
bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn); // cc contract tx validation callback
|
||||
bool (*ismyvin)(CScript const& scriptSig); // checks if evalcode is present in the scriptSig param
|
||||
|
||||
uint8_t didinit;
|
||||
};
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode);
|
||||
|
||||
@@ -100,64 +147,115 @@ struct oracleprice_info
|
||||
int32_t height;
|
||||
};
|
||||
|
||||
typedef std::vector<uint8_t> vscript_t;
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
extern CWallet* pwalletMain;
|
||||
#endif
|
||||
//extern CCoinsViewCache *pcoinsTip;
|
||||
bool GetAddressUnspent(uint160 addressHash, int type,std::vector<std::pair<CAddressUnspentKey,CAddressUnspentValue> > &unspentOutputs);
|
||||
CBlockIndex *komodo_getblockindex(uint256 hash);
|
||||
int32_t komodo_nextheight();
|
||||
|
||||
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout);
|
||||
void CCclearvars(struct CCcontract_info *cp);
|
||||
UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr);
|
||||
UniValue CClib_info(struct CCcontract_info *cp);
|
||||
CBlockIndex *komodo_blockindex(uint256 hash);
|
||||
CBlockIndex *komodo_chainactive(int32_t height);
|
||||
int32_t komodo_blockheight(uint256 hash);
|
||||
void StartShutdown();
|
||||
|
||||
static const uint256 zeroid;
|
||||
static uint256 ignoretxid;
|
||||
static int32_t ignorevin;
|
||||
bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock);
|
||||
int32_t is_hexstr(char *str,int32_t n);
|
||||
bool myAddtomempool(CTransaction &tx, CValidationState *pstate = NULL, bool fSkipExpiry = false);
|
||||
//uint64_t myGettxout(uint256 hash,int32_t n);
|
||||
bool myIsutxo_spentinmempool(uint256 txid,int32_t vout);
|
||||
int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag,int32_t lockflag);
|
||||
bool myIsutxo_spentinmempool(uint256 &spenttxid,int32_t &spentvini,uint256 txid,int32_t vout);
|
||||
bool mytxid_inmempool(uint256 txid);
|
||||
int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout);
|
||||
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);
|
||||
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
||||
int64_t CCaddress_balance(char *coinaddr);
|
||||
int64_t CCaddress_balance(char *coinaddr,int32_t CCflag);
|
||||
CPubKey CCtxidaddr(char *txidaddr,uint256 txid);
|
||||
CPubKey CCCustomtxidaddr(char *txidaddr,uint256 txid,uint8_t taddr,uint8_t prefix,uint8_t prefix2);
|
||||
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
|
||||
CTransaction &txOut, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> ¶ms);
|
||||
|
||||
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
|
||||
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
|
||||
uint256 OracleMerkle(int32_t height,uint256 reforacletxid,char *format,std::vector<struct oracle_merklepair>publishers);
|
||||
uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk);
|
||||
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
|
||||
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
|
||||
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
|
||||
uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey);
|
||||
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
|
||||
uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num);
|
||||
uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data);
|
||||
int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen);
|
||||
CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey);
|
||||
|
||||
//int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
|
||||
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
|
||||
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, vscript_t &vopretNonfungible);
|
||||
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid);
|
||||
|
||||
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
|
||||
void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std::vector<uint8_t> payload);
|
||||
int32_t payments_parsehexdata(std::vector<uint8_t> &hexdata,cJSON *item,int32_t len);
|
||||
int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex);
|
||||
|
||||
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, vscript_t vopretNonfungible);
|
||||
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, std::vector<std::pair<uint8_t, vscript_t>> oprets);
|
||||
CScript EncodeTokenImportOpRet(std::vector<uint8_t> origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector<std::pair<uint8_t, vscript_t>> oprets);
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::pair<uint8_t, vscript_t> opretWithId);
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> oprets);
|
||||
int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk);
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
|
||||
uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
|
||||
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
|
||||
void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible);
|
||||
bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector<CPubKey> &vinPubkeys);
|
||||
|
||||
// CCcustom
|
||||
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
|
||||
//uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopret1, std::vector<uint8_t> &vopret2);
|
||||
|
||||
// CCutils
|
||||
bool priv2addr(char *coinaddr,uint8_t buf33[33],uint8_t priv32[32]);
|
||||
CPubKey buf2pk(uint8_t *buf33);
|
||||
void endiancpy(uint8_t *dest,uint8_t *src,int32_t len);
|
||||
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);
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, const std::vector<std::vector<unsigned char>>* vData = NULL);
|
||||
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, const std::vector<std::vector<unsigned char>>* vData = NULL);
|
||||
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk);
|
||||
CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);
|
||||
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);
|
||||
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2,uint8_t *priv,char *coinaddr);
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2);
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2);
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk);
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk);
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2);
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2);
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk);
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk);
|
||||
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk);
|
||||
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2);
|
||||
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
|
||||
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode);
|
||||
|
||||
bool IsCCInput(CScript const& scriptSig);
|
||||
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime);
|
||||
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);
|
||||
uint256 Parseuint256(const char *hexstr);
|
||||
CPubKey pubkey2pk(std::vector<uint8_t> pubkey);
|
||||
int64_t CCfullsupply(uint256 tokenid);
|
||||
int64_t CCtoken_balance(char *destaddr,uint256 tokenid);
|
||||
@@ -168,18 +266,24 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK
|
||||
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue);
|
||||
bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t numvins,int32_t preventCCvouts,int32_t numvouts);
|
||||
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
|
||||
bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t taddr,uint8_t prefix,uint8_t prefix2);
|
||||
std::vector<uint8_t> Mypubkey();
|
||||
bool Myprivkey(uint8_t myprivkey[]);
|
||||
int64_t CCduration(int32_t &numblocks,uint256 txid);
|
||||
uint256 CCOraclesReverseScan(char const *logcategory,uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid);
|
||||
int32_t CCCointxidExists(char const *logcategory,uint256 cointxid);
|
||||
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids);
|
||||
bool komodo_txnotarizedconfirmed(uint256 txid);
|
||||
CPubKey check_signing_pubkey(CScript scriptSig);
|
||||
// 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);
|
||||
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr);
|
||||
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr);
|
||||
extern std::vector<CPubKey> NULL_pubkeys;
|
||||
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret,std::vector<CPubKey> pubkeys = NULL_pubkeys);
|
||||
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr,bool CCflag = true);
|
||||
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr,bool CCflag = true);
|
||||
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs);
|
||||
int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs);
|
||||
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout);
|
||||
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout,int32_t CCflag);
|
||||
|
||||
// curve25519 and sha256
|
||||
bits256 curve25519_shared(bits256 privkey,bits256 otherpub);
|
||||
@@ -187,5 +291,33 @@ bits256 curve25519_basepoint9();
|
||||
bits256 curve25519(bits256 mysecret,bits256 basepoint);
|
||||
void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
|
||||
bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen);
|
||||
UniValue ValueFromAmount(const CAmount& amount);
|
||||
|
||||
|
||||
// bitcoin LogPrintStr with category "-debug" cmdarg support for C++ ostringstream:
|
||||
#define CCLOG_INFO 0
|
||||
#define CCLOG_DEBUG1 1
|
||||
#define CCLOG_DEBUG2 2
|
||||
#define CCLOG_DEBUG3 3
|
||||
#define CCLOG_MAXLEVEL 3
|
||||
template <class T>
|
||||
void CCLogPrintStream(const char *category, int level, T print_to_stream)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
print_to_stream(stream);
|
||||
if (level < 0)
|
||||
level = 0;
|
||||
if (level > CCLOG_MAXLEVEL)
|
||||
level = CCLOG_MAXLEVEL;
|
||||
for (int i = level; i <= CCLOG_MAXLEVEL; i++)
|
||||
if( LogAcceptCategory((std::string(category) + std::string("-") + std::to_string(i)).c_str()) || // '-debug=cctokens-0', '-debug=cctokens-1',...
|
||||
i == 0 && LogAcceptCategory(std::string(category).c_str()) ) { // also supporting '-debug=cctokens' for CCLOG_INFO
|
||||
LogPrintStr(stream.str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
// use: LOGSTREAM("yourcategory", your-debug-level, stream << "some log data" << data2 << data3 << ... << std::endl);
|
||||
#define LOGSTREAM(category, level, logoperator) CCLogPrintStream( category, level, [=](std::ostringstream &stream) {logoperator;} )
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
956
src/cc/CCtokens.cpp
Normal file
956
src/cc/CCtokens.cpp
Normal file
@@ -0,0 +1,956 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCtokens.h"
|
||||
|
||||
/* TODO: correct this:
|
||||
-----------------------------
|
||||
The SetTokenFillamounts() and ValidateTokenRemainder() work in tandem to calculate the vouts for a fill and to validate the vouts, respectively.
|
||||
|
||||
This pair of functions are critical to make sure the trading is correct and is the trickiest part of the tokens contract.
|
||||
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
//vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
|
||||
//vout.0: remaining amount of bid to unspendable
|
||||
//vout.1: vin.1 value to signer of vin.2
|
||||
//vout.2: vin.2 tokenoshis to original pubkey
|
||||
//vout.3: CC output for tokenoshis change (if any)
|
||||
//vout.4: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [tokenid] [remaining token required] [origpubkey]
|
||||
ValidateTokenRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits);
|
||||
|
||||
Yes, this is quite confusing...
|
||||
|
||||
In ValidateTokenRemainder the naming convention is nValue is the coin/token with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or tokens, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits.
|
||||
|
||||
We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it.
|
||||
------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// tx validation
|
||||
bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
static uint256 zero;
|
||||
CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2;
|
||||
int32_t i, starti, numvins, numvouts, preventCCvins, preventCCvouts;
|
||||
int64_t remaining_price, nValue, tokenoshis, outputs, inputs, tmpprice, totalunits, ignore;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
vscript_t /*vopretExtra,*/ tmporigpubkey, ignorepubkey;
|
||||
uint8_t funcid, evalCodeInOpret;
|
||||
char destaddr[64], origaddr[64], CCaddr[64];
|
||||
std::vector<CPubKey> voutTokenPubkeys, vinTokenPubkeys;
|
||||
|
||||
if (strcmp(ASSETCHAINS_SYMBOL, "ROGUE") == 0 && chainActive.Height() <= 12500)
|
||||
return true;
|
||||
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
outputs = inputs = 0;
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
|
||||
// check boundaries:
|
||||
if (numvouts < 1)
|
||||
return eval->Invalid("no vouts");
|
||||
|
||||
if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets)) == 0)
|
||||
return eval->Invalid("TokenValidate: invalid opreturn payload");
|
||||
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokensValidate funcId=" << (char)(funcid?funcid:' ') << " evalcode=" << std::hex << (int)cp->evalcode << std::endl);
|
||||
|
||||
if (eval->GetTxUnconfirmed(tokenid, createTx, hashBlock) == 0)
|
||||
return eval->Invalid("cant find token create txid");
|
||||
//else if (IsCCInput(tx.vin[0].scriptSig) != 0)
|
||||
// return eval->Invalid("illegal token vin0"); // <-- this validation was removed because some token tx might not have normal vins
|
||||
else if (funcid != 'c')
|
||||
{
|
||||
if (tokenid == zeroid)
|
||||
return eval->Invalid("illegal tokenid");
|
||||
else if (!TokensExactAmounts(true, cp, inputs, outputs, eval, tx, tokenid)) {
|
||||
if (!eval->Valid())
|
||||
return false; //TokenExactAmounts must call eval->Invalid()!
|
||||
else
|
||||
return eval->Invalid("tokens cc inputs != cc outputs");
|
||||
}
|
||||
}
|
||||
|
||||
// validate spending from token cc addr: allowed only for burned non-fungible tokens:
|
||||
if (ExtractTokensCCVinPubkeys(tx, vinTokenPubkeys) && std::find(vinTokenPubkeys.begin(), vinTokenPubkeys.end(), GetUnspendable(cp, NULL)) != vinTokenPubkeys.end()) {
|
||||
// validate spending from token unspendable cc addr:
|
||||
int64_t burnedAmount = HasBurnedTokensvouts(cp, eval, tx, tokenid);
|
||||
if (burnedAmount > 0) {
|
||||
vscript_t vopretNonfungible;
|
||||
GetNonfungibleData(tokenid, vopretNonfungible);
|
||||
if( vopretNonfungible.empty() )
|
||||
return eval->Invalid("spending cc marker not supported for fungible tokens");
|
||||
}
|
||||
}
|
||||
|
||||
switch (funcid)
|
||||
{
|
||||
case 'c': // create wont be called to be verified as it has no CC inputs
|
||||
//vin.0: normal input
|
||||
//vout.0: issuance tokenoshis to CC
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.n-1: opreturn EVAL_TOKENS 'c' <tokenname> <description>
|
||||
//if (evalCodeInOpret != EVAL_TOKENS)
|
||||
// return eval->Invalid("unexpected TokenValidate for createtoken");
|
||||
//else
|
||||
return true;
|
||||
|
||||
case 't': // transfer
|
||||
//vin.0: normal input
|
||||
//vin.1 .. vin.n-1: valid CC outputs
|
||||
//vout.0 to n-2: tokenoshis output to CC
|
||||
//vout.n-2: normal output for change (if any)
|
||||
//vout.n-1: opreturn <other evalcode> 't' tokenid <other contract payload>
|
||||
if (inputs == 0)
|
||||
return eval->Invalid("no token inputs for transfer");
|
||||
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "token transfer preliminarily validated inputs=" << inputs << "->outputs=" << outputs << " preventCCvins=" << preventCCvins<< " preventCCvouts=" << preventCCvouts << std::endl);
|
||||
break; // breaking to other contract validation...
|
||||
|
||||
default:
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "illegal tokens funcid=" << (char)(funcid?funcid:' ') << std::endl);
|
||||
return eval->Invalid("unexpected token funcid");
|
||||
}
|
||||
|
||||
// forward validation if evalcode in opret is not EVAL_TOKENS
|
||||
// init for forwarding validation call
|
||||
//if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS?
|
||||
// struct CCcontract_info *cpOther = NULL, C;
|
||||
|
||||
// cpOther = CCinit(&C, evalCodeInOpret);
|
||||
// if (cpOther)
|
||||
// return cpOther->validate(cpOther, eval, tx, nIn);
|
||||
// else
|
||||
// return eval->Invalid("unsupported evalcode in opret");
|
||||
//}
|
||||
return true;
|
||||
// what does this do?
|
||||
// return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
}
|
||||
|
||||
// helper funcs:
|
||||
|
||||
// extract cc token vins' pubkeys:
|
||||
bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector<CPubKey> &vinPubkeys) {
|
||||
|
||||
bool found = false;
|
||||
CPubKey pubkey;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
vinPubkeys.clear();
|
||||
|
||||
for (int32_t i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
// check for cc token vins:
|
||||
if( (*cpTokens->ismyvin)(tx.vin[i].scriptSig) )
|
||||
{
|
||||
|
||||
auto findEval = [](CC *cond, struct CCVisitor _) {
|
||||
bool r = false;
|
||||
|
||||
if (cc_typeId(cond) == CC_Secp256k1) {
|
||||
*(CPubKey*)_.context = buf2pk(cond->publicKey);
|
||||
//std::cerr << "findEval found pubkey=" << HexStr(*(CPubKey*)_.context) << std::endl;
|
||||
r = true;
|
||||
}
|
||||
// false for a match, true for continue
|
||||
return r ? 0 : 1;
|
||||
};
|
||||
|
||||
CC *cond = GetCryptoCondition(tx.vin[i].scriptSig);
|
||||
|
||||
if (cond) {
|
||||
CCVisitor visitor = { findEval, (uint8_t*)"", 0, &pubkey };
|
||||
bool out = !cc_visit(cond, visitor);
|
||||
cc_free(cond);
|
||||
|
||||
if (pubkey.IsValid()) {
|
||||
vinPubkeys.push_back(pubkey);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
thread_local uint32_t tokenValIndentSize = 0;
|
||||
|
||||
// validates opret for token tx:
|
||||
uint8_t ValidateTokenOpret(CTransaction tx, uint256 tokenid) {
|
||||
|
||||
uint256 tokenidOpret = zeroid;
|
||||
uint8_t funcid;
|
||||
uint8_t dummyEvalCode;
|
||||
std::vector<CPubKey> voutPubkeysDummy;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> opretsDummy;
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
std::string indentStr = std::string().append(tokenValIndentSize, '.');
|
||||
|
||||
if (tx.vout.size() == 0)
|
||||
return (uint8_t)0;
|
||||
|
||||
if ((funcid = DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenidOpret, voutPubkeysDummy, opretsDummy)) == 0)
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
else if (funcid == 'c')
|
||||
{
|
||||
if (tokenid != zeroid && tokenid == tx.GetHash()) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl);
|
||||
return funcid;
|
||||
}
|
||||
else {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my tokenbase txid=" << tx.GetHash().GetHex() << std::endl);
|
||||
}
|
||||
}
|
||||
else if (funcid == 'i')
|
||||
{
|
||||
if (tokenid != zeroid && tokenid == tx.GetHash()) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is import 'i' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl);
|
||||
return funcid;
|
||||
}
|
||||
else {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my import txid=" << tx.GetHash().GetHex() << std::endl);
|
||||
}
|
||||
}
|
||||
else if (funcid == 't')
|
||||
{
|
||||
//std::cerr << indentStr << "ValidateTokenOpret() tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
if (tokenid != zeroid && tokenid == tokenidOpret) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl);
|
||||
return funcid;
|
||||
}
|
||||
else {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my tokenid=" << tokenidOpret.GetHex() << std::endl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not supported funcid=" << (char)funcid << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl);
|
||||
}
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// remove token->unspendablePk (it is only for marker usage)
|
||||
void FilterOutTokensUnspendablePk(const std::vector<CPubKey> &sourcePubkeys, std::vector<CPubKey> &destPubkeys) {
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
CPubKey tokensUnspendablePk = GetUnspendable(cpTokens, NULL);
|
||||
destPubkeys.clear();
|
||||
|
||||
for (auto pk : sourcePubkeys)
|
||||
if (pk != tokensUnspendablePk)
|
||||
destPubkeys.push_back(pk);
|
||||
|
||||
}
|
||||
|
||||
void FilterOutNonCCOprets(const std::vector<std::pair<uint8_t, vscript_t>> &oprets, vscript_t &vopret) {
|
||||
|
||||
vopret.clear();
|
||||
|
||||
if (oprets.size() > 2)
|
||||
LOGSTREAM("cctokens", CCLOG_INFO, stream << "FilterOutNonCCOprets() warning!! oprets.size > 2 currently not supported" << oprets.size() << std::endl);
|
||||
|
||||
for (auto o : oprets) {
|
||||
if (o.first < OPRETID_FIRSTNONCCDATA) { // skip burn, import, etc opret data
|
||||
vopret = o.second; // return first contract opret (more than 1 is not supported yet)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if the vout is a really Tokens CC vout
|
||||
// also checks tokenid in opret or txid if this is 'c' tx
|
||||
// goDeeper is true: the func also validates amounts of the passed transaction:
|
||||
// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx
|
||||
// checkPubkeys is true: validates if the vout is token vout1 or token vout1of2. Should always be true!
|
||||
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true*/, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid)
|
||||
{
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
std::string indentStr = std::string().append(tokenValIndentSize, '.');
|
||||
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
|
||||
int32_t n = tx.vout.size();
|
||||
// just check boundaries:
|
||||
if (n == 0 || v < 0 || v >= n-1) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "isTokensvout() incorrect params: (n == 0 or v < 0 or v >= n-1)" << " v=" << v << " n=" << n << " returning 0" << std::endl);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition())
|
||||
{
|
||||
if (goDeeper) {
|
||||
//validate all tx
|
||||
int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0;
|
||||
|
||||
tokenValIndentSize++;
|
||||
// false --> because we already at the 1-st level ancestor tx and do not need to dereference ancestors of next levels
|
||||
bool isEqual = TokensExactAmounts(false, cp, myCCVinsAmount, myCCVoutsAmount, eval, tx, reftokenid);
|
||||
tokenValIndentSize--;
|
||||
|
||||
if (!isEqual) {
|
||||
// if ccInputs != ccOutputs and it is not the tokenbase tx
|
||||
// this means it is possibly a fake tx (dimxy):
|
||||
if (reftokenid != tx.GetHash()) { // checking that this is the true tokenbase tx, by verifying that funcid=c, is done further in this function (dimxy)
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() warning: for the verified tx detected a bad vintx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx, skipping the verified tx" << std::endl);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// token opret most important checks (tokenid == reftokenid, tokenid is non-zero, tx is 'tokenbase'):
|
||||
const uint8_t funcId = ValidateTokenOpret(tx, reftokenid);
|
||||
//std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
if (funcId != 0) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null funcId=" << (char)(funcId ? funcId : ' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
|
||||
uint8_t dummyEvalCode;
|
||||
uint256 tokenIdOpret;
|
||||
std::vector<CPubKey> voutPubkeys, voutPubkeysInOpret;
|
||||
vscript_t vopretExtra, vopretNonfungible;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
uint8_t evalCode = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim
|
||||
uint8_t evalCode2 = 0; // will be checked if zero or not
|
||||
|
||||
// test vouts for possible token use-cases:
|
||||
std::vector<std::pair<CTxOut, std::string>> testVouts;
|
||||
|
||||
DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysInOpret, oprets);
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "IsTokensvout() oprets.size()=" << oprets.size() << std::endl);
|
||||
|
||||
// get assets/channels/gateways token data:
|
||||
FilterOutNonCCOprets(oprets, vopretExtra); // NOTE: only 1 additional evalcode in token opret is currently supported
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "IsTokensvout() vopretExtra=" << HexStr(vopretExtra) << std::endl);
|
||||
|
||||
// get non-fungible data
|
||||
GetNonfungibleData(reftokenid, vopretNonfungible);
|
||||
FilterOutTokensUnspendablePk(voutPubkeysInOpret, voutPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there)
|
||||
|
||||
// NOTE: evalcode order in vouts is important:
|
||||
// non-fungible-eval -> EVAL_TOKENS -> assets-eval
|
||||
|
||||
if (vopretNonfungible.size() > 0)
|
||||
evalCode = vopretNonfungible.begin()[0];
|
||||
if (vopretExtra.size() > 0)
|
||||
evalCode2 = vopretExtra.begin()[0];
|
||||
|
||||
if (evalCode == EVAL_TOKENS && evalCode2 != 0) {
|
||||
evalCode = evalCode2; // for using MakeTokensCC1vout(evalcode,...) instead of MakeCC1vout(EVAL_TOKENS, evalcode...)
|
||||
evalCode2 = 0;
|
||||
}
|
||||
|
||||
if( /*checkPubkeys &&*/ funcId != 'c' ) { // for 'c' there is no pubkeys
|
||||
// verify that the vout is token by constructing vouts with the pubkeys in the opret:
|
||||
|
||||
// maybe this is dual-eval 1 pubkey or 1of2 pubkey vout?
|
||||
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) {
|
||||
// check dual/three-eval 1 pubkey vout with the first pubkey
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0]")) );
|
||||
if (evalCode2 != 0)
|
||||
// also check in backward evalcode order
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0] backward-eval")) );
|
||||
|
||||
if(voutPubkeys.size() == 2) {
|
||||
// check dual/three eval 1of2 pubkeys vout
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2")) );
|
||||
// check dual/three eval 1 pubkey vout with the second pubkey
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1]")));
|
||||
if (evalCode2 != 0) {
|
||||
// also check in backward evalcode order:
|
||||
// check dual/three eval 1of2 pubkeys vout
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1of2vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2 backward-eval")));
|
||||
// check dual/three eval 1 pubkey vout with the second pubkey
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1] backward-eval")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// maybe this is like gatewayclaim to single-eval token?
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]), std::string("single-eval cc1 pk[0]")));
|
||||
// maybe this is like FillSell for non-fungible token?
|
||||
if( evalCode != 0 )
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval-token cc1 pk[0]")));
|
||||
if( evalCode2 != 0 )
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval2-token cc1 pk[0]")));
|
||||
|
||||
if (voutPubkeys.size() == 2) {
|
||||
// the same for pk[1]:
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]), std::string("single-eval cc1 pk[1]")));
|
||||
if (evalCode != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval-token cc1 pk[1]")));
|
||||
if (evalCode2 != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval2-token cc1 pk[1]")));
|
||||
}
|
||||
}
|
||||
|
||||
// maybe it is single-eval or dual/three-eval token change?
|
||||
std::vector<CPubKey> vinPubkeys, vinPubkeysUnfiltered;
|
||||
ExtractTokensCCVinPubkeys(tx, vinPubkeysUnfiltered);
|
||||
FilterOutTokensUnspendablePk(vinPubkeysUnfiltered, vinPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there)
|
||||
|
||||
for(std::vector<CPubKey>::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) {
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it), std::string("single-eval cc1 self vin pk")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk")));
|
||||
|
||||
if (evalCode2 != 0)
|
||||
// also check in backward evalcode order:
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk backward-eval")));
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
CPubKey origPubkey;
|
||||
vscript_t vorigPubkey;
|
||||
std::string dummyName, dummyDescription;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, oprets) == 0) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() could not decode create opret" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
origPubkey = pubkey2pk(vorigPubkey);
|
||||
|
||||
// for 'c' recognize the tokens only to token originator pubkey (but not to unspendable <-- closed sec violation)
|
||||
// maybe this is like gatewayclaim to single-eval token?
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, origPubkey), std::string("single-eval cc1 orig-pk")));
|
||||
// maybe this is like FillSell for non-fungible token?
|
||||
if (evalCode != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, origPubkey), std::string("dual-eval-token cc1 orig-pk")));
|
||||
}
|
||||
|
||||
// try all test vouts:
|
||||
for (auto t : testVouts) {
|
||||
if (t.first == tx.vout[v]) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() valid amount=" << tx.vout[v].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
}
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() no valid vouts evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
}
|
||||
|
||||
//std::cerr << indentStr; fprintf(stderr,"IsTokensvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str());
|
||||
}
|
||||
//std::cerr << indentStr; fprintf(stderr,"IsTokensvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
// compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs)
|
||||
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cp, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 reftokenid)
|
||||
{
|
||||
CTransaction vinTx;
|
||||
uint256 hashBlock;
|
||||
int64_t tokenoshis;
|
||||
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
int32_t numvins = tx.vin.size();
|
||||
int32_t numvouts = tx.vout.size();
|
||||
inputs = outputs = 0;
|
||||
|
||||
// this is just for log messages indentation for debugging recursive calls:
|
||||
std::string indentStr = std::string().append(tokenValIndentSize, '.');
|
||||
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "TokensExactAmounts() entered for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
|
||||
for (int32_t i = 0; i<numvins; i++)
|
||||
{ // check for additional contracts which may send tokens to the Tokens contract
|
||||
if ((*cpTokens->ismyvin)(tx.vin[i].scriptSig) /*|| IsVinAllowed(tx.vin[i].scriptSig) != 0*/)
|
||||
{
|
||||
//std::cerr << indentStr << "TokensExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
|
||||
// we are not inside the validation code -- dimxy
|
||||
if ((eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)))
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "TokensExactAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl);
|
||||
return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt");
|
||||
}
|
||||
else {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "TokenExactAmounts() checking vintx.vout for tx.vin[" << i << "] nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl);
|
||||
|
||||
// validate vouts of vintx
|
||||
tokenValIndentSize++;
|
||||
tokenoshis = IsTokensvout(goDeeper, true, cpTokens, eval, vinTx, tx.vin[i].prevout.n, reftokenid);
|
||||
tokenValIndentSize--;
|
||||
if (tokenoshis != 0)
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "TokensExactAmounts() adding vintx.vout for tx.vin[" << i << "] tokenoshis=" << tokenoshis << std::endl);
|
||||
inputs += tokenoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < numvouts-1; i ++) // 'numvouts-1' <-- do not check opret
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "TokenExactAmounts() recursively checking tx.vout[" << i << "] nValue=" << tx.vout[i].nValue << std::endl);
|
||||
|
||||
// Note: we pass in here IsTokenvout(false,...) because we don't need to call TokenExactAmounts() recursively from IsTokensvout here
|
||||
// indeed, if we pass 'true' we'll be checking this tx vout again
|
||||
tokenValIndentSize++;
|
||||
tokenoshis = IsTokensvout(false /*<--do not recursion here*/, true /*<--exclude non-tokens vouts*/, cpTokens, eval, tx, i, reftokenid);
|
||||
tokenValIndentSize--;
|
||||
|
||||
if (tokenoshis != 0)
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "TokensExactAmounts() adding tx.vout[" << i << "] tokenoshis=" << tokenoshis << std::endl);
|
||||
outputs += tokenoshis;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << indentStr << "TokensExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
|
||||
if (inputs != outputs) {
|
||||
if (tx.GetHash() != reftokenid)
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "TokenExactAmounts() found unequal token cc inputs=" << inputs << " vs cc outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << " and this is not the create tx" << std::endl);
|
||||
//fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return false; // do not call eval->Invalid() here!
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// get non-fungible data from 'tokenbase' tx (the data might be empty)
|
||||
void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible)
|
||||
{
|
||||
CTransaction tokenbasetx;
|
||||
uint256 hashBlock;
|
||||
|
||||
if (!myGetTransaction(tokenid, tokenbasetx, hashBlock)) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "GetNonfungibleData() cound not load token creation tx=" << tokenid.GetHex() << std::endl);
|
||||
return;
|
||||
}
|
||||
|
||||
vopretNonfungible.clear();
|
||||
// check if it is non-fungible tx and get its second evalcode from non-fungible payload
|
||||
if (tokenbasetx.vout.size() > 0) {
|
||||
std::vector<uint8_t> origpubkey;
|
||||
std::string name, description;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, origpubkey, name, description, oprets) == 'c') {
|
||||
GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// overload, adds inputs from token cc addr
|
||||
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs) {
|
||||
vscript_t vopretNonfungibleDummy;
|
||||
return AddTokenCCInputs(cp, mtx, pk, tokenid, total, maxinputs, vopretNonfungibleDummy);
|
||||
}
|
||||
|
||||
// adds inputs from token cc addr and returns non-fungible opret payload if present
|
||||
// also sets evalcode in cp, if needed
|
||||
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, vscript_t &vopretNonfungible)
|
||||
{
|
||||
char tokenaddr[64], destaddr[64];
|
||||
int64_t threshold, nValue, price, totalinputs = 0;
|
||||
int32_t n = 0;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
|
||||
GetNonfungibleData(tokenid, vopretNonfungible);
|
||||
if (vopretNonfungible.size() > 0)
|
||||
cp->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
|
||||
|
||||
GetTokensCCaddress(cp, tokenaddr, pk);
|
||||
SetCCunspents(unspentOutputs, tokenaddr,true);
|
||||
|
||||
if (unspentOutputs.empty()) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() no utxos for token dual/three eval addr=" << tokenaddr << " evalcode=" << (int)cp->evalcode << " additionalTokensEvalcode2=" << (int)cp->additionalTokensEvalcode2 << std::endl);
|
||||
}
|
||||
|
||||
threshold = total / (maxinputs != 0 ? maxinputs : CC_MAXVINS);
|
||||
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++)
|
||||
{
|
||||
CTransaction vintx;
|
||||
uint256 hashBlock;
|
||||
uint256 vintxid = it->first.txhash;
|
||||
int32_t vout = (int32_t)it->first.index;
|
||||
|
||||
if (it->second.satoshis < threshold) // this should work also for non-fungible tokens (there should be only 1 satoshi for non-fungible token issue)
|
||||
continue;
|
||||
|
||||
int32_t ivin;
|
||||
for (ivin = 0; ivin < mtx.vin.size(); ivin ++)
|
||||
if (vintxid == mtx.vin[ivin].prevout.hash && vout == mtx.vin[ivin].prevout.n)
|
||||
break;
|
||||
if (ivin != mtx.vin.size()) // that is, the tx.vout is already added to mtx.vin (in some previous calls)
|
||||
continue;
|
||||
|
||||
if (GetTransaction(vintxid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
Getscriptaddress(destaddr, vintx.vout[vout].scriptPubKey);
|
||||
if (strcmp(destaddr, tokenaddr) != 0 &&
|
||||
strcmp(destaddr, cp->unspendableCCaddr) != 0 && // TODO: check why this. Should not we add token inputs from unspendable cc addr if mypubkey is used?
|
||||
strcmp(destaddr, cp->unspendableaddr2) != 0) // or the logic is to allow to spend all available tokens (what about unspendableaddr3)?
|
||||
continue;
|
||||
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "AddTokenCCInputs() check vintx vout destaddress=" << destaddr << " amount=" << vintx.vout[vout].nValue << std::endl);
|
||||
|
||||
if ((nValue = IsTokensvout(true, true/*<--add only valid token uxtos */, cp, NULL, vintx, vout, tokenid)) > 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,vintxid, vout) == 0)
|
||||
{
|
||||
//for non-fungible tokens check payload:
|
||||
if (!vopretNonfungible.empty()) {
|
||||
vscript_t vopret;
|
||||
|
||||
// check if it is non-fungible token:
|
||||
GetNonfungibleData(tokenid, vopret);
|
||||
if (vopret != vopretNonfungible) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() found incorrect non-fungible opret payload for vintxid=" << vintxid.GetHex() << std::endl);
|
||||
continue;
|
||||
}
|
||||
// non-fungible evalCode2 cc contract should also check if there exists only one non-fungible vout with amount = 1
|
||||
}
|
||||
|
||||
|
||||
if (total != 0 && maxinputs != 0) // if it is not just to calc amount...
|
||||
mtx.vin.push_back(CTxIn(vintxid, vout, CScript()));
|
||||
|
||||
nValue = it->second.satoshis;
|
||||
totalinputs += nValue;
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "AddTokenCCInputs() adding input nValue=" << nValue << std::endl);
|
||||
n++;
|
||||
|
||||
if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "AddTokenCCInputs() found totalinputs=" << totalinputs << std::endl;
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
// checks if any token vouts are sent to 'dead' pubkey
|
||||
int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, uint256 reftokenid)
|
||||
{
|
||||
uint8_t dummyEvalCode;
|
||||
uint256 tokenIdOpret;
|
||||
std::vector<CPubKey> voutPubkeys, voutPubkeysDummy;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
vscript_t vopretExtra, vopretNonfungible;
|
||||
|
||||
uint8_t evalCode = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim
|
||||
uint8_t evalCode2 = 0; // will be checked if zero or not
|
||||
|
||||
// test vouts for possible token use-cases:
|
||||
std::vector<std::pair<CTxOut, std::string>> testVouts;
|
||||
|
||||
int32_t n = tx.vout.size();
|
||||
// just check boundaries:
|
||||
if (n == 0) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "HasBurnedTokensvouts() incorrect params: tx.vout.size() == 0, txid=" << tx.GetHash().GetHex() << std::endl);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
if (DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysDummy, oprets) == 0) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "HasBurnedTokensvouts() cannot parse opret DecodeTokenOpRet returned 0, txid=" << tx.GetHash().GetHex() << std::endl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get assets/channels/gateways token data:
|
||||
FilterOutNonCCOprets(oprets, vopretExtra); // NOTE: only 1 additional evalcode in token opret is currently supported
|
||||
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "HasBurnedTokensvouts() vopretExtra=" << HexStr(vopretExtra) << std::endl);
|
||||
|
||||
GetNonfungibleData(reftokenid, vopretNonfungible);
|
||||
|
||||
if (vopretNonfungible.size() > 0)
|
||||
evalCode = vopretNonfungible.begin()[0];
|
||||
if (vopretExtra.size() > 0)
|
||||
evalCode2 = vopretExtra.begin()[0];
|
||||
|
||||
if (evalCode == EVAL_TOKENS && evalCode2 != 0) {
|
||||
evalCode = evalCode2;
|
||||
evalCode2 = 0;
|
||||
}
|
||||
|
||||
voutPubkeys.push_back(pubkey2pk(ParseHex(CC_BURNPUBKEY)));
|
||||
|
||||
int64_t burnedAmount = 0;
|
||||
|
||||
for (int i = 0; i < tx.vout.size(); i++) {
|
||||
|
||||
if (tx.vout[i].scriptPubKey.IsPayToCryptoCondition())
|
||||
{
|
||||
// make all possible token vouts for dead pk:
|
||||
for (std::vector<CPubKey>::iterator it = voutPubkeys.begin(); it != voutPubkeys.end(); it++) {
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[i].nValue, *it), std::string("single-eval cc1 burn pk")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[i].nValue, *it), std::string("three-eval cc1 burn pk")));
|
||||
|
||||
if (evalCode2 != 0)
|
||||
// also check in backward evalcode order:
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[i].nValue, *it), std::string("three-eval cc1 burn pk backward-eval")));
|
||||
}
|
||||
|
||||
// try all test vouts:
|
||||
for (auto t : testVouts) {
|
||||
if (t.first == tx.vout[i]) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "HasBurnedTokensvouts() burned amount=" << tx.vout[i].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
burnedAmount += tx.vout[i].nValue;
|
||||
}
|
||||
}
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "HasBurnedTokensvouts() total burned=" << burnedAmount << " evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
}
|
||||
}
|
||||
|
||||
return burnedAmount;
|
||||
}
|
||||
|
||||
CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey) {
|
||||
|
||||
uint8_t funcId, evalCode;
|
||||
uint256 tokenid;
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if ((funcId = DecodeTokenOpRet(scriptPubKey, evalCode, tokenid, voutTokenPubkeys, oprets)) != 0) {
|
||||
CTransaction tokenbasetx;
|
||||
uint256 hashBlock;
|
||||
|
||||
if (myGetTransaction(tokenid, tokenbasetx, hashBlock) && tokenbasetx.vout.size() > 0) {
|
||||
vscript_t vorigpubkey;
|
||||
std::string name, desc;
|
||||
if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, desc) != 0)
|
||||
return pubkey2pk(vorigpubkey);
|
||||
}
|
||||
}
|
||||
return CPubKey(); //return invalid pubkey
|
||||
}
|
||||
|
||||
|
||||
std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, std::string description, vscript_t nonfungibleData)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; struct CCcontract_info *cp, C;
|
||||
if (tokensupply < 0) {
|
||||
CCerror = "negative tokensupply";
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() =" << CCerror << "=" << tokensupply << std::endl);
|
||||
return std::string("");
|
||||
}
|
||||
if (!nonfungibleData.empty() && tokensupply != 1) {
|
||||
CCerror = "for non-fungible tokens tokensupply should be equal to 1";
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() " << CCerror << std::endl);
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
if (name.size() > 32 || description.size() > 4096) // this is also checked on rpc level
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "name len=" << name.size() << " or description len=" << description.size() << " is too big" << std::endl);
|
||||
CCerror = "name should be <= 32, description should be <= 4096";
|
||||
return("");
|
||||
}
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, tokensupply + 2 * txfee, 64) > 0)
|
||||
{
|
||||
uint8_t destEvalCode = EVAL_TOKENS;
|
||||
if( nonfungibleData.size() > 0 )
|
||||
destEvalCode = nonfungibleData.begin()[0];
|
||||
|
||||
// NOTE: we should prevent spending fake-tokens from this marker in IsTokenvout():
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cp, NULL))); // new marker to token cc addr, burnable and validated, vout pos now changed to 0 (from 1)
|
||||
mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, tokensupply, mypk));
|
||||
//mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(cp->CChexstr) << OP_CHECKSIG)); // old marker (non-burnable because spending could not be validated)
|
||||
//mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cp, NULL))); // ...moved to vout=0 for matching with rogue-game token
|
||||
|
||||
return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), name, description, nonfungibleData)));
|
||||
}
|
||||
|
||||
CCerror = "cant find normal inputs";
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() " << CCerror << std::endl);
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
// transfer tokens to another pubkey
|
||||
// param additionalEvalCode allows transfer of dual-eval non-fungible tokens
|
||||
std::string TokenTransfer(int64_t txfee, uint256 tokenid, vscript_t destpubkey, int64_t total)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t CCchange = 0, inputs = 0; struct CCcontract_info *cp, C;
|
||||
vscript_t vopretNonfungible, vopretEmpty;
|
||||
|
||||
if (total < 0) {
|
||||
CCerror = strprintf("negative total");
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << CCerror << "=" << total << std::endl);
|
||||
return("");
|
||||
}
|
||||
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1); // seems, mask is not used anymore
|
||||
|
||||
if ((inputs = AddTokenCCInputs(cp, mtx, mypk, tokenid, total, 60, vopretNonfungible)) > 0) // NOTE: AddTokenCCInputs might set cp->additionalEvalCode which is used in FinalizeCCtx!
|
||||
{
|
||||
if (inputs < total) { //added dimxy
|
||||
CCerror = strprintf("insufficient token inputs");
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << std::endl);
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
uint8_t destEvalCode = EVAL_TOKENS;
|
||||
if (vopretNonfungible.size() > 0)
|
||||
destEvalCode = vopretNonfungible.begin()[0];
|
||||
|
||||
if (inputs > total)
|
||||
CCchange = (inputs - total);
|
||||
mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, total, pubkey2pk(destpubkey))); // if destEvalCode == EVAL_TOKENS then it is actually MakeCC1vout(EVAL_TOKENS,...)
|
||||
if (CCchange != 0)
|
||||
mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, CCchange, mypk));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(pubkey2pk(destpubkey)); // dest pubkey for validating vout
|
||||
|
||||
return FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet(tokenid, voutTokenPubkeys, std::make_pair((uint8_t)0, vopretEmpty)));
|
||||
}
|
||||
else {
|
||||
CCerror = strprintf("no token inputs");
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << total << std::endl);
|
||||
}
|
||||
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
|
||||
}
|
||||
else {
|
||||
CCerror = strprintf("insufficient normal inputs for tx fee");
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << std::endl);
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
int64_t GetTokenBalance(CPubKey pk, uint256 tokenid)
|
||||
{
|
||||
uint256 hashBlock;
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction tokentx;
|
||||
|
||||
// CCerror = strprintf("obsolete, cannot return correct value without eval");
|
||||
// return 0;
|
||||
|
||||
if (GetTransaction(tokenid, tokentx, hashBlock, false) == 0)
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "cant find tokenid" << std::endl);
|
||||
CCerror = strprintf("cant find tokenid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct CCcontract_info *cp, C;
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0));
|
||||
}
|
||||
|
||||
UniValue TokenInfo(uint256 tokenid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
uint256 hashBlock;
|
||||
CTransaction vintx;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
vscript_t vopretNonfungible;
|
||||
std::string name, description;
|
||||
struct CCcontract_info *cpTokens, tokensCCinfo;
|
||||
|
||||
cpTokens = CCinit(&tokensCCinfo, EVAL_TOKENS);
|
||||
|
||||
if( !GetTransaction(tokenid, vintx, hashBlock, false) )
|
||||
{
|
||||
fprintf(stderr, "TokenInfo() cant find tokenid\n");
|
||||
result.push_back(Pair("result", "error"));
|
||||
result.push_back(Pair("error", "cant find tokenid"));
|
||||
return(result);
|
||||
}
|
||||
if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description, oprets) != 'c')
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenInfo() passed tokenid isnt token creation txid" << std::endl);
|
||||
result.push_back(Pair("result", "error"));
|
||||
result.push_back(Pair("error", "tokenid isnt token creation txid"));
|
||||
return result;
|
||||
}
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("tokenid", tokenid.GetHex()));
|
||||
result.push_back(Pair("owner", HexStr(origpubkey)));
|
||||
result.push_back(Pair("name", name));
|
||||
|
||||
int64_t supply = 0, output;
|
||||
for (int v = 0; v < vintx.vout.size() - 1; v++)
|
||||
if ((output = IsTokensvout(false, true, cpTokens, NULL, vintx, v, tokenid)) > 0)
|
||||
supply += output;
|
||||
result.push_back(Pair("supply", supply));
|
||||
result.push_back(Pair("description", description));
|
||||
|
||||
GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible);
|
||||
if( !vopretNonfungible.empty() )
|
||||
result.push_back(Pair("data", HexStr(vopretNonfungible)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue TokenList()
|
||||
{
|
||||
UniValue result(UniValue::VARR);
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressIndexCCMarker;
|
||||
|
||||
struct CCcontract_info *cp, C; uint256 txid, hashBlock;
|
||||
CTransaction vintx; std::vector<uint8_t> origpubkey;
|
||||
std::string name, description;
|
||||
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
|
||||
auto addTokenId = [&](uint256 txid) {
|
||||
if (GetTransaction(txid, vintx, hashBlock, false) != 0) {
|
||||
if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description) != 0) {
|
||||
result.push_back(txid.GetHex());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SetCCtxids(addressIndex, cp->normaladdr,false); // find by old normal addr marker
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it = addressIndex.begin(); it != addressIndex.end(); it++) {
|
||||
addTokenId(it->first.txhash);
|
||||
}
|
||||
|
||||
SetCCunspents(addressIndexCCMarker, cp->unspendableCCaddr,true); // find by burnable validated cc addr marker
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it = addressIndexCCMarker.begin(); it != addressIndexCCMarker.end(); it++) {
|
||||
addTokenId(it->first.txhash);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
40
src/cc/CCtokens.h
Normal file
40
src/cc/CCtokens.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
CCassetstx has the functions that create the EVAL_ASSETS transactions. It is expected that rpc calls would call these functions. For EVAL_ASSETS, the rpc functions are in rpcwallet.cpp
|
||||
|
||||
CCassetsCore has functions that are used in two contexts, both during rpc transaction create time and also during the blockchain validation. Using the identical functions is a good way to prevent them from being mismatched. The must match or the transaction will get rejected.
|
||||
*/
|
||||
|
||||
#ifndef CC_TOKENS_H
|
||||
#define CC_TOKENS_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
// CCcustom
|
||||
bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
|
||||
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description, std::vector<uint8_t> nonfungibleData);
|
||||
std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector<uint8_t> destpubkey, int64_t total);
|
||||
int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, uint256 reftokenid);
|
||||
CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey);
|
||||
|
||||
int64_t GetTokenBalance(CPubKey pk, uint256 tokenid);
|
||||
UniValue TokenInfo(uint256 tokenid);
|
||||
UniValue TokenList();
|
||||
|
||||
#endif
|
||||
296
src/cc/CCtokensOpRet.cpp
Normal file
296
src/cc/CCtokensOpRet.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
// encode decode tokens opret
|
||||
// (moved to a separate file to enable linking lib common.so with importcoin.cpp)
|
||||
|
||||
#include "CCtokens.h"
|
||||
|
||||
#ifndef IS_CHARINSTR
|
||||
#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos)
|
||||
#endif
|
||||
|
||||
// NOTE: this inital tx won't be used by other contract
|
||||
// for tokens to be used there should be at least one 't' tx with other contract's custom opret
|
||||
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, vscript_t vopretNonfungible)
|
||||
{
|
||||
/* CScript opret;
|
||||
uint8_t evalcode = EVAL_TOKENS;
|
||||
funcid = 'c'; // override the param
|
||||
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description; \
|
||||
if (!vopretNonfungible.empty()) {
|
||||
ss << (uint8_t)OPRETID_NONFUNGIBLEDATA;
|
||||
ss << vopretNonfungible;
|
||||
}); */
|
||||
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if(!vopretNonfungible.empty())
|
||||
oprets.push_back(std::make_pair(OPRETID_NONFUNGIBLEDATA, vopretNonfungible));
|
||||
return EncodeTokenCreateOpRet(funcid, origpubkey, name, description, oprets);
|
||||
}
|
||||
|
||||
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, std::vector<std::pair<uint8_t, vscript_t>> oprets)
|
||||
{
|
||||
CScript opret;
|
||||
uint8_t evalcode = EVAL_TOKENS;
|
||||
funcid = 'c'; // override the param
|
||||
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description;
|
||||
for (auto o : oprets) {
|
||||
if (o.first != 0) {
|
||||
ss << (uint8_t)o.first;
|
||||
ss << o.second;
|
||||
}
|
||||
});
|
||||
return(opret);
|
||||
}
|
||||
|
||||
// opret 'i' for imported tokens
|
||||
CScript EncodeTokenImportOpRet(std::vector<uint8_t> origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector<std::pair<uint8_t, vscript_t>> oprets)
|
||||
{
|
||||
CScript opret;
|
||||
uint8_t evalcode = EVAL_TOKENS;
|
||||
uint8_t funcid = 'i';
|
||||
|
||||
srctokenid = revuint256(srctokenid); // do not forget this
|
||||
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description << srctokenid;
|
||||
for (auto o : oprets) {
|
||||
if (o.first != 0) {
|
||||
ss << (uint8_t)o.first;
|
||||
ss << o.second;
|
||||
}
|
||||
});
|
||||
return(opret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::pair<uint8_t, vscript_t> opretWithId)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
oprets.push_back(opretWithId);
|
||||
return EncodeTokenOpRet(tokenid, voutPubkeys, oprets);
|
||||
}
|
||||
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> oprets)
|
||||
{
|
||||
CScript opret;
|
||||
uint8_t tokenFuncId = 't';
|
||||
uint8_t evalCodeInOpret = EVAL_TOKENS;
|
||||
|
||||
tokenid = revuint256(tokenid);
|
||||
|
||||
uint8_t ccType = 0;
|
||||
if (voutPubkeys.size() >= 0 && voutPubkeys.size() <= 2)
|
||||
ccType = voutPubkeys.size();
|
||||
else {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "EncodeTokenOpRet voutPubkeys.size()=" << voutPubkeys.size() << " not supported" << std::endl);
|
||||
}
|
||||
|
||||
//vopret_t vpayload;
|
||||
//GetOpReturnData(payload, vpayload);
|
||||
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType;
|
||||
if (ccType >= 1) ss << voutPubkeys[0];
|
||||
if (ccType == 2) ss << voutPubkeys[1];
|
||||
for (auto o : oprets) {
|
||||
if (o.first != 0) {
|
||||
ss << (uint8_t)o.first;
|
||||
ss << o.second;
|
||||
}
|
||||
});
|
||||
|
||||
// bad opret cases (tries to attach payload without re-serialization):
|
||||
|
||||
// error "64: scriptpubkey":
|
||||
// if (payload.size() > 0)
|
||||
// opret += payload;
|
||||
|
||||
// error "64: scriptpubkey":
|
||||
// CScript opretPayloadNoOpcode(vpayload);
|
||||
// return opret + opretPayloadNoOpcode;
|
||||
|
||||
// error "sig_aborted":
|
||||
// opret.resize(opret.size() + vpayload.size());
|
||||
// CScript::iterator it = opret.begin() + opret.size();
|
||||
// for (int i = 0; i < vpayload.size(); i++, it++)
|
||||
// *it = vpayload[i];
|
||||
|
||||
return opret;
|
||||
}
|
||||
|
||||
// overload for compatibility
|
||||
//CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload)
|
||||
//{
|
||||
// return EncodeTokenOpRet(tokenid, voutPubkeys, payload);
|
||||
//}
|
||||
|
||||
// overload for fungible tokens (no additional data in opret):
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description) {
|
||||
//vopret_t vopretNonfungibleDummy;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> opretsDummy;
|
||||
return DecodeTokenCreateOpRet(scriptPubKey, origpubkey, name, description, opretsDummy);
|
||||
}
|
||||
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
|
||||
{
|
||||
vscript_t vopret, vblob;
|
||||
uint8_t dummyEvalcode, funcid, opretId = 0;
|
||||
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
oprets.clear();
|
||||
|
||||
if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'c')
|
||||
{
|
||||
if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description;
|
||||
while (!ss.eof()) {
|
||||
ss >> opretId;
|
||||
if (!ss.eof()) {
|
||||
ss >> vblob;
|
||||
oprets.push_back(std::make_pair(opretId, vblob));
|
||||
}
|
||||
}))
|
||||
{
|
||||
return(funcid);
|
||||
}
|
||||
}
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenCreateOpRet() incorrect token create opret" << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// for imported tokens
|
||||
uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
|
||||
{
|
||||
vscript_t vopret, vblob;
|
||||
uint8_t dummyEvalcode, funcid, opretId = 0;
|
||||
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
oprets.clear();
|
||||
|
||||
if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'i')
|
||||
{
|
||||
if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description; ss >> srctokenid;
|
||||
while (!ss.eof()) {
|
||||
ss >> opretId;
|
||||
if (!ss.eof()) {
|
||||
ss >> vblob;
|
||||
oprets.push_back(std::make_pair(opretId, vblob));
|
||||
}
|
||||
}))
|
||||
{
|
||||
srctokenid = revuint256(srctokenid); // do not forget this
|
||||
return(funcid);
|
||||
}
|
||||
}
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenImportOpRet() incorrect token import opret" << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// decodes token opret:
|
||||
// for 't' returns all data from opret, vopretExtra contains other contract's data (currently only assets').
|
||||
// for 'c' and 'i' returns only funcid. NOTE: nonfungible data is not returned
|
||||
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
|
||||
{
|
||||
vscript_t vopret, vblob, dummyPubkey, vnonfungibleDummy;
|
||||
uint8_t funcId = 0, *script, dummyEvalCode, dummyFuncId, ccType, opretId = 0;
|
||||
std::string dummyName; std::string dummyDescription;
|
||||
uint256 dummySrcTokenId;
|
||||
CPubKey voutPubkey1, voutPubkey2;
|
||||
|
||||
vscript_t voldstyledata;
|
||||
bool foundOldstyle = false;
|
||||
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
tokenid = zeroid;
|
||||
oprets.clear();
|
||||
|
||||
if (script != NULL && vopret.size() > 2)
|
||||
{
|
||||
// NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set!
|
||||
// bool isEof = true;
|
||||
|
||||
evalCodeTokens = script[0];
|
||||
if (evalCodeTokens != EVAL_TOKENS) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect evalcode in tokens opret" << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
funcId = script[1];
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet decoded funcId=" << (char)(funcId ? funcId : ' ') << std::endl);
|
||||
|
||||
switch (funcId)
|
||||
{
|
||||
case 'c':
|
||||
return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, oprets);
|
||||
case 'i':
|
||||
return DecodeTokenImportOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, dummySrcTokenId, oprets);
|
||||
//break;
|
||||
case 't':
|
||||
|
||||
// compatibility with old-style rogue or assets data (with no opretid):
|
||||
// try to unmarshal old-style rogue or assets data:
|
||||
foundOldstyle = E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType;
|
||||
if (ccType >= 1) ss >> voutPubkey1;
|
||||
if (ccType == 2) ss >> voutPubkey2;
|
||||
if (!ss.eof()) {
|
||||
ss >> voldstyledata;
|
||||
}) && voldstyledata.size() >= 2 &&
|
||||
(voldstyledata.begin()[0] == 0x11 /*EVAL_ROGUE*/ && IS_CHARINSTR(voldstyledata.begin()[1], "RHQKG") ||
|
||||
voldstyledata.begin()[0] == EVAL_ASSETS && IS_CHARINSTR(voldstyledata.begin()[1], "sbSBxo")) ;
|
||||
|
||||
if (foundOldstyle || // fix for compatibility with old style data (no opretid)
|
||||
E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType;
|
||||
if (ccType >= 1) ss >> voutPubkey1;
|
||||
if (ccType == 2) ss >> voutPubkey2;
|
||||
while (!ss.eof()) {
|
||||
ss >> opretId;
|
||||
if (!ss.eof()) {
|
||||
ss >> vblob;
|
||||
oprets.push_back(std::make_pair(opretId, vblob));
|
||||
}
|
||||
}))
|
||||
{
|
||||
if (!(ccType >= 0 && ccType <= 2)) { //incorrect ccType
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// add verification pubkeys:
|
||||
voutPubkeys.clear();
|
||||
if (voutPubkey1.IsValid())
|
||||
voutPubkeys.push_back(voutPubkey1);
|
||||
if (voutPubkey2.IsValid())
|
||||
voutPubkeys.push_back(voutPubkey2);
|
||||
|
||||
tokenid = revuint256(tokenid);
|
||||
|
||||
if (foundOldstyle) { //patch for old-style opret data with no opretid
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "DecodeTokenOpRet() found old-style rogue/asset data, evalcode=" << (int)voldstyledata.begin()[0] << " funcid=" << (char)voldstyledata.begin()[1] << " for tokenid=" << revuint256(tokenid).GetHex() << std::endl);
|
||||
uint8_t opretIdRestored;
|
||||
if (voldstyledata.begin()[0] == 0x11 /*EVAL_ROGUE*/)
|
||||
opretIdRestored = OPRETID_ROGUEGAMEDATA;
|
||||
else // EVAL_ASSETS
|
||||
opretIdRestored = OPRETID_ASSETSDATA;
|
||||
|
||||
oprets.push_back(std::make_pair(opretIdRestored, voldstyledata));
|
||||
}
|
||||
|
||||
return(funcId);
|
||||
}
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() bad opret format," << " ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl);
|
||||
return (uint8_t)0;
|
||||
|
||||
default:
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() empty opret, could not parse" << std::endl);
|
||||
}
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
282
src/cc/CCtx.cpp
282
src/cc/CCtx.cpp
@@ -16,6 +16,8 @@
|
||||
#include "CCinclude.h"
|
||||
#include "key_io.h"
|
||||
|
||||
std::vector<CPubKey> NULL_pubkeys;
|
||||
|
||||
/*
|
||||
FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.
|
||||
|
||||
@@ -38,13 +40,18 @@ bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScrip
|
||||
return(false);
|
||||
}
|
||||
|
||||
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
|
||||
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret,std::vector<CPubKey> pubkeys)
|
||||
{
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
|
||||
int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0;
|
||||
int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64];
|
||||
uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*othercond3=0,*cond; CPubKey unspendablepk;
|
||||
CTransaction vintx; std::string hex; CPubKey globalpk; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
|
||||
int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0;
|
||||
int32_t i,flag,utxovout,n,err = 0;
|
||||
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], unspendabletokensaddr[64],CC1of2CCaddr[64];
|
||||
uint8_t *privkey, myprivkey[32], unspendablepriv[32], /*tokensunspendablepriv[32],*/ *msg32 = 0;
|
||||
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond=0, *condCC2=0,*mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
|
||||
CPubKey unspendablepk /*, tokensunspendablepk*/;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
globalpk = GetUnspendable(cp,0);
|
||||
n = mtx.vout.size();
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
@@ -52,17 +59,39 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
|
||||
normaloutputs += mtx.vout[i].nValue;
|
||||
totaloutputs += mtx.vout[i].nValue;
|
||||
}
|
||||
if ( (n= mtx.vin.size()) > 64 )
|
||||
if ( (n= mtx.vin.size()) > CC_MAXVINS )
|
||||
{
|
||||
fprintf(stderr,"FinalizeCCTx: %d is too many vins\n",n);
|
||||
return("0");
|
||||
}
|
||||
Myprivkey(myprivkey);
|
||||
unspendablepk = GetUnspendable(cp,unspendablepriv);
|
||||
|
||||
GetCCaddress(cp,myaddr,mypk);
|
||||
mycond = MakeCCcond1(cp->evalcode,mypk);
|
||||
GetCCaddress(cp,unspendable,unspendablepk);
|
||||
othercond = MakeCCcond1(cp->evalcode,unspendablepk);
|
||||
|
||||
// to spend from single-eval evalcode 'unspendable' cc addr
|
||||
unspendablepk = GetUnspendable(cp, unspendablepriv);
|
||||
GetCCaddress(cp, unspendable, unspendablepk);
|
||||
othercond = MakeCCcond1(cp->evalcode, unspendablepk);
|
||||
GetCCaddress1of2(cp,CC1of2CCaddr,unspendablepk,unspendablepk);
|
||||
|
||||
//fprintf(stderr,"evalcode.%d (%s)\n",cp->evalcode,unspendable);
|
||||
|
||||
// tokens support:
|
||||
// to spend from dual/three-eval mypk vout
|
||||
GetTokensCCaddress(cp, mytokensaddr, mypk);
|
||||
// NOTE: if additionalEvalcode2 is not set it is a dual-eval (not three-eval) cc cond:
|
||||
mytokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, mypk);
|
||||
|
||||
// to spend from single-eval EVAL_TOKENS mypk
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
GetCCaddress(cpTokens, mysingletokensaddr, mypk);
|
||||
mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk);
|
||||
|
||||
// to spend from dual/three-eval EVAL_TOKEN+evalcode 'unspendable' pk:
|
||||
GetTokensCCaddress(cp, unspendabletokensaddr, unspendablepk); // it may be a three-eval cc, if cp->additionalEvalcode2 is set
|
||||
othertokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, unspendablepk);
|
||||
|
||||
//Reorder vins so that for multiple normal vins all other except vin0 goes to the end
|
||||
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
|
||||
for (i=0; i<n; i++)
|
||||
@@ -127,41 +156,107 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
|
||||
else
|
||||
{
|
||||
Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey);
|
||||
//fprintf(stderr,"vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr);
|
||||
if ( strcmp(destaddr,myaddr) == 0 )
|
||||
//fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s) vs %s\n",i,(double)utxovalues[i]/COIN,destaddr,cp->unspendableaddr2);
|
||||
//std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " for vin[" << i << "] satoshis=" << utxovalues[i] << std::endl;
|
||||
if( strcmp(destaddr, myaddr) == 0 )
|
||||
{
|
||||
//fprintf(stderr, "FinalizeCCTx() matched cc myaddr (%s)\n", myaddr);
|
||||
privkey = myprivkey;
|
||||
cond = mycond;
|
||||
|
||||
}
|
||||
else if (strcmp(destaddr, mytokensaddr) == 0) // if this is TokensCC1vout
|
||||
{
|
||||
privkey = myprivkey;
|
||||
cond = mytokenscond;
|
||||
//fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout my token addr.(%s)\n",mytokensaddr);
|
||||
}
|
||||
else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout
|
||||
{
|
||||
privkey = myprivkey;
|
||||
cond = mysingletokenscond;
|
||||
//fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout my token addr.(%s)\n", mytokensaddr);
|
||||
}
|
||||
else if ( strcmp(destaddr,unspendable) == 0 )
|
||||
{
|
||||
privkey = unspendablepriv;
|
||||
cond = othercond;
|
||||
//fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable);
|
||||
//fprintf(stderr,"FinalizeCCTx evalcode(%d) matched unspendable CC addr.(%s)\n",cp->evalcode,unspendable);
|
||||
}
|
||||
else if ( strcmp(destaddr,cp->unspendableaddr2) == 0)
|
||||
else if (strcmp(destaddr, unspendabletokensaddr) == 0)
|
||||
{
|
||||
privkey = unspendablepriv;
|
||||
cond = othertokenscond;
|
||||
//fprintf(stderr,"FinalizeCCTx() matched unspendabletokensaddr dual/three-eval CC addr.(%s)\n",unspendabletokensaddr);
|
||||
}
|
||||
// check if this is the 2nd additional evalcode + 'unspendable' cc addr:
|
||||
else if ( strcmp(destaddr, cp->unspendableaddr2) == 0)
|
||||
{
|
||||
//fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2);
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2);
|
||||
privkey = cp->unspendablepriv2;
|
||||
if ( othercond2 == 0 && cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR )
|
||||
othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2);
|
||||
else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR) )
|
||||
othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3);
|
||||
if( othercond2 == 0 )
|
||||
othercond2 = MakeCCcond1(cp->unspendableEvalcode2, cp->unspendablepk2);
|
||||
cond = othercond2;
|
||||
}
|
||||
// check if this is 3rd additional evalcode + 'unspendable' cc addr:
|
||||
else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
|
||||
{
|
||||
//fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3);
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3);
|
||||
privkey = cp->unspendablepriv3;
|
||||
if ( othercond3 == 0 )
|
||||
othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
|
||||
if( othercond3 == 0 )
|
||||
othercond3 = MakeCCcond1(cp->unspendableEvalcode3, cp->unspendablepk3);
|
||||
cond = othercond3;
|
||||
}
|
||||
// check if this is spending from 1of2 cc coins addr:
|
||||
else if (strcmp(cp->coins1of2addr, destaddr) == 0)
|
||||
{
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr);
|
||||
privkey = cp->coins1of2priv;//myprivkey;
|
||||
if (othercond1of2 == 0)
|
||||
othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]);
|
||||
cond = othercond1of2;
|
||||
}
|
||||
else if ( strcmp(CC1of2CCaddr,destaddr) == 0 )
|
||||
{
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s CC1of2CCaddr!\n",CC1of2CCaddr);
|
||||
privkey = unspendablepriv;
|
||||
if (condCC2 == 0)
|
||||
condCC2 = MakeCCcond1of2(cp->evalcode,unspendablepk,unspendablepk);
|
||||
cond = condCC2;
|
||||
}
|
||||
// check if this is spending from 1of2 cc tokens addr:
|
||||
else if (strcmp(cp->tokens1of2addr, destaddr) == 0)
|
||||
{
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr);
|
||||
privkey = myprivkey;
|
||||
if (othercond1of2tokens == 0)
|
||||
// NOTE: if additionalEvalcode2 is not set then it is dual-eval cc else three-eval cc
|
||||
// TODO: verify evalcodes order if additionalEvalcode2 is not 0
|
||||
othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->additionalTokensEvalcode2, cp->tokens1of2pk[0], cp->tokens1of2pk[1]);
|
||||
cond = othercond1of2tokens;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
|
||||
continue;
|
||||
flag = 0;
|
||||
if ( pubkeys != NULL_pubkeys )
|
||||
{
|
||||
char coinaddr[64];
|
||||
GetCCaddress1of2(cp,coinaddr,globalpk,pubkeys[i]);
|
||||
//fprintf(stderr,"%s + %s -> %s vs %s\n",HexStr(globalpk).c_str(),HexStr(pubkeys[i]).c_str(),coinaddr,destaddr);
|
||||
if ( strcmp(destaddr,coinaddr) == 0 )
|
||||
{
|
||||
privkey = cp->CCpriv;
|
||||
if ( othercond4 != 0 )
|
||||
cc_free(othercond4);
|
||||
othercond4 = MakeCCcond1of2(cp->evalcode,globalpk,pubkeys[i]);
|
||||
cond = othercond4;
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
if ( flag == 0 )
|
||||
{
|
||||
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
|
||||
return("");
|
||||
}
|
||||
}
|
||||
uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
|
||||
if ( cc_signTreeSecp256k1Msg32(cond,privkey,sighash.begin()) != 0 )
|
||||
@@ -178,25 +273,40 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"vini.%d has CC signing error address.(%s)\n",i,destaddr);
|
||||
return("");
|
||||
}
|
||||
}
|
||||
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
|
||||
}
|
||||
}
|
||||
if ( mycond != 0 )
|
||||
cc_free(mycond);
|
||||
if ( condCC2 != 0 )
|
||||
cc_free(condCC2);
|
||||
if ( othercond != 0 )
|
||||
cc_free(othercond);
|
||||
if ( othercond2 != 0 )
|
||||
cc_free(othercond2);
|
||||
if ( othercond3 != 0 )
|
||||
cc_free(othercond3);
|
||||
if ( othercond4 != 0 )
|
||||
cc_free(othercond4);
|
||||
if ( othercond1of2 != 0 )
|
||||
cc_free(othercond1of2);
|
||||
if ( othercond1of2tokens != 0 )
|
||||
cc_free(othercond1of2tokens);
|
||||
if ( mytokenscond != 0 )
|
||||
cc_free(mytokenscond);
|
||||
if ( mysingletokenscond != 0 )
|
||||
cc_free(mysingletokenscond);
|
||||
if ( othertokenscond != 0 )
|
||||
cc_free(othertokenscond);
|
||||
std::string strHex = EncodeHexTx(mtx);
|
||||
if ( strHex.size() > 0 )
|
||||
return(strHex);
|
||||
else return("0");
|
||||
}
|
||||
|
||||
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr)
|
||||
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr,bool ccflag)
|
||||
{
|
||||
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
|
||||
n = (int32_t)strlen(coinaddr);
|
||||
@@ -205,7 +315,7 @@ void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValu
|
||||
for (i=0; i<=n; i++)
|
||||
ptr[i] = coinaddr[i];
|
||||
CBitcoinAddress address(addrstr);
|
||||
if ( address.GetIndexKey(hashBytes, type) == 0 )
|
||||
if ( address.GetIndexKey(hashBytes, type, ccflag) == 0 )
|
||||
return;
|
||||
addresses.push_back(std::make_pair(hashBytes,type));
|
||||
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
|
||||
@@ -215,7 +325,7 @@ void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValu
|
||||
}
|
||||
}
|
||||
|
||||
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr)
|
||||
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr,bool ccflag)
|
||||
{
|
||||
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
|
||||
n = (int32_t)strlen(coinaddr);
|
||||
@@ -224,7 +334,7 @@ void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex
|
||||
for (i=0; i<=n; i++)
|
||||
ptr[i] = coinaddr[i];
|
||||
CBitcoinAddress address(addrstr);
|
||||
if ( address.GetIndexKey(hashBytes, type) == 0 )
|
||||
if ( address.GetIndexKey(hashBytes, type, ccflag) == 0 )
|
||||
return;
|
||||
addresses.push_back(std::make_pair(hashBytes,type));
|
||||
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
|
||||
@@ -234,10 +344,10 @@ void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex
|
||||
}
|
||||
}
|
||||
|
||||
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
|
||||
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout,int32_t CCflag)
|
||||
{
|
||||
uint256 txid; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,CCflag!=0?true:false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -247,10 +357,56 @@ int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t CCaddress_balance(char *coinaddr)
|
||||
int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag,int32_t lockflag)
|
||||
{
|
||||
CCoins coins;
|
||||
//fprintf(stderr,"CCgettxoud %s/v%d\n",txid.GetHex().c_str(),vout);
|
||||
if ( mempoolflag != 0 )
|
||||
{
|
||||
if ( lockflag != 0 )
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
CCoinsViewMemPool view(pcoinsTip, mempool);
|
||||
if (!view.GetCoins(txid, coins))
|
||||
return(-1);
|
||||
else if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) != 0 )
|
||||
return(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
CCoinsViewMemPool view(pcoinsTip, mempool);
|
||||
if (!view.GetCoins(txid, coins))
|
||||
return(-1);
|
||||
else if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) != 0 )
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pcoinsTip->GetCoins(txid, coins))
|
||||
return(-1);
|
||||
}
|
||||
if ( vout < coins.vout.size() )
|
||||
return(coins.vout[vout].nValue);
|
||||
else return(-1);
|
||||
}
|
||||
|
||||
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout)
|
||||
{
|
||||
CSpentIndexKey key(txid, vout);
|
||||
CSpentIndexValue value;
|
||||
if ( !GetSpentIndex(key, value) )
|
||||
return(-1);
|
||||
spenttxid = value.txid;
|
||||
vini = (int32_t)value.inputIndex;
|
||||
height = value.blockHeight;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t CCaddress_balance(char *coinaddr,int32_t CCflag)
|
||||
{
|
||||
int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,CCflag!=0?true:false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
sum += it->second.satoshis;
|
||||
@@ -261,28 +417,33 @@ int64_t CCaddress_balance(char *coinaddr)
|
||||
int64_t CCfullsupply(uint256 tokenid)
|
||||
{
|
||||
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
|
||||
if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
if ( myGetTransaction(tokenid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
{
|
||||
if ( DecodeAssetCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description) > 0 )
|
||||
if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description))
|
||||
{
|
||||
return(tx.vout[0].nValue);
|
||||
return(tx.vout[1].nValue);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
|
||||
int64_t CCtoken_balance(char *coinaddr,uint256 reftokenid)
|
||||
{
|
||||
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector<uint8_t> origpubkey;
|
||||
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 tokenid,txid,hashBlock;
|
||||
std::vector<uint8_t> vopretExtra;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
uint8_t evalCode;
|
||||
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
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 )
|
||||
if ( myGetTransaction(txid,tx,hashBlock) != 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 )
|
||||
char str[65];
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, oprets) != 0 && reftokenid == tokenid))
|
||||
{
|
||||
sum += it->second.satoshis;
|
||||
}
|
||||
@@ -348,16 +509,18 @@ 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=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;
|
||||
int32_t abovei,belowi,ind,vout,i,n = 0; 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);
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
|
||||
threshold = total/(maxinputs+1);
|
||||
if ( maxinputs > maxutxos )
|
||||
maxutxos = maxinputs;
|
||||
utxos = (struct CC_utxo *)calloc(CC_MAXVINS,sizeof(*utxos));
|
||||
if ( maxinputs > CC_MAXVINS )
|
||||
maxinputs = CC_MAXVINS;
|
||||
if ( maxinputs > 0 )
|
||||
threshold = total/maxinputs;
|
||||
else threshold = total;
|
||||
sum = 0;
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
{
|
||||
@@ -384,7 +547,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
|
||||
if ( i != n )
|
||||
continue;
|
||||
}
|
||||
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
up = &utxos[n++];
|
||||
up->txid = txid;
|
||||
@@ -392,7 +555,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
|
||||
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 || sum >= total )
|
||||
if ( n >= maxinputs || sum >= total )
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -438,18 +601,19 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up;
|
||||
int32_t abovei,belowi,ind,vout,i,n = 0; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
|
||||
threshold = total/(maxinputs+1);
|
||||
if ( maxinputs > maxutxos )
|
||||
maxutxos = maxinputs;
|
||||
utxos = (struct CC_utxo *)calloc(CC_MAXVINS,sizeof(*utxos));
|
||||
if ( maxinputs > CC_MAXVINS )
|
||||
maxinputs = CC_MAXVINS;
|
||||
if ( maxinputs > 0 )
|
||||
threshold = total/maxinputs;
|
||||
else threshold = total;
|
||||
sum = 0;
|
||||
Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -475,7 +639,7 @@ int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinput
|
||||
if ( i != n )
|
||||
continue;
|
||||
}
|
||||
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
up = &utxos[n++];
|
||||
up->txid = txid;
|
||||
@@ -483,7 +647,7 @@ int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinput
|
||||
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 || sum >= total )
|
||||
if ( n >= maxinputs || sum >= total )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
105
src/cc/CCutilbits.cpp
Normal file
105
src/cc/CCutilbits.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
CCutilbits.cpp has very low level functions that are universally useful for all contracts and have low dependency from other sources
|
||||
*/
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "komodo_structs.h"
|
||||
|
||||
int32_t unstringbits(char *buf,uint64_t bits)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i<8; i++,bits>>=8)
|
||||
if ( (buf[i]= (char)(bits & 0xff)) == 0 )
|
||||
break;
|
||||
buf[i] = 0;
|
||||
return(i);
|
||||
}
|
||||
|
||||
uint64_t stringbits(char *str)
|
||||
{
|
||||
uint64_t bits = 0;
|
||||
if ( str == 0 )
|
||||
return(0);
|
||||
int32_t i,n = (int32_t)strlen(str);
|
||||
if ( n > 8 )
|
||||
n = 8;
|
||||
for (i=n-1; i>=0; i--)
|
||||
bits = (bits << 8) | (str[i] & 0xff);
|
||||
//printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits);
|
||||
return(bits);
|
||||
}
|
||||
|
||||
uint256 revuint256(uint256 txid)
|
||||
{
|
||||
uint256 revtxid; int32_t i;
|
||||
for (i=31; i>=0; i--)
|
||||
((uint8_t *)&revtxid)[31-i] = ((uint8_t *)&txid)[i];
|
||||
return(revtxid);
|
||||
}
|
||||
|
||||
char *uint256_str(char *dest,uint256 txid)
|
||||
{
|
||||
int32_t i,j=0;
|
||||
for (i=31; i>=0; i--)
|
||||
sprintf(&dest[j++ * 2],"%02x",((uint8_t *)&txid)[i]);
|
||||
dest[64] = 0;
|
||||
return(dest);
|
||||
}
|
||||
|
||||
char *pubkey33_str(char *dest,uint8_t *pubkey33)
|
||||
{
|
||||
int32_t i;
|
||||
if ( pubkey33 != 0 )
|
||||
{
|
||||
for (i=0; i<33; i++)
|
||||
sprintf(&dest[i * 2],"%02x",pubkey33[i]);
|
||||
} else dest[0] = 0;
|
||||
return(dest);
|
||||
}
|
||||
|
||||
uint256 Parseuint256(const char *hexstr)
|
||||
{
|
||||
uint256 txid; int32_t i; std::vector<unsigned char> txidbytes(ParseHex(hexstr));
|
||||
memset(&txid,0,sizeof(txid));
|
||||
if ( strlen(hexstr) == 64 )
|
||||
{
|
||||
for (i=31; i>=0; i--)
|
||||
((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i];
|
||||
}
|
||||
return(txid);
|
||||
}
|
||||
|
||||
CPubKey buf2pk(uint8_t *buf33)
|
||||
{
|
||||
CPubKey pk; int32_t i; uint8_t *dest;
|
||||
dest = (uint8_t *)pk.begin();
|
||||
for (i=0; i<33; i++)
|
||||
dest[i] = buf33[i];
|
||||
return(pk);
|
||||
}
|
||||
|
||||
CPubKey pubkey2pk(std::vector<uint8_t> pubkey)
|
||||
{
|
||||
CPubKey pk; int32_t i,n; uint8_t *dest,*pubkey33;
|
||||
n = pubkey.size();
|
||||
dest = (uint8_t *)pk.begin();
|
||||
pubkey33 = (uint8_t *)pubkey.data();
|
||||
for (i=0; i<n; i++)
|
||||
dest[i] = pubkey33[i];
|
||||
return(pk);
|
||||
}
|
||||
@@ -58,24 +58,114 @@ CC *MakeCCcond1(uint8_t evalcode,CPubKey pk)
|
||||
return CCNewThreshold(2, {condCC, Sig});
|
||||
}
|
||||
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk)
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, const std::vector<std::vector<unsigned char>>* vData)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeCCcond1(evalcode,pk);
|
||||
vout = CTxOut(nValue,CCPubKey(payoutCond));
|
||||
if ( vData )
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> vtmpData = std::vector<std::vector<unsigned char>>(vData->begin(), vData->end());
|
||||
std::vector<CPubKey> vPubKeys = std::vector<CPubKey>();
|
||||
vPubKeys.push_back(pk);
|
||||
COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, vtmpData);
|
||||
vout.scriptPubKey << ccp.AsVector() << OP_DROP;
|
||||
}
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
|
||||
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, const std::vector<std::vector<unsigned char>>* vData)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2);
|
||||
vout = CTxOut(nValue,CCPubKey(payoutCond));
|
||||
if ( vData )
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> vtmpData = std::vector<std::vector<unsigned char>>(vData->begin(), vData->end());
|
||||
std::vector<CPubKey> vPubKeys = std::vector<CPubKey>();
|
||||
vPubKeys.push_back(pk1);
|
||||
vPubKeys.push_back(pk2);
|
||||
COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, vtmpData);
|
||||
vout.scriptPubKey << ccp.AsVector() << OP_DROP;
|
||||
}
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) 1of2 cryptocondition:
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
// make 1of2 sigs cond
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk1));
|
||||
pks.push_back(CCNewSecp256k1(pk2));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back( CCNewEval(E_MARSHAL(ss << evalcode)) );
|
||||
if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
if( evalcode2 != 0 )
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) 1of2 cryptocondition:
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) {
|
||||
return MakeTokensCCcond1of2(evalcode, 0, pk1, pk2);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) cryptocondition:
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode)));
|
||||
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
if (evalcode2 != 0)
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // signature
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) cryptocondition:
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) {
|
||||
return MakeTokensCCcond1(evalcode, 0, pk);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) 1of2 cc vout:
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1of2(evalcode, evalcode2, pk1, pk2);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) 1of2 cc vout:
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) {
|
||||
return MakeTokensCC1of2vout(evalcode, 0, nValue, pk1, pk2);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) cc vout:
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) cc vout:
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) {
|
||||
return MakeTokensCC1vout(evalcode, 0, nValue, pk);
|
||||
}
|
||||
|
||||
|
||||
CC* GetCryptoCondition(CScript const& scriptSig)
|
||||
{
|
||||
auto pc = scriptSig.begin();
|
||||
@@ -95,106 +185,55 @@ bool IsCCInput(CScript const& scriptSig)
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t unstringbits(char *buf,uint64_t bits)
|
||||
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i<8; i++,bits>>=8)
|
||||
if ( (buf[i]= (char)(bits & 0xff)) == 0 )
|
||||
break;
|
||||
buf[i] = 0;
|
||||
return(i);
|
||||
}
|
||||
|
||||
uint64_t stringbits(char *str)
|
||||
{
|
||||
uint64_t bits = 0;
|
||||
if ( str == 0 )
|
||||
return(0);
|
||||
int32_t i,n = (int32_t)strlen(str);
|
||||
if ( n > 8 )
|
||||
n = 8;
|
||||
for (i=n-1; i>=0; i--)
|
||||
bits = (bits << 8) | (str[i] & 0xff);
|
||||
//printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits);
|
||||
return(bits);
|
||||
}
|
||||
|
||||
uint256 revuint256(uint256 txid)
|
||||
{
|
||||
uint256 revtxid; int32_t i;
|
||||
for (i=31; i>=0; i--)
|
||||
((uint8_t *)&revtxid)[31-i] = ((uint8_t *)&txid)[i];
|
||||
return(revtxid);
|
||||
}
|
||||
|
||||
char *uint256_str(char *dest,uint256 txid)
|
||||
{
|
||||
int32_t i,j=0;
|
||||
for (i=31; i>=0; i--)
|
||||
sprintf(&dest[j++ * 2],"%02x",((uint8_t *)&txid)[i]);
|
||||
dest[64] = 0;
|
||||
return(dest);
|
||||
}
|
||||
|
||||
char *pubkey33_str(char *dest,uint8_t *pubkey33)
|
||||
{
|
||||
int32_t i;
|
||||
if ( pubkey33 != 0 )
|
||||
int64_t interest; uint64_t valuein;
|
||||
CCoinsViewCache &view = *pcoinsTip;
|
||||
valuein = view.GetValueIn(height,&interest,tx,blocktime);
|
||||
if ( valuein-tx.GetValueOut() > txfee )
|
||||
{
|
||||
for (i=0; i<33; i++)
|
||||
sprintf(&dest[i * 2],"%02x",pubkey33[i]);
|
||||
} else dest[0] = 0;
|
||||
return(dest);
|
||||
}
|
||||
|
||||
uint256 Parseuint256(char *hexstr)
|
||||
{
|
||||
uint256 txid; int32_t i; std::vector<unsigned char> txidbytes(ParseHex(hexstr));
|
||||
memset(&txid,0,sizeof(txid));
|
||||
if ( strlen(hexstr) == 64 )
|
||||
{
|
||||
for (i=31; i>=0; i--)
|
||||
((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i];
|
||||
//fprintf(stderr, "txfee.%li vs txfee.%li\n", valuein-tx.GetValueOut(), txfee);
|
||||
return false;
|
||||
}
|
||||
return(txid);
|
||||
}
|
||||
|
||||
CPubKey buf2pk(uint8_t *buf33)
|
||||
{
|
||||
CPubKey pk; int32_t i; uint8_t *dest;
|
||||
dest = (uint8_t *)pk.begin();
|
||||
for (i=0; i<33; i++)
|
||||
dest[i] = buf33[i];
|
||||
return(pk);
|
||||
}
|
||||
|
||||
CPubKey pubkey2pk(std::vector<uint8_t> pubkey)
|
||||
{
|
||||
CPubKey pk; int32_t i,n; uint8_t *dest,*pubkey33;
|
||||
n = pubkey.size();
|
||||
dest = (uint8_t *)pk.begin();
|
||||
pubkey33 = (uint8_t *)pubkey.data();
|
||||
for (i=0; i<n; i++)
|
||||
dest[i] = pubkey33[i];
|
||||
return(pk);
|
||||
return true;
|
||||
}
|
||||
|
||||
// set additional 'unspendable' addr
|
||||
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
|
||||
{
|
||||
cp->evalcode2 = evalcode;
|
||||
cp->unspendableEvalcode2 = evalcode;
|
||||
cp->unspendablepk2 = pk;
|
||||
memcpy(cp->unspendablepriv2,priv,32);
|
||||
strcpy(cp->unspendableaddr2,coinaddr);
|
||||
}
|
||||
|
||||
// set yet another additional 'unspendable' addr
|
||||
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
|
||||
{
|
||||
cp->evalcode3 = evalcode;
|
||||
cp->unspendableEvalcode3 = evalcode;
|
||||
cp->unspendablepk3 = pk;
|
||||
memcpy(cp->unspendablepriv3,priv,32);
|
||||
strcpy(cp->unspendableaddr3,coinaddr);
|
||||
}
|
||||
|
||||
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 cryptocondition vout:
|
||||
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2,uint8_t *priv,char *coinaddr)
|
||||
{
|
||||
cp->coins1of2pk[0] = pk1;
|
||||
cp->coins1of2pk[1] = pk2;
|
||||
memcpy(cp->coins1of2priv,priv,32);
|
||||
strcpy(cp->coins1of2addr,coinaddr);
|
||||
}
|
||||
|
||||
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 token cryptocondition vout
|
||||
// to get tokenaddr use GetTokensCCaddress()
|
||||
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *tokenaddr)
|
||||
{
|
||||
cp->tokens1of2pk[0] = pk1;
|
||||
cp->tokens1of2pk[1] = pk2;
|
||||
strcpy(cp->tokens1of2addr, tokenaddr);
|
||||
}
|
||||
|
||||
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
|
||||
{
|
||||
CTxDestination address; txnouttype whichType;
|
||||
@@ -207,6 +246,18 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t taddr,uint8_t prefix, uint8_t prefix2)
|
||||
{
|
||||
CTxDestination address; txnouttype whichType;
|
||||
if ( ExtractDestination(scriptPubKey,address) != 0 )
|
||||
{
|
||||
strcpy(destaddr,(char *)CCustomBitcoinAddress(address,taddr,prefix,prefix2).ToString().c_str());
|
||||
return(true);
|
||||
}
|
||||
//fprintf(stderr,"ExtractDestination failed\n");
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
|
||||
CTransaction &txOut, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> ¶ms)
|
||||
{
|
||||
@@ -267,6 +318,16 @@ CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
|
||||
return(pk);
|
||||
}
|
||||
|
||||
CPubKey CCCustomtxidaddr(char *txidaddr,uint256 txid,uint8_t taddr,uint8_t prefix,uint8_t prefix2)
|
||||
{
|
||||
uint8_t buf33[33]; CPubKey pk;
|
||||
buf33[0] = 0x02;
|
||||
endiancpy(&buf33[1],(uint8_t *)&txid,32);
|
||||
pk = buf2pk(buf33);
|
||||
GetCustomscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG,taddr,prefix,prefix2);
|
||||
return(pk);
|
||||
}
|
||||
|
||||
bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
|
||||
{
|
||||
CC *payoutCond;
|
||||
@@ -287,6 +348,28 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
|
||||
return(_GetCCaddress(destaddr,cp->evalcode,pk));
|
||||
}
|
||||
|
||||
bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
|
||||
{
|
||||
CC *payoutCond;
|
||||
destaddr[0] = 0;
|
||||
if ((payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk)) != 0)
|
||||
{
|
||||
Getscriptaddress(destaddr, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
}
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
|
||||
// get scriptPubKey adddress for three/dual eval token cc vout
|
||||
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk)
|
||||
{
|
||||
destaddr[0] = 0;
|
||||
if (pk.size() == 0)
|
||||
pk = GetUnspendable(cp, 0);
|
||||
return(_GetTokensCCaddress(destaddr, cp->evalcode, cp->additionalTokensEvalcode2, pk));
|
||||
}
|
||||
|
||||
|
||||
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
|
||||
{
|
||||
CC *payoutCond;
|
||||
@@ -299,17 +382,30 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
|
||||
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue)
|
||||
// get scriptPubKey adddress for three/dual eval token 1of2 cc vout
|
||||
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2)
|
||||
{
|
||||
CC *payoutCond;
|
||||
destaddr[0] = 0;
|
||||
if ((payoutCond = MakeTokensCCcond1of2(cp->evalcode, cp->additionalTokensEvalcode2, pk, pk2)) != 0) // if additionalTokensEvalcode2 not set then it is dual-eval cc else three-eval cc
|
||||
{
|
||||
Getscriptaddress(destaddr, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
}
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
|
||||
bool ConstrainVout(CTxOut vout, int32_t CCflag, char *cmpaddr, int64_t nValue)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
|
||||
{
|
||||
fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n",vout.scriptPubKey.IsPayToCryptoCondition(),CCflag);
|
||||
fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n", vout.scriptPubKey.IsPayToCryptoCondition(), CCflag);
|
||||
return(false);
|
||||
}
|
||||
else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
|
||||
else if ( cmpaddr != 0 && (Getscriptaddress(destaddr, vout.scriptPubKey) == 0 || strcmp(destaddr, cmpaddr) != 0) )
|
||||
{
|
||||
fprintf(stderr,"constrain vout error addr %s vs %s\n",cmpaddr!=0?cmpaddr:"",destaddr!=0?destaddr:"");
|
||||
fprintf(stderr,"constrain vout error: check addr %s vs script addr %s\n", cmpaddr!=0?cmpaddr:"", destaddr!=0?destaddr:"");
|
||||
return(false);
|
||||
}
|
||||
else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || (
|
||||
@@ -345,6 +441,20 @@ bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t n
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool priv2addr(char *coinaddr,uint8_t *buf33,uint8_t priv32[32])
|
||||
{
|
||||
CKey priv; CPubKey pk; int32_t i; uint8_t *src;
|
||||
priv.SetKey32(priv32);
|
||||
pk = priv.GetPubKey();
|
||||
if ( buf33 != 0 )
|
||||
{
|
||||
src = (uint8_t *)pk.begin();
|
||||
for (i=0; i<33; i++)
|
||||
buf33[i] = src[i];
|
||||
}
|
||||
return(Getscriptaddress(coinaddr, CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Mypubkey()
|
||||
{
|
||||
extern uint8_t NOTARY_PUBKEY33[33];
|
||||
@@ -359,7 +469,7 @@ std::vector<uint8_t> Mypubkey()
|
||||
|
||||
bool Myprivkey(uint8_t myprivkey[])
|
||||
{
|
||||
char coinaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret;
|
||||
char coinaddr[64],checkaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret; uint8_t buf33[33];
|
||||
if ( Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG) != 0 )
|
||||
{
|
||||
n = (int32_t)strlen(coinaddr);
|
||||
@@ -380,7 +490,13 @@ bool Myprivkey(uint8_t myprivkey[])
|
||||
fprintf(stderr,"0x%02x, ",myprivkey[i]);
|
||||
fprintf(stderr," found privkey for %s!\n",dest);
|
||||
}
|
||||
return(true);
|
||||
if ( priv2addr(checkaddr,buf33,myprivkey) != 0 )
|
||||
{
|
||||
if ( buf2pk(buf33) == Mypubkey() && strcmp(checkaddr,coinaddr) == 0 )
|
||||
return(true);
|
||||
else printf("mismatched privkey -> addr %s vs %s\n",checkaddr,coinaddr);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -396,39 +512,10 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
|
||||
return(pubkey2pk(ParseHex(cp->CChexstr)));
|
||||
}
|
||||
|
||||
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
|
||||
void CCclearvars(struct CCcontract_info *cp)
|
||||
{
|
||||
CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
|
||||
height = KOMODO_CONNECTING;
|
||||
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
|
||||
return(true);
|
||||
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
|
||||
return eval->Invalid("CC are disabled or not active yet");
|
||||
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
|
||||
{
|
||||
from_mempool = 1;
|
||||
height &= ((1<<30) - 1);
|
||||
}
|
||||
//fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
|
||||
// there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example
|
||||
//txid = ctx.GetHash();
|
||||
//if ( txid == cp->prevtxid )
|
||||
// return(true);
|
||||
//fprintf(stderr,"process CC %02x\n",cp->evalcode);
|
||||
cp->evalcode2 = cp->evalcode3 = 0;
|
||||
cp->unspendableEvalcode2 = cp->unspendableEvalcode3 = 0;
|
||||
cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0;
|
||||
if ( paramsNull.size() != 0 ) // Don't expect params
|
||||
return eval->Invalid("Cannot have params");
|
||||
//else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses
|
||||
// return eval->Invalid("no-vouts");
|
||||
else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"done CC %02x\n",cp->evalcode);
|
||||
//cp->prevtxid = txid;
|
||||
return(true);
|
||||
}
|
||||
//fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
|
||||
return(false);
|
||||
}
|
||||
|
||||
int64_t CCduration(int32_t &numblocks,uint256 txid)
|
||||
@@ -462,6 +549,95 @@ int64_t CCduration(int32_t &numblocks,uint256 txid)
|
||||
return(duration);
|
||||
}
|
||||
|
||||
uint256 CCOraclesReverseScan(char const *logcategory,uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
|
||||
{
|
||||
CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts;
|
||||
int64_t val,merkleht; CPubKey pk; std::vector<uint8_t>data; char str[65],str2[65];
|
||||
|
||||
txid = zeroid;
|
||||
LogPrint(logcategory,"start reverse scan %s\n",uint256_str(str,batontxid));
|
||||
while ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
{
|
||||
LogPrint(logcategory,"check %s\n",uint256_str(str,batontxid));
|
||||
if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid )
|
||||
{
|
||||
LogPrint(logcategory,"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 )
|
||||
{
|
||||
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());
|
||||
|
||||
LogPrint(logcategory,"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;
|
||||
LogPrint(logcategory,"set txid\n");
|
||||
return(mhash);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(logcategory,"missing hash\n");
|
||||
return(zeroid);
|
||||
}
|
||||
}
|
||||
else LogPrint(logcategory,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height);
|
||||
batontxid = bhash;
|
||||
LogPrint(logcategory,"new hash %s\n",uint256_str(str,batontxid));
|
||||
} else break;
|
||||
}
|
||||
LogPrint(logcategory,"end of loop\n");
|
||||
return(zeroid);
|
||||
}
|
||||
|
||||
int32_t myIs_coinaddr_inmempoolvout(char const *logcategory,char *coinaddr)
|
||||
{
|
||||
int32_t i,n; char destaddr[64];
|
||||
BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
|
||||
{
|
||||
const CTransaction &tx = e.GetTx();
|
||||
if ( (n= tx.vout.size()) > 0 )
|
||||
{
|
||||
const uint256 &txid = tx.GetHash();
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
|
||||
if ( strcmp(destaddr,coinaddr) == 0 )
|
||||
{
|
||||
LogPrint(logcategory,"found (%s) vout in mempool\n",coinaddr);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t CCCointxidExists(char const *logcategory,uint256 cointxid)
|
||||
{
|
||||
char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock;
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
CCtxidaddr(txidaddr,cointxid);
|
||||
SetCCtxids(addressIndex,txidaddr,true);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
return(myIs_coinaddr_inmempoolvout(logcategory,txidaddr));
|
||||
}
|
||||
|
||||
/* Get the block merkle root for a proof
|
||||
* IN: proofData
|
||||
* OUT: merkle root
|
||||
* OUT: transaction IDS
|
||||
*/
|
||||
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids)
|
||||
{
|
||||
CMerkleBlock merkleBlock;
|
||||
if (!E_UNMARSHAL(proofData, ss >> merkleBlock))
|
||||
return uint256();
|
||||
return merkleBlock.txn.ExtractMatches(txids);
|
||||
}
|
||||
|
||||
bool komodo_txnotarizedconfirmed(uint256 txid)
|
||||
{
|
||||
char str[65];
|
||||
@@ -502,3 +678,112 @@ bool komodo_txnotarizedconfirmed(uint256 txid)
|
||||
return (true);
|
||||
return (false);
|
||||
}
|
||||
|
||||
CPubKey check_signing_pubkey(CScript scriptSig)
|
||||
{
|
||||
bool found = false;
|
||||
CPubKey pubkey;
|
||||
|
||||
auto findEval = [](CC *cond, struct CCVisitor _) {
|
||||
bool r = false;
|
||||
|
||||
if (cc_typeId(cond) == CC_Secp256k1) {
|
||||
*(CPubKey*)_.context=buf2pk(cond->publicKey);
|
||||
r = true;
|
||||
}
|
||||
// false for a match, true for continue
|
||||
return r ? 0 : 1;
|
||||
};
|
||||
|
||||
CC *cond = GetCryptoCondition(scriptSig);
|
||||
|
||||
if (cond) {
|
||||
CCVisitor visitor = { findEval, (uint8_t*)"", 0, &pubkey };
|
||||
bool out = !cc_visit(cond, visitor);
|
||||
cc_free(cond);
|
||||
|
||||
if (pubkey.IsValid()) {
|
||||
return pubkey;
|
||||
}
|
||||
}
|
||||
return CPubKey();
|
||||
}
|
||||
|
||||
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
|
||||
{
|
||||
CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
|
||||
height = KOMODO_CONNECTING;
|
||||
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
|
||||
return(true);
|
||||
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
|
||||
return eval->Invalid("CC are disabled or not active yet");
|
||||
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
|
||||
{
|
||||
from_mempool = 1;
|
||||
height &= ((1<<30) - 1);
|
||||
}
|
||||
if (cp->validate == NULL)
|
||||
return eval->Invalid("validation not supported for eval code");
|
||||
|
||||
//fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
|
||||
// there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example
|
||||
//txid = ctx.GetHash();
|
||||
//if ( txid == cp->prevtxid )
|
||||
// return(true);
|
||||
//fprintf(stderr,"process CC %02x\n",cp->evalcode);
|
||||
CCclearvars(cp);
|
||||
if ( paramsNull.size() != 0 ) // Don't expect params
|
||||
return eval->Invalid("Cannot have params");
|
||||
//else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses
|
||||
// return eval->Invalid("no-vouts");
|
||||
else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"done CC %02x\n",cp->evalcode);
|
||||
//cp->prevtxid = txid;
|
||||
return(true);
|
||||
}
|
||||
//fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
|
||||
return(false);
|
||||
}
|
||||
|
||||
extern struct CCcontract_info CCinfos[0x100];
|
||||
extern std::string MYCCLIBNAME;
|
||||
bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx,unsigned int nIn);
|
||||
|
||||
bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,const CTransaction &txTo,unsigned int nIn)
|
||||
{
|
||||
uint8_t evalcode; int32_t height,from_mempool; struct CCcontract_info *cp;
|
||||
if ( ASSETCHAINS_CCLIB != MYCCLIBNAME )
|
||||
{
|
||||
fprintf(stderr,"-ac_cclib=%s vs myname %s\n",ASSETCHAINS_CCLIB.c_str(),MYCCLIBNAME.c_str());
|
||||
return eval->Invalid("-ac_cclib name mismatches myname");
|
||||
}
|
||||
height = KOMODO_CONNECTING;
|
||||
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
|
||||
return(true);
|
||||
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
|
||||
return eval->Invalid("CC are disabled or not active yet");
|
||||
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
|
||||
{
|
||||
from_mempool = 1;
|
||||
height &= ((1<<30) - 1);
|
||||
}
|
||||
evalcode = cond->code[0];
|
||||
if ( evalcode >= EVAL_FIRSTUSER && evalcode <= EVAL_LASTUSER )
|
||||
{
|
||||
cp = &CCinfos[(int32_t)evalcode];
|
||||
if ( cp->didinit == 0 )
|
||||
{
|
||||
if ( CClib_initcp(cp,evalcode) == 0 )
|
||||
cp->didinit = 1;
|
||||
else return eval->Invalid("unsupported CClib evalcode");
|
||||
}
|
||||
CCclearvars(cp);
|
||||
if ( paramsNull.size() != 0 ) // Don't expect params
|
||||
return eval->Invalid("Cannot have params");
|
||||
else if ( CClib_validate(cp,height,eval,txTo,nIn) != 0 )
|
||||
return(true);
|
||||
return(false); //eval->Invalid("error in CClib_validate");
|
||||
}
|
||||
return eval->Invalid("cclib CC must have evalcode between 16 and 127");
|
||||
}
|
||||
|
||||
34
src/cc/Makefile
Normal file
34
src/cc/Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
SHELL = /bin/sh
|
||||
CC = gcc
|
||||
CC_DARWIN = g++-6
|
||||
CC_WIN = x86_64-w64-mingw32-gcc-posix
|
||||
CFLAGS_DARWIN = -std=c++11 -arch x86_64 -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -c -Wl,-undefined -Wl,dynamic_lookup -dynamiclib
|
||||
CFLAGS = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c
|
||||
CFLAGS_WIN = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c
|
||||
DEBUGFLAGS = -O0 -D _DEBUG
|
||||
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
|
||||
$(info $(OS))
|
||||
OS := $(shell uname -s)
|
||||
$(info $(OS))
|
||||
TARGET = ../libcc.so
|
||||
TARGET_DARWIN = ../libcc.dylib
|
||||
TARGET_WIN = ../libcc.dll
|
||||
SOURCES = cclib.cpp
|
||||
#HEADERS = $(shell echo ../cryptoconditions/include/*.h)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(SOURCES)
|
||||
$(info Building cclib to src/)
|
||||
ifeq ($(OS),Darwin)
|
||||
$(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) $(SOURCES)
|
||||
else ifeq ($(OS),Linux)
|
||||
$(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) $(SOURCES)
|
||||
#else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host
|
||||
else
|
||||
$(info WINDOWS)
|
||||
$(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) $(SOURCES)
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf $(TARGET)
|
||||
38
src/cc/Makefile_rogue
Normal file
38
src/cc/Makefile_rogue
Normal file
@@ -0,0 +1,38 @@
|
||||
SHELL = /bin/sh
|
||||
CC = gcc
|
||||
CC_DARWIN = g++-6
|
||||
CC_WIN = x86_64-w64-mingw32-gcc-posix
|
||||
CFLAGS_DARWIN = -DBUILD_ROGUE -std=c++11 -arch x86_64 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib
|
||||
CFLAGS = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared
|
||||
CFLAGS_WIN = -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I./rogue/x86_64-w64-mingw32/include -I./rogue/x86_64-w64-mingw32/include/ncursesw -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared
|
||||
DEBUGFLAGS = -O0 -D _DEBUG
|
||||
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
|
||||
$(info $(OS))
|
||||
OS := $(shell uname -s)
|
||||
$(info $(OS))
|
||||
TARGET = librogue.so
|
||||
TARGET_DARWIN = librogue.dylib
|
||||
TARGET_WIN = librogue.dll
|
||||
SOURCES = cclib.cpp
|
||||
#HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(SOURCES)
|
||||
$(info Building cclib to src/)
|
||||
ifeq ($(OS),Darwin)
|
||||
$(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) -c $(SOURCES)
|
||||
cp $(TARGET_DARWIN) ../libcc.dylib
|
||||
else ifeq ($(HOST),x86_64-w64-mingw32)
|
||||
$(info WINDOWS)
|
||||
$(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) -c $(SOURCES)
|
||||
cp $(TARGET_WIN) ../libcc.dll
|
||||
#else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host
|
||||
else
|
||||
$(info LINUX)
|
||||
$(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES)
|
||||
cp $(TARGET) ../libcc.so
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf $(TARGET)
|
||||
7
src/cc/README.md
Normal file
7
src/cc/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## CCLIB
|
||||
Please follow the below instructions to build the cryptoconditions library into the Komodo source directory `komodo/src` - supported operating systems are Linux, OSX and Windows (mingw crossbuild):
|
||||
|
||||
```
|
||||
make clean
|
||||
make
|
||||
```
|
||||
@@ -14,6 +14,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCassets.h"
|
||||
#include "CCtokens.h"
|
||||
|
||||
/*
|
||||
Assets can be created or transferred.
|
||||
@@ -45,32 +46,22 @@
|
||||
|
||||
valid CC output: create or transfer or buyoffer or selloffer or exchange or cancel or fill
|
||||
|
||||
create
|
||||
vin.0: normal input
|
||||
vout.0: issuance assetoshis to CC
|
||||
vout.1: tag sent to normal address of AssetsCCaddress
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['c'] [origpubkey] "<assetname>" "<description>"
|
||||
|
||||
transfer
|
||||
vin.0: normal input
|
||||
vin.1 .. vin.n-1: valid CC outputs
|
||||
vout.0 to n-2: assetoshis output to CC
|
||||
vout.n-2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid]
|
||||
|
||||
buyoffer:
|
||||
vins.*: normal inputs (bid + change)
|
||||
vout.0: amount of bid to unspendable
|
||||
vout.1: normal output for change (if any)
|
||||
vout.1: CC output for marker
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
|
||||
|
||||
cancelbuy:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
vin.2: CC marker from buyoffer for txfee
|
||||
vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
|
||||
vout.1: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid]
|
||||
vout.1: vin.2 back to users pubkey
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid] 0 0 [origpubkey]
|
||||
|
||||
fillbuy:
|
||||
vin.0: normal input
|
||||
@@ -87,8 +78,9 @@
|
||||
vin.0: normal input
|
||||
vin.1+: valid CC output for sale
|
||||
vout.0: vin.1 assetoshis output to CC to unspendable
|
||||
vout.1: CC output for change (if any)
|
||||
vout.2: normal output for change (if any)
|
||||
vout.1: CC output for marker
|
||||
vout.2: CC output for change (if any)
|
||||
vout.3: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
|
||||
|
||||
exchange:
|
||||
@@ -102,8 +94,10 @@
|
||||
cancel:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
|
||||
vin.2: CC marker from selloffer for txfee
|
||||
vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
|
||||
vout.1: normal output for change (if any)
|
||||
vout.1: vin.2 back to users pubkey
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
|
||||
|
||||
fillsell:
|
||||
@@ -133,45 +127,99 @@
|
||||
|
||||
|
||||
// tx validation
|
||||
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
static uint256 zero;
|
||||
CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2; int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector<uint8_t> origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid; char destaddr[64],origaddr[64],CCaddr[64];
|
||||
CTxDestination address;
|
||||
CTransaction vinTx, createTx;
|
||||
uint256 hashBlock, assetid, assetid2;
|
||||
int32_t i,starti, numvins, numvouts, preventCCvins, preventCCvouts;
|
||||
int64_t remaining_price, nValue, assetoshis, outputsDummy,inputs,tmpprice,totalunits,ignore;
|
||||
std::vector<uint8_t> origpubkey, tmporigpubkey, ignorepubkey, vopretNonfungible, vopretNonfungibleDummy;
|
||||
uint8_t funcid, evalCodeInOpret;
|
||||
char destaddr[64], origNormalAddr[64], origTokensCCaddr[64], origCCaddrDummy[64];
|
||||
char tokensDualEvalUnspendableCCaddr[64], origAssetsCCaddr[64];
|
||||
|
||||
//return true;
|
||||
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
outputs = inputs = 0;
|
||||
outputsDummy = inputs = 0;
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( (funcid= DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,remaining_price,origpubkey)) == 0 )
|
||||
return eval->Invalid("Invalid opreturn payload");
|
||||
fprintf(stderr,"AssetValidate (%c)\n",funcid);
|
||||
if ( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid,createTx,hashBlock) == 0 )
|
||||
|
||||
// add specific chains exceptions for old token support:
|
||||
if (strcmp(ASSETCHAINS_SYMBOL, "SEC") == 0 && chainActive.Height() <= 144073)
|
||||
return true;
|
||||
|
||||
if (strcmp(ASSETCHAINS_SYMBOL, "MGNX") == 0 && chainActive.Height() <= 210190)
|
||||
return true;
|
||||
|
||||
// add specific chains exceptions for old token support:
|
||||
if (strcmp(ASSETCHAINS_SYMBOL, "SEC") == 0 && chainActive.Height() <= 144073)
|
||||
return true;
|
||||
|
||||
if (strcmp(ASSETCHAINS_SYMBOL, "MGNX") == 0 && chainActive.Height() <= 210190)
|
||||
return true;
|
||||
|
||||
if (numvouts == 0)
|
||||
return eval->Invalid("AssetValidate: no vouts");
|
||||
|
||||
if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 )
|
||||
return eval->Invalid("AssetValidate: invalid opreturn payload");
|
||||
|
||||
// non-fungible tokens support:
|
||||
GetNonfungibleData(assetid, vopretNonfungible);
|
||||
if (vopretNonfungible.size() > 0)
|
||||
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
|
||||
|
||||
// find dual-eval tokens unspendable addr:
|
||||
GetTokensCCaddress(cpAssets, tokensDualEvalUnspendableCCaddr, GetUnspendable(cpAssets, NULL));
|
||||
// this is for marker validation:
|
||||
GetCCaddress(cpAssets, origAssetsCCaddr, origpubkey);
|
||||
|
||||
// we need this for validating single-eval tokens' vins/vous:
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
// find single-eval token user cc addr:
|
||||
//GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey));
|
||||
|
||||
//fprintf(stderr,"AssetValidate (%c)\n",funcid);
|
||||
|
||||
if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 )
|
||||
return eval->Invalid("cant find asset create txid");
|
||||
else if ( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2,createTx,hashBlock) == 0 )
|
||||
else if( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2, createTx, hashBlock) == 0 )
|
||||
return eval->Invalid("cant find asset2 create txid");
|
||||
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
|
||||
else if( IsCCInput(tx.vin[0].scriptSig) != 0 ) // vin0 should be normal vin
|
||||
return eval->Invalid("illegal asset vin0");
|
||||
else if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else if ( funcid != 'c' )
|
||||
else if( numvouts < 2 )
|
||||
return eval->Invalid("too few vouts"); // it was if(numvouts < 1) but it refers at least to vout[1] below
|
||||
else if( funcid != 'c' )
|
||||
{
|
||||
if ( funcid == 't' )
|
||||
/* if( funcid == 't' )
|
||||
starti = 0;
|
||||
else starti = 1;
|
||||
if ( assetid == zero )
|
||||
else
|
||||
starti = 1; */
|
||||
|
||||
if( assetid == zero )
|
||||
return eval->Invalid("illegal assetid");
|
||||
else if ( AssetExactAmounts(2, cp,inputs,starti,outputs,eval,tx,assetid) == false )
|
||||
return eval->Invalid("asset inputs != outputs");
|
||||
|
||||
else if (!AssetCalcAmounts(cpAssets, inputs, outputsDummy/*outputsDummy is calculated incorrectly but not used*/, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs
|
||||
return false; // returns false if some problems with reading vintxes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch ( funcid )
|
||||
switch( funcid )
|
||||
{
|
||||
case 'c': // create wont be called to be verified as it has no CC inputs
|
||||
//vin.0: normal input
|
||||
//vout.0: issuance assetoshis to CC
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['c'] [{"<assetname>":"<description>"}]
|
||||
return eval->Invalid("unexpected AssetValidate for createasset");
|
||||
//if (evalCodeInOpret == EVAL_ASSETS)
|
||||
// return eval->Invalid("unexpected AssetValidate for createasset");
|
||||
// return
|
||||
return eval->Invalid("invalid asset funcid \'c\'");
|
||||
break;
|
||||
case 't': // transfer
|
||||
//vin.0: normal input
|
||||
@@ -179,38 +227,46 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//vout.0 to n-2: assetoshis output to CC
|
||||
//vout.n-2: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid]
|
||||
if ( inputs == 0 )
|
||||
return eval->Invalid("no asset inputs for transfer");
|
||||
fprintf(stderr,"transfer validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts);
|
||||
//if (inputs == 0)
|
||||
// return eval->Invalid("no asset inputs for transfer");
|
||||
//fprintf(stderr,"transfer preliminarily validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts);
|
||||
return eval->Invalid("invalid asset funcid \'t\'");
|
||||
break;
|
||||
|
||||
case 'b': // buyoffer
|
||||
//vins.*: normal inputs (bid + change)
|
||||
//vout.0: amount of bid to unspendable
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.1: CC output for marker
|
||||
//vout.2: normal output for change (if any)
|
||||
// vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
|
||||
if ( remaining_price == 0 )
|
||||
|
||||
// as we don't use tokenconvert we should not be here:
|
||||
return eval->Invalid("invalid asset funcid (b)");
|
||||
|
||||
if( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null amount for buyoffer");
|
||||
else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr,0) == 0 ) // coins to assets unspendable cc addr
|
||||
return eval->Invalid("invalid vout for buyoffer");
|
||||
preventCCvins = 1;
|
||||
preventCCvouts = 1;
|
||||
fprintf(stderr,"buy offer validated to destaddr.(%s)\n",cp->unspendableCCaddr);
|
||||
fprintf(stderr,"buy offer validated to destaddr.(%s)\n",cpAssets->unspendableCCaddr);
|
||||
break;
|
||||
|
||||
case 'o': // cancelbuy
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
//vin.2: CC marker from buyoffer for txfee
|
||||
//vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.1: vin.2 back to users pubkey
|
||||
//vout.2: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['o']
|
||||
if ( (nValue= AssetValidateBuyvin(cp,eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, origCCaddrDummy, origNormalAddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( ConstrainVout(tx.vout[0],0,origaddr,nValue) == 0 )
|
||||
else if( ConstrainVout(tx.vout[0],0, origNormalAddr, nValue) == 0 )
|
||||
return eval->Invalid("invalid refund for cancelbuy");
|
||||
preventCCvins = 2;
|
||||
preventCCvins = 3;
|
||||
preventCCvouts = 0;
|
||||
fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origaddr);
|
||||
//fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origNormalAddr);
|
||||
break;
|
||||
|
||||
case 'B': // fillbuy:
|
||||
@@ -224,36 +280,40 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//vout.4: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
|
||||
preventCCvouts = 4;
|
||||
if ( (nValue= AssetValidateBuyvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
|
||||
if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
else if( numvouts < 4 )
|
||||
return eval->Invalid("not enough vouts for fillbuy");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
else if( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillbuy");
|
||||
else
|
||||
{
|
||||
if ( nValue != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
if( nValue != tx.vout[0].nValue + tx.vout[1].nValue )
|
||||
return eval->Invalid("locked value doesnt match vout0+1 fillbuy");
|
||||
else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
else if( tx.vout[4].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change present
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals)
|
||||
return eval->Invalid("vout2 doesnt go to origpubkey fillbuy");
|
||||
else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue )
|
||||
else if ( inputs != tx.vout[2].nValue + tx.vout[4].nValue )
|
||||
return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy");
|
||||
preventCCvouts ++;
|
||||
}
|
||||
else if ( ConstrainVout(tx.vout[2],1,CCaddr,inputs) == 0 )
|
||||
else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals)
|
||||
return eval->Invalid("vout2 doesnt match inputs fillbuy");
|
||||
else if ( ConstrainVout(tx.vout[1],0,0,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[1], 0, NULL, 0) == 0 )
|
||||
return eval->Invalid("vout1 is CC for fillbuy");
|
||||
else if ( ValidateBidRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits) == false )
|
||||
else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to asset cc addr
|
||||
return eval->Invalid("invalid marker for original pubkey");
|
||||
else if( ValidateBidRemainder(remaining_price, tx.vout[0].nValue, nValue, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
|
||||
return eval->Invalid("mismatched remainder for fillbuy");
|
||||
else if ( remaining_price != 0 )
|
||||
else if( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins to asset unspendable cc addr
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"fillbuy validated\n");
|
||||
//fprintf(stderr,"fillbuy validated\n");
|
||||
break;
|
||||
//case 'e': // selloffer
|
||||
// break; // disable swaps
|
||||
@@ -261,36 +321,48 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//vin.0: normal input
|
||||
//vin.1+: valid CC output for sale
|
||||
//vout.0: vin.1 assetoshis output to CC to unspendable
|
||||
//vout.1: CC output for change (if any)
|
||||
//vout.2: normal output for change (if any)
|
||||
//vout.1: CC output for marker
|
||||
//vout.2: CC output for change (if any)
|
||||
//vout.3: normal output for change (if any)
|
||||
//'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
|
||||
//'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
|
||||
preventCCvouts = 1;
|
||||
if ( remaining_price == 0 )
|
||||
|
||||
// as we don't use tokenconvert we should not be here:
|
||||
return eval->Invalid("invalid asset funcid (s)");
|
||||
|
||||
preventCCvouts = 2;
|
||||
if( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null remaining_price for selloffer");
|
||||
if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("invalid normal vout1 for sellvin");
|
||||
if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change presents
|
||||
{
|
||||
preventCCvouts++;
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
|
||||
else if ( tx.vout[0].nValue+tx.vout[1].nValue != inputs )
|
||||
return eval->Invalid("mismatched vout0+vout1 total for selloffer");
|
||||
} else if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,inputs) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
|
||||
if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // tokens to tokens unspendable cc addr. TODO: this in incorrect, should be assets if we got here!
|
||||
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
|
||||
else if( tx.vout[0].nValue + tx.vout[2].nValue != inputs )
|
||||
return eval->Invalid("mismatched vout0+vout2 total for selloffer");
|
||||
}
|
||||
// no cc change:
|
||||
else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // tokens to tokens unspendable cc addr TODO: this in incorrect, should be assets if got here!
|
||||
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
|
||||
//fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price);
|
||||
break;
|
||||
|
||||
case 'x': // cancel
|
||||
case 'x': // cancel sell
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
|
||||
//vin.2: CC marker from selloffer for txfee
|
||||
//vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.1: vin.2 back to users pubkey
|
||||
//vout.2: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
|
||||
if ( (assetoshis= AssetValidateSellvin(cp,eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
|
||||
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 ) // NOTE:
|
||||
return(false);
|
||||
else if ( ConstrainVout(tx.vout[0],1,CCaddr,assetoshis) == 0 )
|
||||
else if( ConstrainVout(tx.vout[0], 1, origTokensCCaddr, assetoshis) == 0 ) // tokens returning to originator cc addr
|
||||
return eval->Invalid("invalid vout for cancel");
|
||||
preventCCvins = 2;
|
||||
preventCCvins = 3;
|
||||
preventCCvouts = 1;
|
||||
break;
|
||||
|
||||
@@ -303,31 +375,35 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//'S'.vout.2: vin.2 value to original pubkey [origpubkey]
|
||||
//vout.3: normal output for change (if any)
|
||||
//'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey]
|
||||
if ( (assetoshis= AssetValidateSellvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
|
||||
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
else if( numvouts < 4 )
|
||||
return eval->Invalid("not enough vouts for fillask");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
else if( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillask");
|
||||
else
|
||||
{
|
||||
if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
if( assetoshis != tx.vout[0].nValue + tx.vout[1].nValue )
|
||||
return eval->Invalid("locked value doesnt match vout0+1 fillask");
|
||||
if ( ValidateAskRemainder(remaining_price,tx.vout[0].nValue,assetoshis,tx.vout[1].nValue,tx.vout[2].nValue,totalunits) == false )
|
||||
if( ValidateAskRemainder(remaining_price, tx.vout[0].nValue, assetoshis, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
|
||||
return eval->Invalid("mismatched remainder for fillask");
|
||||
else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[1], 1, NULL, 0) == 0 ) // do not check token buyer's cc addr
|
||||
return eval->Invalid("normal vout1 for fillask");
|
||||
else if ( ConstrainVout(tx.vout[2],0,origaddr,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[2], 0, origNormalAddr, 0) == 0 ) // coins to originator normal addr
|
||||
return eval->Invalid("normal vout1 for fillask");
|
||||
else if ( remaining_price != 0 )
|
||||
else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to originator asset cc addr
|
||||
return eval->Invalid("invalid marker for original pubkey");
|
||||
else if( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fill");
|
||||
if ( ConstrainVout(tx.vout[0], 1, tokensDualEvalUnspendableCCaddr, 0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"fill validated\n");
|
||||
//fprintf(stderr,"fill validated\n");
|
||||
break;
|
||||
case 'E': // fillexchange
|
||||
////////// not implemented yet ////////////
|
||||
return eval->Invalid("unexpected assets fillexchange funcid");
|
||||
break; // disable asset swaps
|
||||
//vin.0: normal input
|
||||
@@ -339,51 +415,63 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//vout.3: CC output for asset2 change (if any)
|
||||
//vout.3/4: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
|
||||
if ( AssetExactAmounts(1, cp,inputs,1,outputs,eval,tx,assetid2) == false )
|
||||
eval->Invalid("asset2 inputs != outputs");
|
||||
if ( (assetoshis= AssetValidateSellvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
|
||||
//if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false )
|
||||
// eval->Invalid("asset2 inputs != outputs");
|
||||
|
||||
////////// not implemented yet ////////////
|
||||
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
else if( numvouts < 3 )
|
||||
return eval->Invalid("not enough vouts for fillex");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
else if( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillex");
|
||||
else
|
||||
{
|
||||
if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
if( assetoshis != tx.vout[0].nValue + tx.vout[1].nValue )
|
||||
return eval->Invalid("locked value doesnt match vout0+1 fillex");
|
||||
else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
////////// not implemented yet ////////////
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 )
|
||||
return eval->Invalid("vout2 doesnt go to origpubkey fillex");
|
||||
else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue )
|
||||
else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue )
|
||||
{
|
||||
fprintf(stderr,"inputs %.8f != %.8f + %.8f\n",(double)inputs/COIN,(double)tx.vout[2].nValue/COIN,(double)tx.vout[3].nValue/COIN);
|
||||
return eval->Invalid("asset inputs doesnt match vout2+3 fillex");
|
||||
}
|
||||
}
|
||||
else if ( ConstrainVout(tx.vout[2],1,CCaddr,inputs) == 0 )
|
||||
////////// not implemented yet ////////////
|
||||
else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 )
|
||||
return eval->Invalid("vout2 doesnt match inputs fillex");
|
||||
else if ( ConstrainVout(tx.vout[1],0,0,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 )
|
||||
return eval->Invalid("vout1 is CC for fillex");
|
||||
fprintf(stderr,"assets vout0 %llu, vin1 %llu, vout2 %llu -> orig, vout1 %llu, total %llu\n",(long long)tx.vout[0].nValue,(long long)assetoshis,(long long)tx.vout[2].nValue,(long long)tx.vout[1].nValue,(long long)totalunits);
|
||||
if ( ValidateSwapRemainder(remaining_price,tx.vout[0].nValue,assetoshis,tx.vout[1].nValue,tx.vout[2].nValue,totalunits) == false )
|
||||
if( ValidateSwapRemainder(remaining_price, tx.vout[0].nValue, assetoshis,tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
|
||||
return eval->Invalid("mismatched remainder for fillex");
|
||||
else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 )
|
||||
////////// not implemented yet ////////////
|
||||
return eval->Invalid("normal vout1 for fillex");
|
||||
else if ( remaining_price != 0 )
|
||||
else if( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) // TODO: unsure about this, but this is not impl yet anyway
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillex");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"fill validated\n");
|
||||
////////// not implemented yet ////////////
|
||||
//fprintf(stderr,"fill validated\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"illegal assets funcid.(%c)\n",funcid);
|
||||
return eval->Invalid("unexpected assets funcid");
|
||||
break;
|
||||
//break;
|
||||
}
|
||||
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
|
||||
// what does this do?
|
||||
bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts); // seems we do not need this call as we already checked vouts well
|
||||
//std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl;
|
||||
return (bPrevent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ bool AuctionExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransactio
|
||||
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any auction CC for now
|
||||
return eval->Invalid("no validation yet");
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
@@ -124,7 +124,7 @@ int64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPu
|
||||
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);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
|
||||
705
src/cc/cclib.cpp
Normal file
705
src/cc/cclib.cpp
Normal file
@@ -0,0 +1,705 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
#include "primitives/block.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "script/cc.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/utils.h"
|
||||
#include "cc/CCinclude.h"
|
||||
#include "main.h"
|
||||
#include "chain.h"
|
||||
#include "core_io.h"
|
||||
#include "crosschain.h"
|
||||
|
||||
#define FAUCET2SIZE COIN
|
||||
#define EVAL_FAUCET2 EVAL_FIRSTUSER
|
||||
|
||||
#ifdef BUILD_ROGUE
|
||||
#define EVAL_ROGUE 17
|
||||
std::string MYCCLIBNAME = (char *)"rogue";
|
||||
|
||||
|
||||
#elif BUILD_CUSTOMCC
|
||||
#include "customcc.h"
|
||||
|
||||
#elif BUILD_GAMESCC
|
||||
#include "gamescc.h"
|
||||
|
||||
#else
|
||||
#define EVAL_SUDOKU 17
|
||||
#define EVAL_MUSIG 18
|
||||
#define EVAL_DILITHIUM 19
|
||||
std::string MYCCLIBNAME = (char *)"sudoku";
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_GAMESCC
|
||||
void komodo_netevent(std::vector<uint8_t> payload) {}
|
||||
#endif
|
||||
|
||||
extern std::string MYCCLIBNAME;
|
||||
|
||||
char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); }
|
||||
|
||||
struct CClib_rpcinfo
|
||||
{
|
||||
char *CCname,*method,*help;
|
||||
int32_t numrequiredargs,maxargs;
|
||||
uint8_t funcid,evalcode;
|
||||
}
|
||||
|
||||
CClib_methods[] =
|
||||
{
|
||||
{ (char *)"faucet2", (char *)"fund", (char *)"amount", 1, 1, 'F', EVAL_FAUCET2 },
|
||||
{ (char *)"faucet2", (char *)"get", (char *)"<no args>", 0, 0, 'G', EVAL_FAUCET2 },
|
||||
#ifdef BUILD_ROGUE
|
||||
{ (char *)"rogue", (char *)"newgame", (char *)"maxplayers buyin", 0, 2, 'G', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"gameinfo", (char *)"gametxid", 1, 1, 'T', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"pending", (char *)"<no args>", 0, 0, 'P', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"keystrokes", (char *)"gametxid keystrokes", 2, 2, 'K', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"bailout", (char *)"gametxid", 1, 1, 'Q', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"playerinfo", (char *)"playertxid", 1, 1, 'I', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"players", (char *)"<no args>", 0, 0, 'D', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"games", (char *)"<no args>", 0, 0, 'F', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"setname", (char *)"pname", 1, 1, 'N', EVAL_ROGUE },
|
||||
{ (char *)"rogue", (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, 'X', EVAL_ROGUE },
|
||||
#elif BUILD_CUSTOMCC
|
||||
RPC_FUNCS
|
||||
#elif BUILD_GAMESCC
|
||||
RPC_FUNCS
|
||||
#else
|
||||
{ (char *)"sudoku", (char *)"gen", (char *)"<no args>", 0, 0, 'G', EVAL_SUDOKU },
|
||||
{ (char *)"sudoku", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_SUDOKU },
|
||||
{ (char *)"sudoku", (char *)"pending", (char *)"<no args>", 0, 0, 'U', EVAL_SUDOKU },
|
||||
{ (char *)"sudoku", (char *)"solution", (char *)"txid solution timestamps[81]", 83, 83, 'S', EVAL_SUDOKU },
|
||||
{ (char *)"musig", (char *)"calcmsg", (char *)"sendtxid scriptPubKey", 2, 2, 'C', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"combine", (char *)"pubkeys ...", 2, 999999999, 'P', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"session", (char *)"myindex,numsigners,combined_pk,pkhash,msg32", 5, 5, 'R', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"commit", (char *)"pkhash,ind,commitment", 3, 3, 'H', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"nonce", (char *)"pkhash,ind,nonce", 3, 3, 'N', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"partialsig", (char *)"pkhash,ind,partialsig", 3, 3, 'S', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"verify", (char *)"msg sig pubkey", 3, 3, 'V', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"send", (char *)"combined_pk amount", 2, 2, 'x', EVAL_MUSIG },
|
||||
{ (char *)"musig", (char *)"spend", (char *)"sendtxid sig scriptPubKey", 3, 3, 'y', EVAL_MUSIG },
|
||||
{ (char *)"dilithium", (char *)"keypair", (char *)"[hexseed]", 0, 1, 'K', EVAL_DILITHIUM },
|
||||
{ (char *)"dilithium", (char *)"register", (char *)"handle, [hexseed]", 1, 2, 'R', EVAL_DILITHIUM },
|
||||
{ (char *)"dilithium", (char *)"handleinfo", (char *)"handle", 1, 1, 'I', EVAL_DILITHIUM },
|
||||
{ (char *)"dilithium", (char *)"sign", (char *)"msg [hexseed]", 1, 2, 'S', EVAL_DILITHIUM },
|
||||
{ (char *)"dilithium", (char *)"verify", (char *)"pubtxid msg sig", 3, 3, 'V', EVAL_DILITHIUM },
|
||||
{ (char *)"dilithium", (char *)"send", (char *)"handle pubtxid amount", 3, 3, 'x', EVAL_DILITHIUM },
|
||||
{ (char *)"dilithium", (char *)"spend", (char *)"sendtxid scriptPubKey [hexseed]", 2, 3, 'y', EVAL_DILITHIUM },
|
||||
{ (char *)"dilithium", (char *)"Qsend", (char *)"mypubtxid hexseed/'mypriv' destpubtxid,amount, ...", 4, 66, 'Q', EVAL_DILITHIUM },
|
||||
#endif
|
||||
};
|
||||
|
||||
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params);
|
||||
|
||||
#ifdef BUILD_ROGUE
|
||||
int32_t rogue_replay(uint64_t seed,int32_t sleepmillis);
|
||||
bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
|
||||
|
||||
UniValue rogue_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
|
||||
#else
|
||||
bool sudoku_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
|
||||
UniValue sudoku_txidinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue sudoku_generate(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue sudoku_solution(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue sudoku_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
|
||||
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
|
||||
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
|
||||
bool dilithium_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
|
||||
UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue dilithium_handleinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue dilithium_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue dilithium_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue dilithium_keypair(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue dilithium_sign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue dilithium_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue dilithium_Qsend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
|
||||
#endif
|
||||
|
||||
cJSON *cclib_reparse(int32_t *nump,char *jsonstr) // assumes origparams will be freed by caller
|
||||
{
|
||||
cJSON *params; char *newstr; int32_t i,j;
|
||||
*nump = 0;
|
||||
if ( jsonstr != 0 )
|
||||
{
|
||||
if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' )
|
||||
{
|
||||
jsonstr[strlen(jsonstr)-1] = 0;
|
||||
jsonstr++;
|
||||
}
|
||||
newstr = (char *)malloc(strlen(jsonstr)+1);
|
||||
for (i=j=0; jsonstr[i]!=0; i++)
|
||||
{
|
||||
if ( jsonstr[i] == '%' && jsonstr[i+1] == '2' && jsonstr[i+2] == '2' )
|
||||
{
|
||||
newstr[j++] = '"';
|
||||
i += 2;
|
||||
}
|
||||
else if ( jsonstr[i] == '\'' )
|
||||
newstr[j++] = '"';
|
||||
else newstr[j++] = jsonstr[i];
|
||||
}
|
||||
newstr[j] = 0;
|
||||
params = cJSON_Parse(newstr);
|
||||
if ( 0 && params != 0 )
|
||||
printf("new.(%s) -> %s\n",newstr,jprint(params,0));
|
||||
free(newstr);
|
||||
*nump = cJSON_GetArraySize(params);
|
||||
//free(origparams);
|
||||
} else params = 0;
|
||||
return(params);
|
||||
}
|
||||
|
||||
UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint64_t txfee = 10000; int32_t m; cJSON *params = cclib_reparse(&m,jsonstr);
|
||||
fprintf(stderr,"method.(%s) -> (%s)\n",jsonstr!=0?jsonstr:"",params!=0?jprint(params,0):"");
|
||||
#ifdef BUILD_ROGUE
|
||||
if ( cp->evalcode == EVAL_ROGUE )
|
||||
{
|
||||
if ( strcmp(method,"newgame") == 0 )
|
||||
return(rogue_newgame(txfee,cp,params));
|
||||
else if ( strcmp(method,"pending") == 0 )
|
||||
return(rogue_pending(txfee,cp,params));
|
||||
else if ( strcmp(method,"gameinfo") == 0 )
|
||||
return(rogue_gameinfo(txfee,cp,params));
|
||||
else if ( strcmp(method,"register") == 0 )
|
||||
return(rogue_register(txfee,cp,params));
|
||||
else if ( strcmp(method,"keystrokes") == 0 )
|
||||
return(rogue_keystrokes(txfee,cp,params));
|
||||
else if ( strcmp(method,"bailout") == 0 )
|
||||
return(rogue_bailout(txfee,cp,params));
|
||||
else if ( strcmp(method,"highlander") == 0 )
|
||||
return(rogue_highlander(txfee,cp,params));
|
||||
else if ( strcmp(method,"extract") == 0 )
|
||||
return(rogue_extract(txfee,cp,params));
|
||||
else if ( strcmp(method,"playerinfo") == 0 )
|
||||
return(rogue_playerinfo(txfee,cp,params));
|
||||
else if ( strcmp(method,"players") == 0 )
|
||||
return(rogue_players(txfee,cp,params));
|
||||
else if ( strcmp(method,"games") == 0 )
|
||||
return(rogue_games(txfee,cp,params));
|
||||
else if ( strcmp(method,"setname") == 0 )
|
||||
return(rogue_setname(txfee,cp,params));
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid rogue method"));
|
||||
result.push_back(Pair("method",method));
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
#elif BUILD_CUSTOMCC
|
||||
CUSTOM_DISPATCH
|
||||
#elif BUILD_GAMESCC
|
||||
CUSTOM_DISPATCH
|
||||
#else
|
||||
if ( cp->evalcode == EVAL_SUDOKU )
|
||||
{
|
||||
//printf("CClib_method params.%p\n",params);
|
||||
if ( strcmp(method,"txidinfo") == 0 )
|
||||
return(sudoku_txidinfo(txfee,cp,params));
|
||||
else if ( strcmp(method,"gen") == 0 )
|
||||
return(sudoku_generate(txfee,cp,params));
|
||||
else if ( strcmp(method,"solution") == 0 )
|
||||
return(sudoku_solution(txfee,cp,params));
|
||||
else if ( strcmp(method,"pending") == 0 )
|
||||
return(sudoku_pending(txfee,cp,params));
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid sudoku method"));
|
||||
result.push_back(Pair("method",method));
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
else if ( cp->evalcode == EVAL_MUSIG )
|
||||
{
|
||||
//printf("CClib_method params.%p\n",params);
|
||||
if ( strcmp(method,"combine") == 0 )
|
||||
return(musig_combine(txfee,cp,params));
|
||||
else if ( strcmp(method,"calcmsg") == 0 )
|
||||
return(musig_calcmsg(txfee,cp,params));
|
||||
else if ( strcmp(method,"session") == 0 )
|
||||
return(musig_session(txfee,cp,params));
|
||||
else if ( strcmp(method,"commit") == 0 )
|
||||
return(musig_commit(txfee,cp,params));
|
||||
else if ( strcmp(method,"nonce") == 0 ) // returns combined nonce if ready
|
||||
return(musig_nonce(txfee,cp,params));
|
||||
else if ( strcmp(method,"partialsig") == 0 )
|
||||
return(musig_partialsig(txfee,cp,params));
|
||||
else if ( strcmp(method,"verify") == 0 )
|
||||
return(musig_verify(txfee,cp,params));
|
||||
else if ( strcmp(method,"send") == 0 )
|
||||
return(musig_send(txfee,cp,params));
|
||||
else if ( strcmp(method,"spend") == 0 )
|
||||
return(musig_spend(txfee,cp,params));
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid musig method"));
|
||||
result.push_back(Pair("method",method));
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
else if ( cp->evalcode == EVAL_DILITHIUM )
|
||||
{
|
||||
if ( strcmp(method,"Qsend") == 0 )
|
||||
return(dilithium_Qsend(txfee,cp,params));
|
||||
else if ( strcmp(method,"send") == 0 )
|
||||
return(dilithium_send(txfee,cp,params));
|
||||
else if ( strcmp(method,"spend") == 0 )
|
||||
return(dilithium_spend(txfee,cp,params));
|
||||
else if ( strcmp(method,"keypair") == 0 )
|
||||
return(dilithium_keypair(txfee,cp,params));
|
||||
else if ( strcmp(method,"register") == 0 )
|
||||
return(dilithium_register(txfee,cp,params));
|
||||
else if ( strcmp(method,"handleinfo") == 0 )
|
||||
return(dilithium_handleinfo(txfee,cp,params));
|
||||
else if ( strcmp(method,"sign") == 0 )
|
||||
return(dilithium_sign(txfee,cp,params));
|
||||
else if ( strcmp(method,"verify") == 0 )
|
||||
return(dilithium_verify(txfee,cp,params));
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid dilithium method"));
|
||||
result.push_back(Pair("method",method));
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","only sudoku supported for now"));
|
||||
result.push_back(Pair("evalcode",(int)cp->evalcode));
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
|
||||
UniValue CClib_info(struct CCcontract_info *cp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i; char str[2];
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("CClib",CClib_name()));
|
||||
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
|
||||
{
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("evalcode",CClib_methods[i].evalcode));
|
||||
if ( CClib_methods[i].funcid < ' ' || CClib_methods[i].funcid >= 128 )
|
||||
obj.push_back(Pair("funcid",CClib_methods[i].funcid));
|
||||
else
|
||||
{
|
||||
str[0] = CClib_methods[i].funcid;
|
||||
str[1] = 0;
|
||||
obj.push_back(Pair("funcid",str));
|
||||
}
|
||||
obj.push_back(Pair("name",CClib_methods[i].CCname));
|
||||
obj.push_back(Pair("method",CClib_methods[i].method));
|
||||
obj.push_back(Pair("help",CClib_methods[i].help));
|
||||
obj.push_back(Pair("params_required",CClib_methods[i].numrequiredargs));
|
||||
obj.push_back(Pair("params_max",CClib_methods[i].maxargs));
|
||||
a.push_back(obj);
|
||||
}
|
||||
result.push_back(Pair("methods",a));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx; cJSON *params;
|
||||
//printf("CClib params.(%s)\n",jsonstr!=0?jsonstr:"");
|
||||
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
|
||||
{
|
||||
if ( cp->evalcode == CClib_methods[i].evalcode && strcmp(method,CClib_methods[i].method) == 0 )
|
||||
{
|
||||
if ( cp->evalcode == EVAL_FAUCET2 )
|
||||
{
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("method",CClib_methods[i].method));
|
||||
params = cJSON_Parse(jsonstr);
|
||||
rawtx = CClib_rawtxgen(cp,CClib_methods[i].funcid,params);
|
||||
free_json(params);
|
||||
result.push_back(Pair("rawtx",rawtx));
|
||||
return(result);
|
||||
} else return(CClib_method(cp,method,jsonstr));
|
||||
}
|
||||
}
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("method",method));
|
||||
result.push_back(Pair("error","method not found"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
int64_t IsCClibvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cmpaddr) == 0 )
|
||||
return(tx.vout[v].nValue);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool CClibExactAmounts(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;
|
||||
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 faucet2 from mempool");
|
||||
if ( (assetoshis= IsCClibvout(cp,vinTx,tx.vin[i].prevout.n,cp->unspendableCCaddr)) != 0 )
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
||||
if ( (assetoshis= IsCClibvout(cp,tx,i,cp->unspendableCCaddr)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+FAUCET2SIZE+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return eval->Invalid("mismatched inputs != outputs + FAUCET2SIZE + txfee");
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx,unsigned int nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
if ( cp->evalcode != EVAL_FAUCET2 )
|
||||
{
|
||||
#ifdef BUILD_ROGUE
|
||||
return(rogue_validate(cp,height,eval,tx));
|
||||
#elif BUILD_CUSTOMCC
|
||||
return(custom_validate(cp,height,eval,tx));
|
||||
#elif BUILD_GAMESCC
|
||||
return(games_validate(cp,height,eval,tx));
|
||||
#else
|
||||
if ( cp->evalcode == EVAL_SUDOKU )
|
||||
return(sudoku_validate(cp,height,eval,tx));
|
||||
else if ( cp->evalcode == EVAL_MUSIG )
|
||||
return(musig_validate(cp,height,eval,tx));
|
||||
else if ( cp->evalcode == EVAL_DILITHIUM )
|
||||
return(dilithium_validate(cp,height,eval,tx));
|
||||
else return eval->Invalid("invalid evalcode");
|
||||
#endif
|
||||
}
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else
|
||||
{
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
|
||||
{
|
||||
fprintf(stderr,"faucetget invalid vini\n");
|
||||
return eval->Invalid("illegal normal vini");
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check amounts\n");
|
||||
if ( CClibExactAmounts(cp,eval,tx,1,10000) == false )
|
||||
{
|
||||
fprintf(stderr,"faucetget invalid amount\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
preventCCvouts = 1;
|
||||
if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) != 0 )
|
||||
{
|
||||
preventCCvouts++;
|
||||
i = 1;
|
||||
} else i = 0;
|
||||
txid = tx.GetHash();
|
||||
memcpy(hash,&txid,sizeof(hash));
|
||||
fprintf(stderr,"check faucetget txid %s %02x/%02x\n",uint256_str(str,txid),hash[0],hash[31]);
|
||||
if ( tx.vout[i].nValue != FAUCET2SIZE )
|
||||
return eval->Invalid("invalid faucet output");
|
||||
else if ( (hash[0] & 0xff) != 0 || (hash[31] & 0xff) != 0 )
|
||||
return eval->Invalid("invalid faucetget txid");
|
||||
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
|
||||
SetCCtxids(txids,destaddr,tx.vout[i].scriptPubKey.IsPayToCryptoCondition());
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
|
||||
{
|
||||
//int height = it->first.blockHeight;
|
||||
if ( CCduration(numblocks,it->first.txhash) > 0 && numblocks > 3 )
|
||||
{
|
||||
//fprintf(stderr,"would return error %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks);
|
||||
return eval->Invalid("faucet2 is only for brand new addresses");
|
||||
}
|
||||
}
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
fprintf(stderr,"faucet2get validated\n");
|
||||
else fprintf(stderr,"faucet2get invalid\n");
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs,char *cmpaddr,int32_t CCflag)
|
||||
{
|
||||
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0,txfee = 10000; 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,CCflag!=0?true:false);
|
||||
if ( maxinputs > CC_MAXVINS )
|
||||
maxinputs = CC_MAXVINS;
|
||||
if ( maxinputs != 0 )
|
||||
threshold = total/maxinputs;
|
||||
else threshold = total;
|
||||
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;
|
||||
//char str[65]; fprintf(stderr,"%s check %s/v%d %.8f vs %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN,(double)threshold/COIN);
|
||||
if ( it->second.satoshis < threshold || it->second.satoshis == txfee )
|
||||
continue;
|
||||
// no need to prevent dup
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsCClibvout(cp,vintx,vout,cmpaddr)) >= 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 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;
|
||||
} //else fprintf(stderr,"nValue %.8f too small or already spent in mempool\n",(double)nValue/COIN);
|
||||
} else fprintf(stderr,"couldnt get tx\n");
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk)
|
||||
{
|
||||
char coinaddr[64]; int64_t nValue,txfee = 10000; uint256 txid,hashBlock; CTransaction vintx; int32_t vout;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
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;
|
||||
//char str[65]; fprintf(stderr,"%s check %s/v%d %.8f vs %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN,(double)threshold/COIN);
|
||||
if ( it->second.satoshis < txfee )
|
||||
continue;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsCClibvout(cp,vintx,vout,coinaddr)) != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
return(it->second.satoshis);
|
||||
} //else fprintf(stderr,"nValue %.8f too small or already spent in mempool\n",(double)nValue/COIN);
|
||||
} else fprintf(stderr,"couldnt get tx\n");
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk,cclibpk; CScript opret;
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
cclibpk = GetUnspendable(cp,0);
|
||||
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,cclibpk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params)
|
||||
{
|
||||
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk,cclibpk; int64_t funds,txfee=0,inputs,CCchange=0,nValue=FAUCET2SIZE; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
if ( funcid == 'F' )
|
||||
{
|
||||
if ( cJSON_GetArraySize(params) > 0 )
|
||||
{
|
||||
funds = (int64_t)jdouble(jitem(params,0),0)*COIN + 0.0000000049;
|
||||
return(Faucet2Fund(cp,0,funds));
|
||||
} else return("");
|
||||
}
|
||||
else if ( funcid != 'G' )
|
||||
return("");
|
||||
cclibpk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( (inputs= AddCClibInputs(cp,mtx,cclibpk,nValue+txfee,60,cp->unspendableCCaddr,1)) > 0 )
|
||||
{
|
||||
if ( inputs > nValue )
|
||||
CCchange = (inputs - nValue - txfee);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET2,CCchange,cclibpk));
|
||||
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_FAUCET2 << (uint8_t)'G' << j));
|
||||
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
|
||||
{
|
||||
len >>= 1;
|
||||
decode_hex(buf,len,(char *)rawhex.c_str());
|
||||
hash = bits256_doublesha256(0,buf,len);
|
||||
if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 )
|
||||
{
|
||||
fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL));
|
||||
return(rawhex);
|
||||
}
|
||||
//fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]);
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
|
||||
return("");
|
||||
} else fprintf(stderr,"cant find faucet inputs\n");
|
||||
return("");
|
||||
}
|
||||
|
||||
UniValue cclib_error(UniValue &result,const char *errorstr)
|
||||
{
|
||||
result.push_back(Pair("status","error"));
|
||||
result.push_back(Pair("error",errorstr));
|
||||
return(result);
|
||||
}
|
||||
|
||||
uint256 juint256(cJSON *obj)
|
||||
{
|
||||
uint256 tmp; bits256 t = jbits256(obj,0);
|
||||
memcpy(&tmp,&t,sizeof(tmp));
|
||||
return(revuint256(tmp));
|
||||
}
|
||||
|
||||
int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len)
|
||||
{
|
||||
char *hexstr;
|
||||
if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == len*2 )
|
||||
{
|
||||
decode_hex(hash32,len,hexstr);
|
||||
return(0);
|
||||
} else return(-1);
|
||||
}
|
||||
|
||||
#ifdef BUILD_ROGUE
|
||||
#include "rogue_rpc.cpp"
|
||||
#include "rogue/cursesd.c"
|
||||
#include "rogue/vers.c"
|
||||
#include "rogue/extern.c"
|
||||
#include "rogue/armor.c"
|
||||
#include "rogue/chase.c"
|
||||
#include "rogue/command.c"
|
||||
#include "rogue/daemon.c"
|
||||
#include "rogue/daemons.c"
|
||||
#include "rogue/fight.c"
|
||||
#include "rogue/init.c"
|
||||
#include "rogue/io.c"
|
||||
#include "rogue/list.c"
|
||||
#include "rogue/mach_dep.c"
|
||||
#include "rogue/rogue.c"
|
||||
#include "rogue/xcrypt.c"
|
||||
#include "rogue/mdport.c"
|
||||
#include "rogue/misc.c"
|
||||
#include "rogue/monsters.c"
|
||||
#include "rogue/move.c"
|
||||
#include "rogue/new_level.c"
|
||||
#include "rogue/options.c"
|
||||
#include "rogue/pack.c"
|
||||
#include "rogue/passages.c"
|
||||
#include "rogue/potions.c"
|
||||
#include "rogue/rings.c"
|
||||
#include "rogue/rip.c"
|
||||
#include "rogue/rooms.c"
|
||||
#include "rogue/save.c"
|
||||
#include "rogue/scrolls.c"
|
||||
#include "rogue/state.c"
|
||||
#include "rogue/sticks.c"
|
||||
#include "rogue/things.c"
|
||||
#include "rogue/weapons.c"
|
||||
#include "rogue/wizard.c"
|
||||
|
||||
#elif BUILD_CUSTOMCC
|
||||
#include "customcc.cpp"
|
||||
|
||||
#elif BUILD_GAMESCC
|
||||
#include "rogue/cursesd.c"
|
||||
#include "gamescc.cpp"
|
||||
|
||||
#else
|
||||
#include "sudoku.cpp"
|
||||
#include "musig.cpp"
|
||||
#include "dilithium.c"
|
||||
//#include "../secp256k1/src/modules/musig/example.c"
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
117
src/cc/customcc.cpp
Normal file
117
src/cc/customcc.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
simple stub custom cc
|
||||
|
||||
Just update the functions in this file, then from ~/komodo/src/cc
|
||||
|
||||
../komodo-cli -ac_name=CUSTOM stop
|
||||
./makecustom
|
||||
../komodod -ac_name=CUSTOM -ac_cclib=custom -ac_cc=2 ...
|
||||
|
||||
The above will rebuild komodod and get it running again
|
||||
*/
|
||||
|
||||
CScript custom_opret(uint8_t funcid,CPubKey pk)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_CUSTOM;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t custom_opretdecode(CPubKey &pk,CScript scriptPubKey)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t e,f;
|
||||
GetOpReturnData(scriptPubKey,vopret);
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_CUSTOM )
|
||||
{
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
UniValue custom_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag)
|
||||
{
|
||||
CTransaction tx;
|
||||
if ( rawtx.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("hex",rawtx));
|
||||
if ( DecodeHexTx(tx,rawtx) != 0 )
|
||||
{
|
||||
if ( broadcastflag != 0 && myAddtomempool(tx) != 0 )
|
||||
RelayTransaction(tx);
|
||||
result.push_back(Pair("txid",tx.GetHash().ToString()));
|
||||
result.push_back(Pair("result","success"));
|
||||
} else result.push_back(Pair("error","decode hex"));
|
||||
} else result.push_back(Pair("error","couldnt finalize CCtx"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue custom_func0(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("message","just an example of an information returning rpc"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
// send yourself 1 coin to your CC address using normal utxo from your -pubkey
|
||||
|
||||
UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); std::string rawtx;
|
||||
UniValue result(UniValue::VOBJ); CPubKey mypk; int64_t amount = COIN; int32_t broadcastflag=0;
|
||||
if ( txfee == 0 )
|
||||
txfee = CUSTOM_TXFEE;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,COIN+txfee,64) >= COIN+txfee ) // add utxo to mtx
|
||||
{
|
||||
// make op_return payload as normal.
|
||||
CScript opret = custom_opret('1',mypk);
|
||||
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
|
||||
vData.push_back(std::vector<unsigned char>(opret.begin(), opret.end()));
|
||||
// make vout0 with op_return included as payload.
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData));
|
||||
fprintf(stderr, "vout size2.%li\n", mtx.vout.size());
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript());
|
||||
return(custom_rawtxresult(result,rawtx,broadcastflag));
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
bool has_opret(const CTransaction &tx, uint8_t evalcode)
|
||||
{
|
||||
for ( auto vout : tx.vout )
|
||||
{
|
||||
if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
||||
{
|
||||
char expectedaddress[64]; CPubKey pk;
|
||||
CScript opret; int32_t numvout;
|
||||
if ( !has_opret(tx, EVAL_CUSTOM) )
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
|
||||
CScript dummy;
|
||||
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() == 1 )
|
||||
{
|
||||
opret << E_MARSHAL(ss << vParams[0]);
|
||||
}
|
||||
numvout = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
opret = tx.vout[1].scriptPubKey;
|
||||
numvout = 2;
|
||||
}
|
||||
if ( tx.vout.size() != numvout ) // make sure the tx only has appropriate outputs
|
||||
return eval->Invalid("invalid number of vouts");
|
||||
else if ( custom_opretdecode(pk,opret) != '1' ) // verify opreturn payload
|
||||
return eval->Invalid("invalid opreturn");
|
||||
GetCCaddress(cp,expectedaddress,pk);
|
||||
if ( IsCClibvout(cp,tx,0,expectedaddress) == COIN ) // make sure amount and destination matches
|
||||
return(true);
|
||||
else return eval->Invalid("invalid vout0 amount");
|
||||
}
|
||||
45
src/cc/customcc.h
Normal file
45
src/cc/customcc.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
to create a custom libcc.so:
|
||||
|
||||
1. change "func0" and "func1" to method names that fit your custom cc. Of course, you can create more functions by adding another entry to RPC_FUNCS. there is not any practical limit to the number of methods.
|
||||
|
||||
2. For each method make sure there is a UniValue function declaration and CUSTOM_DISPATCH has an if statement checking for it that calls the custom_func
|
||||
|
||||
3. write the actual custom_func0, custom_func1 and custom_validate in customcc.cpp
|
||||
|
||||
4. ./makecustom, which builds cclib.cpp with -DBUILD_CUSTOMCC and puts the libcc.so in ~/komodo/src and rebuilds komodod
|
||||
|
||||
5. launch your chain with -ac_cclib=customcc -ac_cc=2
|
||||
|
||||
*/
|
||||
|
||||
std::string MYCCLIBNAME = (char *)"customcc";
|
||||
|
||||
#define EVAL_CUSTOM (EVAL_FAUCET2+1)
|
||||
#define CUSTOM_TXFEE 10000
|
||||
|
||||
#define MYCCNAME "custom"
|
||||
|
||||
#define RPC_FUNCS \
|
||||
{ (char *)MYCCNAME, (char *)"func0", (char *)"<parameter help>", 1, 1, '0', EVAL_CUSTOM }, \
|
||||
{ (char *)MYCCNAME, (char *)"func1", (char *)"<no args>", 0, 0, '1', EVAL_CUSTOM },
|
||||
|
||||
bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
|
||||
UniValue custom_func0(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
|
||||
#define CUSTOM_DISPATCH \
|
||||
if ( cp->evalcode == EVAL_CUSTOM ) \
|
||||
{ \
|
||||
if ( strcmp(method,"func0") == 0 ) \
|
||||
return(custom_func0(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"func1") == 0 ) \
|
||||
return(custom_func1(txfee,cp,params)); \
|
||||
else \
|
||||
{ \
|
||||
result.push_back(Pair("result","error")); \
|
||||
result.push_back(Pair("error","invalid customcc method")); \
|
||||
result.push_back(Pair("method",method)); \
|
||||
return(result); \
|
||||
} \
|
||||
}
|
||||
0
src/cc/dapps/cJSON.c
Executable file → Normal file
0
src/cc/dapps/cJSON.c
Executable file → Normal file
1119
src/cc/dapps/dappstd.c
Normal file
1119
src/cc/dapps/dappstd.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -236,7 +236,7 @@ void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep)
|
||||
{
|
||||
fclose(fp);
|
||||
*lenp = 0;
|
||||
printf("loadfile null size.(%s)\n",fname);
|
||||
//printf("loadfile null size.(%s)\n",fname);
|
||||
return(0);
|
||||
}
|
||||
if ( filesize > buflen )
|
||||
@@ -312,22 +312,20 @@ uint64_t get_btcusd()
|
||||
|
||||
char *REFCOIN_CLI;
|
||||
|
||||
cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3)
|
||||
cJSON *get_cli(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 )
|
||||
{
|
||||
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);
|
||||
if ( refcoin[0] == 0 )
|
||||
printf("must supply reference coin\n");
|
||||
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s 2>/tmp/oraclefeed.error\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);
|
||||
sprintf(cmdstr,"%s %s %s %s %s %s > %s 2>/tmp/oraclefeed.error\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname);
|
||||
//printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
|
||||
}
|
||||
#ifdef TESTMODE
|
||||
fprintf(stderr,"cmd: %s\n",cmdstr);
|
||||
@@ -340,22 +338,24 @@ cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char
|
||||
#ifdef TESTMODE
|
||||
fprintf(stderr,"jsonstr.(%s)\n",jsonstr);
|
||||
#endif // TESTMODE
|
||||
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
|
||||
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0)
|
||||
*retstrp = jsonstr;
|
||||
else free(jsonstr);
|
||||
}
|
||||
else if ( (jsonstr= filestr(&fsize,"/tmp/oraclefeed.error")) != 0 )
|
||||
*retstrp = jsonstr;
|
||||
return(retjson);
|
||||
}
|
||||
|
||||
bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
|
||||
bits256 broadcasttx(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(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0));
|
||||
if (strcmp("error",jstr(retjson,"result"))==0) printf("%s\n",jstr(retjson,"error"));
|
||||
free_json(retjson);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
@@ -372,36 +372,14 @@ bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
|
||||
return(txid);
|
||||
}
|
||||
|
||||
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(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"","")) != 0 )
|
||||
{
|
||||
fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0));
|
||||
free_json(retjson);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
if ( strlen(retstr) >= 64 )
|
||||
{
|
||||
retstr[64] = 0;
|
||||
decode_hex(txid.bytes,32,retstr);
|
||||
}
|
||||
fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid));
|
||||
free(retstr);
|
||||
}
|
||||
return(txid);
|
||||
}
|
||||
|
||||
int32_t get_coinheight(char *refcoin,char *acname)
|
||||
{
|
||||
cJSON *retjson; char *retstr; int32_t height=0;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
|
||||
{
|
||||
height = jint(retjson,"blocks");
|
||||
free_json(retjson);
|
||||
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
@@ -416,7 +394,7 @@ 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(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
|
||||
{
|
||||
fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0));
|
||||
free_json(retjson);
|
||||
@@ -437,7 +415,7 @@ 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(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
|
||||
{
|
||||
merkleroot = jbits256(retjson,"merkleroot");
|
||||
//fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot));
|
||||
@@ -472,10 +450,12 @@ int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *m
|
||||
return(0);
|
||||
}
|
||||
|
||||
cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr)
|
||||
cJSON *get_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxidstr)
|
||||
{
|
||||
cJSON *retjson; char *retstr;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",bindtxidstr,refcoin,"","")) != 0 )
|
||||
cJSON *retjson; char *retstr; char function[64];
|
||||
if (type==0) sprintf(function,"%s","gatewayspendingwithdraws");
|
||||
else if (type==1) sprintf(function,"%s","importgatewaypendingwithdraws");
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,refcoin,"","")) != 0 )
|
||||
{
|
||||
//printf("pending.(%s)\n",jprint(retjson,0));
|
||||
return(retjson);
|
||||
@@ -488,10 +468,13 @@ cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr)
|
||||
return(0);
|
||||
}
|
||||
|
||||
cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr)
|
||||
cJSON *get_gatewaysprocessed(int8_t type,char *refcoin,char *acname,char *bindtxidstr)
|
||||
{
|
||||
cJSON *retjson; char *retstr;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysprocessed",bindtxidstr,refcoin,"","")) != 0 )
|
||||
char function[64];
|
||||
if (type==0) sprintf(function,"%s","gatewaysprocessed");
|
||||
else if (type==1) sprintf(function,"%s","importgatewayprocessed");
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,refcoin,"","")) != 0 )
|
||||
{
|
||||
//printf("pending.(%s)\n",jprint(retjson,0));
|
||||
return(retjson);
|
||||
@@ -507,7 +490,7 @@ cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr)
|
||||
cJSON *get_rawmempool(char *refcoin,char *acname)
|
||||
{
|
||||
cJSON *retjson; char *retstr;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
|
||||
{
|
||||
//printf("mempool.(%s)\n",jprint(retjson,0));
|
||||
return(retjson);
|
||||
@@ -526,14 +509,14 @@ cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
|
||||
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(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
|
||||
{
|
||||
//printf("addressutxos.(%s)\n",jprint(retjson,0));
|
||||
return(retjson);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
|
||||
//fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
|
||||
free(retstr);
|
||||
}
|
||||
return(0);
|
||||
@@ -542,7 +525,7 @@ cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
|
||||
cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
|
||||
{
|
||||
cJSON *retjson; char *retstr,str[65];
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
|
||||
{
|
||||
return(retjson);
|
||||
}
|
||||
@@ -557,7 +540,7 @@ cJSON *get_rawtransaction(char *refcoin,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 ( (retjson= get_cli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 )
|
||||
{
|
||||
if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1;
|
||||
free_json(retjson);
|
||||
@@ -576,7 +559,7 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int
|
||||
cJSON *retjson; char *retstr; char rescanstr[10];
|
||||
if (rescan) strcpy(rescanstr,"true");
|
||||
else strcpy(rescanstr,"false");
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,label,rescanstr,"")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"importaddress",depositaddr,label,rescanstr,"")) != 0 )
|
||||
{
|
||||
printf("importaddress.(%s)\n",jprint(retjson,0));
|
||||
free_json(retjson);
|
||||
@@ -588,19 +571,20 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int
|
||||
}
|
||||
}
|
||||
|
||||
void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys,char *bindtxidstr)
|
||||
void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys)
|
||||
{
|
||||
cJSON *retjson; char *retstr,Mstr[10],tmp[128];
|
||||
cJSON *retjson; char *retstr,Mstr[10],addr[64];
|
||||
|
||||
sprintf(Mstr,"%d",M);
|
||||
sprintf(tmp,"\"%s\"",bindtxidstr);
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,tmp,"")) != 0 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,"","")) != 0 )
|
||||
{
|
||||
fprintf(stderr,"unexpected addmultisigaddress json.(%s)\n",jprint(retjson,0));
|
||||
free(retstr);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
sprintf(addr,"\"%s\"",retstr);
|
||||
get_cli(refcoin,&retstr,acname,"importaddress",addr,"\"\"","false","");
|
||||
printf("addmultisigaddress.(%s)\n",retstr);
|
||||
free_json(retjson);
|
||||
}
|
||||
@@ -641,12 +625,11 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
|
||||
else txfee = 10000;
|
||||
if ( satoshis < txfee )
|
||||
{
|
||||
printf("createrawtx satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN);
|
||||
printf("createrawtx: 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 )
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 )
|
||||
{
|
||||
//createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...}
|
||||
if ( (vins= getinputarray(&total,retjson,satoshis)) != 0 )
|
||||
@@ -667,7 +650,7 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
|
||||
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 )
|
||||
if ( (retjson2= get_cli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 )
|
||||
{
|
||||
printf("createrawtx: unexpected JSON2.(%s)\n",jprint(retjson2,0));
|
||||
free_json(retjson2);
|
||||
@@ -680,7 +663,7 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
|
||||
free(argB);
|
||||
}
|
||||
else printf("not enough funds to create withdraw tx\n");
|
||||
}
|
||||
}
|
||||
free_json(retjson);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
@@ -692,14 +675,14 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
|
||||
return(txstr);
|
||||
}
|
||||
|
||||
cJSON *addsignature(char *refcoin,char *acname,char *rawtx)
|
||||
cJSON *addsignature(char *refcoin,char *acname,char *rawtx, int M)
|
||||
{
|
||||
char *retstr,*hexstr; cJSON *retjson;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 )
|
||||
if ( (retjson= get_cli(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) )
|
||||
else if ((hexstr=jstr(retjson,"hex"))!= 0 && strlen(hexstr) > strlen(rawtx) + (M*2) + 1)
|
||||
{
|
||||
jaddnum(retjson,"partialtx",1);
|
||||
return(retjson);
|
||||
@@ -714,32 +697,17 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx)
|
||||
return(0);
|
||||
}
|
||||
|
||||
char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K)
|
||||
bits256 gatewayspartialsign(int8_t type,char *refcoin,char *acname,bits256 txid,char *hex)
|
||||
{
|
||||
char *retstr,*hexstr,*hex=0; cJSON *retjson;
|
||||
if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",txidaddr,"","","")) != 0 )
|
||||
char str[65],*retstr; cJSON *retjson; char function[64];
|
||||
if (type==0) sprintf(function,"%s","gatewayspartialsign");
|
||||
else if (type==1) sprintf(function,"%s","importgatewaypartialsign");
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,txid),refcoin,hex,"")) != 0 )
|
||||
{
|
||||
if ((hexstr=jstr(retjson,"hex")) != 0 )
|
||||
{
|
||||
if (strlen(hexstr)>0) hex = clonestr(hexstr);
|
||||
}
|
||||
*K=jint(retjson,"number_of_signs");
|
||||
free_json(retjson);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
printf("error parsing gatewaysmultisig.(%s)\n",retstr);
|
||||
free(retstr);
|
||||
}
|
||||
return(hex);
|
||||
}
|
||||
|
||||
bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex)
|
||||
{
|
||||
char str[65],*retstr; cJSON *retjson;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 )
|
||||
{
|
||||
return(komodobroadcast(refcoin,acname,retjson));
|
||||
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
|
||||
else printf("%s\n",jstr(retjson,"error"));
|
||||
free(retjson);
|
||||
return (txid);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
@@ -749,42 +717,55 @@ bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex)
|
||||
return (zeroid);
|
||||
}
|
||||
|
||||
void gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex)
|
||||
bits256 gatewayscompletesigning(int8_t type,char *refcoin,char *acname,bits256 withtxid,char *hex)
|
||||
{
|
||||
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,"gatewayscompletesigning",bits256_str(str,withtxid),coin,hex,"")) != 0 )
|
||||
char str[65],*retstr; cJSON *retjson; bits256 txid; char function[64];
|
||||
|
||||
if (type==0) sprintf(function,"%s","gatewayscompletesigning");
|
||||
else if (type==1) sprintf(function,"%s","importgatewaycompletesigning");
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,withtxid),refcoin,hex,"")) != 0 )
|
||||
{
|
||||
komodobroadcast(refcoin,acname,retjson);
|
||||
free_json(retjson);
|
||||
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
|
||||
else printf("%s\n",jstr(retjson,"error"));
|
||||
free(retjson);
|
||||
return (txid);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
printf("error parsing gatewayscompletesigning.(%s)\n",retstr);
|
||||
free(retstr);
|
||||
}
|
||||
return (zeroid);
|
||||
}
|
||||
|
||||
void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin)
|
||||
bits256 gatewaysmarkdone(int8_t type,char *refcoin,char *acname,bits256 withtxid)
|
||||
{
|
||||
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,"","")) != 0 )
|
||||
char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; ; char function[64];
|
||||
|
||||
if (type==0) sprintf(function,"%s","gatewaysmarkdone");
|
||||
else if (type==1) sprintf(function,"%s","importgatewaymarkdone");
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,withtxid),refcoin,"","")) != 0 )
|
||||
{
|
||||
komodobroadcast(refcoin,acname,retjson);
|
||||
free_json(retjson);
|
||||
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
|
||||
else printf("%s\n",jstr(retjson,"error"));
|
||||
free(retjson);
|
||||
return (txid);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
printf("error parsing gatewaysmarkdone.(%s)\n",retstr);
|
||||
free(retstr);
|
||||
}
|
||||
return (zeroid);
|
||||
}
|
||||
|
||||
int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys)
|
||||
int32_t get_gatewaysinfo(int8_t type,char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys)
|
||||
{
|
||||
char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 )
|
||||
char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n; char function[64];
|
||||
|
||||
if (type==0) sprintf(function,"%s","gatewaysinfo");
|
||||
else if (type==1) sprintf(function,"%s","importgatewayinfo");
|
||||
if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,"","","")) != 0 )
|
||||
{
|
||||
if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 )
|
||||
{
|
||||
@@ -809,7 +790,6 @@ int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *M
|
||||
strcat(*pubkeys,temp);
|
||||
}
|
||||
}
|
||||
else printf("%s != %s\n",oracle,oraclestr);
|
||||
free_json(retjson);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
@@ -882,57 +862,11 @@ int32_t markerexists(char *refcoin,char *acname,char *coinaddr)
|
||||
free_json(array);
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"Num=%d\n",num);
|
||||
return(num);
|
||||
|
||||
}
|
||||
int32_t markerfromthisnodeorunconfirmed(char *refcoin,char *acname,char *coinaddr)
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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(refcoin,acname)) != 0 )
|
||||
{
|
||||
if ( (n= cJSON_GetArraySize(array)) != 0 )
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
txid = jbits256i(array,i);
|
||||
if ( tx_has_voutaddress(refcoin,acname,txid,coinaddr) > 0 )
|
||||
{
|
||||
num = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free_json(array);
|
||||
} else return(-1);
|
||||
}
|
||||
return(num);
|
||||
}
|
||||
|
||||
void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N)
|
||||
void update_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N)
|
||||
{
|
||||
// check queue to prevent duplicate
|
||||
// check KMD chain and mempool for txidaddr
|
||||
@@ -941,9 +875,11 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t
|
||||
/// 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,*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;
|
||||
cJSON *retjson,*pending,*item,*clijson; char str[65],str1[65],str2[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr;
|
||||
int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,withdrawtxid,lasttxid,completetxid; int64_t satoshis;
|
||||
|
||||
memset(&zeroid,0,sizeof(zeroid));
|
||||
if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 )
|
||||
if ( (retjson= get_gatewayspending(type,refcoin,acname,bindtxidstr)) != 0 )
|
||||
{
|
||||
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
|
||||
{
|
||||
@@ -954,86 +890,95 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t
|
||||
if ( processed != 0 ) // avoid out of utxo conditions
|
||||
break;
|
||||
item = jitem(pending,i);
|
||||
origtxid = jbits256(item,"txid");
|
||||
withdrawtxid = jbits256(item,"withdrawtxid");
|
||||
//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 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
|
||||
if ( (txidaddr=jstr(item,"withdrawtxidaddr"))!= 0 && (withdrawaddr=jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
|
||||
{
|
||||
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0)
|
||||
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0)
|
||||
{
|
||||
if ( strcmp(depositaddr,signeraddr) == 0 )
|
||||
{
|
||||
rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis);
|
||||
if ( rawtx != 0 )
|
||||
{
|
||||
if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0)
|
||||
if ( (clijson=addsignature(refcoin,"",rawtx,M)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0)
|
||||
{
|
||||
gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex"));
|
||||
fprintf(stderr,"withdraw %.8f %s to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr);
|
||||
txid=gatewayscompletesigning(type,refcoin,acname,withdrawtxid,jstr(clijson,"hex"));
|
||||
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s 1of1\n",bits256_str(str,withdrawtxid));
|
||||
else fprintf(stderr,"### SIGNING error broadcasting tx on %s",acname);
|
||||
free_json(clijson);
|
||||
}
|
||||
processed++;
|
||||
processed++;
|
||||
}
|
||||
free(rawtx);
|
||||
} else fprintf(stderr,"couldnt create rawtx\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0)
|
||||
lasttxid = jbits256(item,"last_txid");
|
||||
if ( lasttxid.txid==withdrawtxid.txid)
|
||||
{
|
||||
rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis);
|
||||
}
|
||||
if ( rawtx != 0 )
|
||||
else rawtx=jstr(item,"hex");
|
||||
K=jint(item,"number_of_signs");
|
||||
if ( rawtx!=0 && (clijson=addsignature(refcoin,"",rawtx,M)) != 0 )
|
||||
{
|
||||
if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 )
|
||||
{
|
||||
if ( is_cJSON_True(jobj(clijson,"complete")) != 0 )
|
||||
{
|
||||
gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex"));
|
||||
fprintf(stderr,"withdraw %.8f %s M.%d N.%d to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,M,N,withdrawaddr);
|
||||
}
|
||||
else if ( jint(clijson,"partialtx") != 0 )
|
||||
{
|
||||
txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex"));
|
||||
fprintf(stderr,"%d sign(s) %dof%d partialtx %s sent\n",K+1,M,N,bits256_str(str,txid));
|
||||
}
|
||||
free_json(clijson);
|
||||
if ( is_cJSON_True(jobj(clijson,"complete")) != 0 )
|
||||
{
|
||||
txid=gatewayscompletesigning(type,refcoin,acname,lasttxid,jstr(clijson,"hex"));
|
||||
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %dof%d\n",bits256_str(str,withdrawtxid),K+1,N);
|
||||
else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname);
|
||||
}
|
||||
else if ( jint(clijson,"partialtx") != 0 )
|
||||
{
|
||||
txid=gatewayspartialsign(type,refcoin,acname,lasttxid,jstr(clijson,"hex"));
|
||||
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %d/%dof%d\n",bits256_str(str,withdrawtxid),K+1,M,N);
|
||||
else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname);
|
||||
}
|
||||
free_json(clijson);
|
||||
processed++;
|
||||
free(rawtx);
|
||||
} else fprintf(stderr,"couldnt create msig rawtx\n");
|
||||
}
|
||||
}
|
||||
if ( lasttxid.txid==withdrawtxid.txid) free(rawtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free_json(retjson);
|
||||
}
|
||||
if ( (retjson= get_gatewaysprocessed("KMD",acname,bindtxidstr)) != 0 )
|
||||
if ( (retjson= get_gatewaysprocessed(type,refcoin,acname,bindtxidstr)) != 0 )
|
||||
{
|
||||
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
|
||||
{
|
||||
if ( (pending=jarray(&n,retjson,"processed")) != 0 )
|
||||
if ((pending=jarray(&n,retjson,"processed")) != 0)
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
item = jitem(pending,i);
|
||||
origtxid = jbits256(item,"txid");
|
||||
completetxid = jbits256(item,"completesigningtxid");
|
||||
txidaddr = jstr(item,"withdrawtxidaddr");
|
||||
withdrawtxid= jbits256(item,"withdrawtxid");
|
||||
double amount = jdouble(item,"amount");
|
||||
if (validateaddress(refcoin,"",txidaddr,"iswatchonly")==0 && validateaddress(refcoin,"",txidaddr,"ismine")==0)
|
||||
importaddress(refcoin,"",txidaddr,jstr(item,"txid"),0);
|
||||
if ( txidaddr != 0 && markerexists(refcoin,"",txidaddr)==0)
|
||||
importaddress(refcoin,"",txidaddr,jstr(item,"withdrawtxid"),0);
|
||||
if (is_cJSON_True(jobj(item,"confirmed_or_notarized")) && txidaddr != 0 && markerexists(refcoin,"",txidaddr)==0)
|
||||
{
|
||||
cointxid = komodobroadcast(refcoin,"",item);
|
||||
cointxid = broadcasttx(refcoin,"",item);
|
||||
if ( bits256_nonz(cointxid) != 0 )
|
||||
{
|
||||
withdrawaddr = jstr(item,"withdrawaddr");
|
||||
fprintf(stderr,"withdraw %.8f %s to %s - %s broadcasted on %s\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr,bits256_str(str,cointxid),refcoin);
|
||||
gatewaysmarkdone("KMD",acname,origtxid,refcoin);
|
||||
withdrawaddr = jstr(item,"withdrawaddr");
|
||||
fprintf(stderr,"### WITHDRAW %.8f %s sent to %s\n",amount,refcoin,withdrawaddr);
|
||||
txid=gatewaysmarkdone(type,refcoin,acname,completetxid);
|
||||
if (txid.txid!=zeroid.txid) fprintf(stderr,"### MARKDONE withdraw %s\n",bits256_str(str,withdrawtxid));
|
||||
else fprintf(stderr,"### MARKDONE error broadcasting tx on %s\n",refcoin);
|
||||
}
|
||||
else fprintf(stderr,"### WITHDRAW error broadcasting tx on %s\n",refcoin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free_json(retjson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1094,7 +1039,7 @@ oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 034
|
||||
|
||||
int32_t main(int32_t argc,char **argv)
|
||||
{
|
||||
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;
|
||||
cJSON *clijson,*clijson2,*regjson,*item; int32_t type,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 [refcoin_cli]\n");
|
||||
@@ -1114,13 +1059,12 @@ int32_t main(int32_t argc,char **argv)
|
||||
printf("only formats of L and Ihh are supported now\n");
|
||||
return(-1);
|
||||
}
|
||||
M = N = 1;
|
||||
acheight = 0;
|
||||
M = N = 0;
|
||||
refcoin[0] = 0;
|
||||
while ( 1 )
|
||||
{
|
||||
retstr = 0;
|
||||
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_komodocli("KMD",&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
|
||||
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_cli(refcoin,&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
|
||||
{
|
||||
if ( refcoin[0] == 0 && jstr(clijson,"name") != 0 )
|
||||
{
|
||||
@@ -1131,15 +1075,17 @@ int32_t main(int32_t argc,char **argv)
|
||||
exit(0);
|
||||
}
|
||||
pubkeys=0;
|
||||
if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) < 0 )
|
||||
if ( get_gatewaysinfo(0,refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) == 0 ) type=0;
|
||||
else if ( get_gatewaysinfo(1,refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) == 0 ) type=1;
|
||||
else
|
||||
{
|
||||
printf("cant find bindtxid.(%s)\n",bindtxidstr);
|
||||
exit(0);
|
||||
}
|
||||
if (validateaddress(refcoin,"",depositaddr,"iswatchonly")==0 && validateaddress(refcoin,"",depositaddr,"ismine")==0)
|
||||
{
|
||||
if (M==N==1) importaddress(refcoin,"",depositaddr,bindtxidstr,0);
|
||||
else addmultisigaddress(refcoin,"",M,pubkeys,bindtxidstr);
|
||||
if (M==1 && N==1) importaddress(refcoin,"",depositaddr,bindtxidstr,0);
|
||||
else addmultisigaddress(refcoin,"",M,pubkeys);
|
||||
}
|
||||
if (pubkeys!=0) free(pubkeys);
|
||||
printf("set refcoin %s <- %s [%s] M.%d of N.%d\n",depositaddr,refcoin,REFCOIN_CLI,M,N);
|
||||
@@ -1153,16 +1099,14 @@ int32_t main(int32_t argc,char **argv)
|
||||
{
|
||||
if ( (height= get_oracledata(refcoin,"",prevheight,hexstr,sizeof(hexstr),"Ihh")) != 0 )
|
||||
{
|
||||
if ( (clijson2= get_komodocli("KMD",&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
|
||||
if ( (clijson2= get_cli(refcoin,&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
|
||||
{
|
||||
//printf("data.(%s)\n",jprint(clijson2,0));
|
||||
txid = komodobroadcast("KMD",acname,clijson2);
|
||||
txid = broadcasttx(refcoin,acname,clijson2);
|
||||
if ( bits256_nonz(txid) != 0 )
|
||||
{
|
||||
prevheight = height;
|
||||
acheight = get_coinheight(refcoin,"");
|
||||
printf("%s ht.%d <- %s\n",refcoin,height,hexstr);
|
||||
update_gatewayspending(refcoin,acname,bindtxidstr,M,N);
|
||||
update_gatewayspending(type,refcoin,acname,bindtxidstr,M,N);
|
||||
}
|
||||
free_json(clijson2);
|
||||
}
|
||||
|
||||
@@ -20,18 +20,18 @@
|
||||
#include "cJSON.c"
|
||||
|
||||
/*
|
||||
z_migrate: the purpose of z_migrate is to make converting of all sprout outputs into sapling. the usage would be for the user to specify a sapling address and call z_migrate zsaddr, until it returns that there is nothing left to be done.
|
||||
|
||||
its main functionality is quite similar to a z_mergetoaddress ANY_ZADDR -> onetime_taddr followed by a z_sendmany onetime_taddr -> zsaddr
|
||||
|
||||
since the z_mergetoaddress will take time, it would just queue up an async operation. When it starts, it should see if there are any onetime_taddr with 10000.0001 funds in it, that is a signal for it to do the sapling tx and it can just do that without async as it is fast enough, especially with a taddr input. Maybe it limits itself to one, or it does all possible taddr -> sapling as fast as it can. either is fine as it will be called over and over anyway.
|
||||
|
||||
It might be that there is nothing to do, but some operations are pending. in that case it would return such a status. as soon as the operation finishes, there would be more work to do.
|
||||
|
||||
the amount sent to the taddr, should be 10000.0001
|
||||
|
||||
The GUI or user would be expected to generate a sapling address and then call z_migrate saplingaddr in a loop, until it returns that it is all done. this loop should pause for 10 seconds or so, if z_migrate is just waiting for opid to complete.
|
||||
*/
|
||||
z_migrate: the purpose of z_migrate is to make converting of all sprout outputs into sapling. the usage would be for the user to specify a sapling address and call z_migrate zsaddr, until it returns that there is nothing left to be done.
|
||||
|
||||
its main functionality is quite similar to a z_mergetoaddress ANY_ZADDR -> onetime_taddr followed by a z_sendmany onetime_taddr -> zsaddr
|
||||
|
||||
since the z_mergetoaddress will take time, it would just queue up an async operation. When it starts, it should see if there are any onetime_taddr with 10000.0001 funds in it, that is a signal for it to do the sapling tx and it can just do that without async as it is fast enough, especially with a taddr input. Maybe it limits itself to one, or it does all possible taddr -> sapling as fast as it can. either is fine as it will be called over and over anyway.
|
||||
|
||||
It might be that there is nothing to do, but some operations are pending. in that case it would return such a status. as soon as the operation finishes, there would be more work to do.
|
||||
|
||||
the amount sent to the taddr, should be 10000.0001
|
||||
|
||||
The GUI or user would be expected to generate a sapling address and then call z_migrate saplingaddr in a loop, until it returns that it is all done. this loop should pause for 10 seconds or so, if z_migrate is just waiting for opid to complete.
|
||||
*/
|
||||
|
||||
bits256 zeroid;
|
||||
|
||||
@@ -331,7 +331,7 @@ cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char
|
||||
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 )
|
||||
@@ -599,13 +599,13 @@ int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* comp
|
||||
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;
|
||||
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);
|
||||
free(retstr);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
@@ -649,21 +649,21 @@ int64_t z_getbalance(char *refcoin,char *acname,char *coinaddr)
|
||||
|
||||
int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr)
|
||||
{
|
||||
cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; int32_t retval = -1;
|
||||
cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
|
||||
privkey[0] = 0;
|
||||
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_exportkey",zaddr,"","","")) != 0 )
|
||||
{
|
||||
fprintf(stderr,"z_exportkey.(%s) %s returned json!\n",refcoin,acname);
|
||||
free_json(retjson);
|
||||
return(-1);
|
||||
}
|
||||
else if ( retstr != 0 )
|
||||
{
|
||||
//printf("retstr %s -> %.8f\n",retstr,dstr(amount));
|
||||
strcpy(privkey,retstr);
|
||||
free(retstr);
|
||||
retval = 0;
|
||||
return(0);
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname)
|
||||
@@ -795,20 +795,8 @@ int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr
|
||||
{
|
||||
cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
|
||||
sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
|
||||
//printf("z_sendmany from.(%s) -> %s\n",addr,destaddr);
|
||||
if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","")) != 0 )
|
||||
{
|
||||
/*{
|
||||
"remainingUTXOs": 0,
|
||||
"remainingTransparentValue": 0.00000000,
|
||||
"remainingNotes": 222,
|
||||
"remainingShieldedValue": 5413.39093055,
|
||||
"mergingUTXOs": 0,
|
||||
"mergingTransparentValue": 0.00000000,
|
||||
"mergingNotes": 10,
|
||||
"mergingShieldedValue": 822.47447172,
|
||||
"opid": "opid-f28f6261-4120-436c-aca5-859870a40a70"
|
||||
}*/
|
||||
if ( (opstr= jstr(retjson,"opid")) != 0 )
|
||||
strcpy(opidstr,opstr);
|
||||
retval = jint(retjson,"remainingNotes");
|
||||
@@ -872,7 +860,7 @@ int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinadd
|
||||
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 )
|
||||
@@ -893,7 +881,7 @@ int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinadd
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
@@ -901,7 +889,7 @@ int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinadd
|
||||
// retval=1;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
free_json(txobj);
|
||||
}
|
||||
|
||||
@@ -264,12 +264,12 @@ int32_t dicefinish_utxosget(int32_t &total,struct dicefinish_utxo *utxos,int32_t
|
||||
int32_t n = 0; int64_t threshold = 2 * 10000;
|
||||
total = 0;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,false);
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
if ( myIsutxo_spentinmempool(it->first.txhash,(int32_t)it->first.index) == 0 )
|
||||
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,it->first.txhash,(int32_t)it->first.index) == 0 )
|
||||
{
|
||||
if ( it->second.satoshis < threshold || it->second.satoshis > 10*threshold )
|
||||
continue;
|
||||
@@ -302,7 +302,7 @@ int32_t dice_betspent(char *debugstr,uint256 bettxid)
|
||||
}
|
||||
{
|
||||
//LOCK(mempool.cs);
|
||||
if ( myIsutxo_spentinmempool(bettxid,0) != 0 || myIsutxo_spentinmempool(bettxid,1) != 0 )
|
||||
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,bettxid,0) != 0 || myIsutxo_spentinmempool(ignoretxid,ignorevin,bettxid,1) != 0 )
|
||||
{
|
||||
fprintf(stderr,"%s bettxid.%s already spent in mempool\n",debugstr,bettxid.GetHex().c_str());
|
||||
return(-1);
|
||||
@@ -1051,10 +1051,12 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
|
||||
char coinaddr[64],str[65]; uint64_t threshold,sbits,nValue,totalinputs = 0; uint256 txid,hash,proof,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
if ( maxinputs > CC_MAXVINS )
|
||||
maxinputs = CC_MAXVINS;
|
||||
if ( maxinputs > 0 )
|
||||
threshold = total / maxinputs;
|
||||
else threshold = total / 64;
|
||||
else threshold = total;
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -1067,7 +1069,7 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
|
||||
break;
|
||||
if ( j != mtx.vin.size() )
|
||||
continue;
|
||||
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
|
||||
{
|
||||
@@ -1106,7 +1108,7 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
|
||||
fundingPubKey = tx.vout[1].scriptPubKey;
|
||||
} else return(0);
|
||||
GetCCaddress(cp,coinaddr,dicepk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
entropyval = 0;
|
||||
int loops = 0;
|
||||
int numtxs = unspentOutputs.size()/2;
|
||||
@@ -1176,7 +1178,7 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
entropytxid = txid;
|
||||
entropyval = tx.vout[0].nValue;
|
||||
@@ -1213,6 +1215,9 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr,"numentropy tx %d: %.8f\n",n,(double)totalinputs/COIN);
|
||||
entropytxs = n;
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
bool DicePlanExists(CScript &fundingPubKey,uint256 &fundingtxid,struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks)
|
||||
@@ -1220,7 +1225,7 @@ bool DicePlanExists(CScript &fundingPubKey,uint256 &fundingtxid,struct CCcontrac
|
||||
char CCaddr[64]; uint64_t sbits=0; uint256 txid,hashBlock; CTransaction tx;
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
GetCCaddress(cp,CCaddr,dicepk);
|
||||
SetCCtxids(txids,cp->normaladdr);
|
||||
SetCCtxids(txids,cp->normaladdr,false);
|
||||
if ( fundingtxid != zeroid ) // avoid scan unless creating new funding plan
|
||||
{
|
||||
//fprintf(stderr,"check fundingtxid\n");
|
||||
@@ -1316,7 +1321,7 @@ UniValue DiceList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits; int64_t minbet,maxbet,maxodds,timeoutblocks; char str[65];
|
||||
cp = CCinit(&C,EVAL_DICE);
|
||||
SetCCtxids(addressIndex,cp->normaladdr);
|
||||
SetCCtxids(addressIndex,cp->normaladdr,false);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -1447,7 +1452,7 @@ std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet
|
||||
CCerror = "Your dealer is broke, find a new casino.";
|
||||
return("");
|
||||
}
|
||||
if ( myIsutxo_spentinmempool(entropytxid,0) != 0 )
|
||||
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,entropytxid,0) != 0 )
|
||||
{
|
||||
CCerror = "entropy txid is spent";
|
||||
return("");
|
||||
@@ -1657,7 +1662,7 @@ void *dealer0_loop(void *_arg)
|
||||
if ( (cp= Diceinit(fundingPubKey,dealer0_fundingtxid,&C,planstr,txfee,mypk,dicepk,refsbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"error initializing dealer0_loop\n");
|
||||
exit(-1);
|
||||
StartShutdown();
|
||||
}
|
||||
fprintf(stderr,"dealer0 node running\n");
|
||||
height = lastht = 0;
|
||||
@@ -1769,7 +1774,7 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx
|
||||
return(0.);
|
||||
}
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
|
||||
3682
src/cc/dilithium.c
Normal file
3682
src/cc/dilithium.c
Normal file
File diff suppressed because one or more lines are too long
475
src/cc/dilithium.h
Normal file
475
src/cc/dilithium.h
Normal file
@@ -0,0 +1,475 @@
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
#ifndef CPUCYCLES_H
|
||||
#define CPUCYCLES_H
|
||||
|
||||
#ifdef DBENCH
|
||||
#define DBENCH_START() uint64_t time = cpucycles_start()
|
||||
#define DBENCH_STOP(t) t += cpucycles_stop() - time - timing_overhead
|
||||
#else
|
||||
#define DBENCH_START()
|
||||
#define DBENCH_STOP(t)
|
||||
#endif
|
||||
|
||||
#ifdef USE_RDPMC // Needs echo 2 > /sys/devices/cpu/rdpmc
|
||||
#ifdef SERIALIZE_RDC
|
||||
|
||||
static inline uint64_t cpucycles_start(void) {
|
||||
const uint32_t ecx = (1U << 30) + 1;
|
||||
uint64_t result;
|
||||
|
||||
asm volatile("cpuid; movl %1,%%ecx; rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax"
|
||||
: "=&a" (result) : "r" (ecx) : "rbx", "rcx", "rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64_t cpucycles_stop(void) {
|
||||
const uint32_t ecx = (1U << 30) + 1;
|
||||
uint64_t result, dummy;
|
||||
|
||||
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax; movq %%rax,%0; cpuid"
|
||||
: "=&r" (result), "=c" (dummy) : "c" (ecx) : "rax", "rbx", "rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint64_t cpucycles_start(void) {
|
||||
const uint32_t ecx = (1U << 30) + 1;
|
||||
uint64_t result;
|
||||
|
||||
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax"
|
||||
: "=a" (result) : "c" (ecx) : "rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64_t cpucycles_stop(void) {
|
||||
const uint32_t ecx = (1U << 30) + 1;
|
||||
uint64_t result;
|
||||
|
||||
asm volatile("rdpmc; shlq $32,%%rdx; orq %%rdx,%%rax"
|
||||
: "=a" (result) : "c" (ecx) : "rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#else
|
||||
#ifdef SERIALIZE_RDC
|
||||
|
||||
static inline uint64_t cpucycles_start(void) {
|
||||
uint64_t result;
|
||||
|
||||
asm volatile("cpuid; rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax"
|
||||
: "=a" (result) : : "%rbx", "%rcx", "%rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64_t cpucycles_stop(void) {
|
||||
uint64_t result;
|
||||
|
||||
asm volatile("rdtscp; shlq $32,%%rdx; orq %%rdx,%%rax; mov %%rax,%0; cpuid"
|
||||
: "=r" (result) : : "%rax", "%rbx", "%rcx", "%rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint64_t cpucycles_start(void) {
|
||||
uint64_t result;
|
||||
|
||||
asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax"
|
||||
: "=a" (result) : : "%rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64_t cpucycles_stop(void) {
|
||||
uint64_t result;
|
||||
|
||||
asm volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax"
|
||||
: "=a" (result) : : "%rdx");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int64_t cpucycles_overhead(void);
|
||||
|
||||
#endif*/
|
||||
|
||||
#ifndef FIPS202_H
|
||||
#define FIPS202_H
|
||||
|
||||
|
||||
#define SHAKE128_RATE 168
|
||||
#define SHAKE256_RATE 136
|
||||
|
||||
void shake128_absorb(uint64_t *s,
|
||||
const uint8_t *input,
|
||||
int32_t inlen);
|
||||
|
||||
void shake128_squeezeblocks(uint8_t *output,
|
||||
int32_t nblocks,
|
||||
uint64_t *s);
|
||||
|
||||
void shake256_absorb(uint64_t *s,
|
||||
const uint8_t *input,
|
||||
int32_t inlen);
|
||||
|
||||
void shake256_squeezeblocks(uint8_t *output,
|
||||
int32_t nblocks,
|
||||
uint64_t *s);
|
||||
|
||||
void shake128(uint8_t *output,
|
||||
int32_t outlen,
|
||||
const uint8_t *input,
|
||||
int32_t inlen);
|
||||
|
||||
void shake256(uint8_t *output,
|
||||
int32_t outlen,
|
||||
const uint8_t *input,
|
||||
int32_t inlen);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#ifndef MODE
|
||||
#define MODE 3
|
||||
#endif
|
||||
|
||||
#define SEEDBYTES 32U
|
||||
#define CRHBYTES 48U
|
||||
#define N 256U
|
||||
#define Q 8380417U
|
||||
#define QBITS 23U
|
||||
#define ROOT_OF_UNITY 1753U
|
||||
#define D 14U
|
||||
#define GAMMA1 ((Q - 1U)/16U)
|
||||
#define GAMMA2 (GAMMA1/2U)
|
||||
#define ALPHA (2U*GAMMA2)
|
||||
|
||||
#if MODE == 0
|
||||
#define K 3U
|
||||
#define L 2U
|
||||
#define ETA 7U
|
||||
#define SETABITS 4U
|
||||
#define BETA 375U
|
||||
#define OMEGA 64U
|
||||
|
||||
#elif MODE == 1
|
||||
#define K 4U
|
||||
#define L 3U
|
||||
#define ETA 6U
|
||||
#define SETABITS 4U
|
||||
#define BETA 325U
|
||||
#define OMEGA 80U
|
||||
|
||||
#elif MODE == 2
|
||||
#define K 5U
|
||||
#define L 4U
|
||||
#define ETA 5U
|
||||
#define SETABITS 4U
|
||||
#define BETA 275U
|
||||
#define OMEGA 96U
|
||||
|
||||
#elif MODE == 3
|
||||
#define K 6U
|
||||
#define L 5U
|
||||
#define ETA 3U
|
||||
#define SETABITS 3U
|
||||
#define BETA 175U
|
||||
#define OMEGA 120U
|
||||
|
||||
#endif
|
||||
|
||||
#define POL_SIZE_PACKED ((N*QBITS)/8)
|
||||
#define POLT1_SIZE_PACKED ((N*(QBITS - D))/8)
|
||||
#define POLT0_SIZE_PACKED ((N*D)/8)
|
||||
#define POLETA_SIZE_PACKED ((N*SETABITS)/8)
|
||||
#define POLZ_SIZE_PACKED ((N*(QBITS - 3))/8)
|
||||
#define POLW1_SIZE_PACKED ((N*4)/8)
|
||||
#define POLVECK_SIZE_PACKED (K*POL_SIZE_PACKED)
|
||||
#define POLVECL_SIZE_PACKED (L*POL_SIZE_PACKED)
|
||||
|
||||
#define CRYPTO_PUBLICKEYBYTES (SEEDBYTES + K*POLT1_SIZE_PACKED)
|
||||
#define CRYPTO_SECRETKEYBYTES (2*SEEDBYTES + (L + K)*POLETA_SIZE_PACKED + CRHBYTES + K*POLT0_SIZE_PACKED)
|
||||
#define CRYPTO_BYTES (L*POLZ_SIZE_PACKED + (OMEGA + K) + (N/8 + 8))
|
||||
|
||||
#endif
|
||||
#ifndef POLY_H
|
||||
#define POLY_H
|
||||
|
||||
//#include <stdint.h>
|
||||
//#include "params.h"
|
||||
//#include "fips202.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t coeffs[N];
|
||||
} poly __attribute__((aligned(32)));
|
||||
|
||||
void poly_reduce(poly *a);
|
||||
void poly_csubq(poly *a);
|
||||
void poly_freeze(poly *a);
|
||||
|
||||
void poly_add(poly *c, const poly *a, const poly *b);
|
||||
void poly_sub(poly *c, const poly *a, const poly *b);
|
||||
void poly_neg(poly *a);
|
||||
void poly_shiftl(poly *a, uint32_t k);
|
||||
|
||||
void poly_ntt(poly *a);
|
||||
void poly_invntt_montgomery(poly *a);
|
||||
void poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b);
|
||||
|
||||
void poly_power2round(poly *a1, poly *a0, const poly *a);
|
||||
void poly_decompose(poly *a1, poly *a0, const poly *a);
|
||||
uint32_t poly_make_hint(poly *h, const poly *a, const poly *b);
|
||||
void poly_use_hint(poly *a, const poly *b, const poly *h);
|
||||
|
||||
int poly_chknorm(const poly *a, uint32_t B);
|
||||
void poly_uniform(poly *a, const uint8_t *buf);
|
||||
void poly_uniform_eta(poly *a,
|
||||
const uint8_t seed[SEEDBYTES],
|
||||
uint8_t nonce);
|
||||
void poly_uniform_gamma1m1(poly *a,
|
||||
const uint8_t seed[SEEDBYTES + CRHBYTES],
|
||||
uint16_t nonce);
|
||||
|
||||
void polyeta_pack(uint8_t *r, const poly *a);
|
||||
void polyeta_unpack(poly *r, const uint8_t *a);
|
||||
|
||||
void polyt1_pack(uint8_t *r, const poly *a);
|
||||
void polyt1_unpack(poly *r, const uint8_t *a);
|
||||
|
||||
void polyt0_pack(uint8_t *r, const poly *a);
|
||||
void polyt0_unpack(poly *r, const uint8_t *a);
|
||||
|
||||
void polyz_pack(uint8_t *r, const poly *a);
|
||||
void polyz_unpack(poly *r, const uint8_t *a);
|
||||
|
||||
void polyw1_pack(uint8_t *r, const poly *a);
|
||||
#endif
|
||||
#ifndef POLYVEC_H
|
||||
#define POLYVEC_H
|
||||
|
||||
//#include <stdint.h>
|
||||
//#include "params.h"
|
||||
//#include "poly.h"
|
||||
|
||||
/* Vectors of polynomials of length L */
|
||||
typedef struct {
|
||||
poly vec[L];
|
||||
} polyvecl;
|
||||
|
||||
void polyvecl_freeze(polyvecl *v);
|
||||
|
||||
void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v);
|
||||
|
||||
void polyvecl_ntt(polyvecl *v);
|
||||
void polyvecl_pointwise_acc_invmontgomery(poly *w,
|
||||
const polyvecl *u,
|
||||
const polyvecl *v);
|
||||
|
||||
int polyvecl_chknorm(const polyvecl *v, uint32_t B);
|
||||
|
||||
|
||||
|
||||
/* Vectors of polynomials of length K */
|
||||
typedef struct {
|
||||
poly vec[K];
|
||||
} polyveck;
|
||||
|
||||
void polyveck_reduce(polyveck *v);
|
||||
void polyveck_csubq(polyveck *v);
|
||||
void polyveck_freeze(polyveck *v);
|
||||
|
||||
void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v);
|
||||
void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v);
|
||||
void polyveck_shiftl(polyveck *v, uint32_t k);
|
||||
|
||||
void polyveck_ntt(polyveck *v);
|
||||
void polyveck_invntt_montgomery(polyveck *v);
|
||||
|
||||
int polyveck_chknorm(const polyveck *v, uint32_t B);
|
||||
|
||||
void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v);
|
||||
void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v);
|
||||
uint32_t polyveck_make_hint(polyveck *h,
|
||||
const polyveck *u,
|
||||
const polyveck *v);
|
||||
void polyveck_use_hint(polyveck *w, const polyveck *v, const polyveck *h);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NTT_H
|
||||
#define NTT_H
|
||||
|
||||
//#include <stdint.h>
|
||||
//#include "params.h"
|
||||
|
||||
void ntt(uint32_t p[N]);
|
||||
void invntt_frominvmont(uint32_t p[N]);
|
||||
|
||||
#endif
|
||||
#ifndef PACKING_H
|
||||
#define PACKING_H
|
||||
|
||||
//#include "params.h"
|
||||
//#include "polyvec.h"
|
||||
|
||||
void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES],
|
||||
const uint8_t rho[SEEDBYTES], const polyveck *t1);
|
||||
void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES],
|
||||
const uint8_t rho[SEEDBYTES],
|
||||
const uint8_t key[SEEDBYTES],
|
||||
const uint8_t tr[CRHBYTES],
|
||||
const polyvecl *s1,
|
||||
const polyveck *s2,
|
||||
const polyveck *t0);
|
||||
void pack_sig(uint8_t sig[CRYPTO_BYTES],
|
||||
const polyvecl *z, const polyveck *h, const poly *c);
|
||||
|
||||
void unpack_pk(uint8_t rho[SEEDBYTES], polyveck *t1,
|
||||
const uint8_t pk[CRYPTO_PUBLICKEYBYTES]);
|
||||
void unpack_sk(uint8_t rho[SEEDBYTES],
|
||||
uint8_t key[SEEDBYTES],
|
||||
uint8_t tr[CRHBYTES],
|
||||
polyvecl *s1,
|
||||
polyveck *s2,
|
||||
polyveck *t0,
|
||||
const uint8_t sk[CRYPTO_SECRETKEYBYTES]);
|
||||
int unpack_sig(polyvecl *z, polyveck *h, poly *c,
|
||||
const uint8_t sig[CRYPTO_BYTES]);
|
||||
|
||||
#endif
|
||||
#ifndef REDUCE_H
|
||||
#define REDUCE_H
|
||||
|
||||
//#include <stdint.h>
|
||||
|
||||
#define MONT 4193792U // 2^32 % Q
|
||||
#define QINV 4236238847U // -q^(-1) mod 2^32
|
||||
|
||||
/* a <= Q*2^32 => r < 2*Q */
|
||||
uint32_t montgomery_reduce(uint64_t a);
|
||||
|
||||
/* r < 2*Q */
|
||||
uint32_t reduce32(uint32_t a);
|
||||
|
||||
/* a < 2*Q => r < Q */
|
||||
uint32_t csubq(uint32_t a);
|
||||
|
||||
/* r < Q */
|
||||
uint32_t freeze(uint32_t a);
|
||||
|
||||
#endif
|
||||
#ifndef ROUNDING_H
|
||||
#define ROUNDING_H
|
||||
|
||||
//#include <stdint.h>
|
||||
|
||||
uint32_t power2round(const uint32_t a, uint32_t *a0);
|
||||
uint32_t decompose(uint32_t a, uint32_t *a0);
|
||||
uint32_t make_hint(const uint32_t a, const uint32_t b);
|
||||
uint32_t use_hint(const uint32_t a, const uint32_t hint);
|
||||
|
||||
#endif
|
||||
#ifndef SIGN_H
|
||||
#define SIGN_H
|
||||
|
||||
//#include "params.h"
|
||||
//#include "poly.h"
|
||||
//#include "polyvec.h"
|
||||
|
||||
void expand_mat(polyvecl mat[K], const uint8_t rho[SEEDBYTES]);
|
||||
void challenge(poly *c, const uint8_t mu[CRHBYTES],
|
||||
const polyveck *w1);
|
||||
|
||||
int crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int crypto_sign(uint8_t *sm, int32_t *smlen,
|
||||
const uint8_t *msg, int32_t len,
|
||||
const uint8_t *sk);
|
||||
|
||||
int crypto_sign_open(uint8_t *m, int32_t *mlen,
|
||||
const uint8_t *sm, int32_t smlen,
|
||||
const uint8_t *pk);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef API_H
|
||||
#define API_H
|
||||
|
||||
#ifndef MODE
|
||||
#define MODE 3
|
||||
#endif
|
||||
|
||||
#if MODE == 0
|
||||
#if CRYPTO_PUBLICKEYBYTES -896U
|
||||
CRYPTO_PUBLICKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_SECRETKEYBYTES -2096U
|
||||
CRYPTO_SECRETKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_BYTES -1387U
|
||||
CRYPTO_BYTES size error
|
||||
#endif
|
||||
|
||||
#elif MODE == 1
|
||||
#if CRYPTO_PUBLICKEYBYTES -1184U
|
||||
CRYPTO_PUBLICKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_SECRETKEYBYTES -2800U
|
||||
CRYPTO_SECRETKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_BYTES -2044U
|
||||
CRYPTO_BYTES size error
|
||||
#endif
|
||||
|
||||
#elif MODE == 2
|
||||
#if CRYPTO_PUBLICKEYBYTES -1472U
|
||||
CRYPTO_PUBLICKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_SECRETKEYBYTES -3504U
|
||||
CRYPTO_SECRETKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_BYTES -2701U
|
||||
CRYPTO_BYTES size error
|
||||
#endif
|
||||
|
||||
#elif MODE == 3
|
||||
#if CRYPTO_PUBLICKEYBYTES -1760U
|
||||
CRYPTO_PUBLICKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_SECRETKEYBYTES -3856U
|
||||
CRYPTO_SECRETKEYBYTES size error
|
||||
#endif
|
||||
#if CRYPTO_BYTES -3366U
|
||||
CRYPTO_BYTES size error
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define CRYPTO_ALGNAME "Dilithium"
|
||||
|
||||
int crypto_sign_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
int crypto_sign(uint8_t *sm, int32_t *smlen,
|
||||
const uint8_t *msg, int32_t len,
|
||||
const uint8_t *sk);
|
||||
|
||||
int crypto_sign_open(uint8_t *m, int32_t *mlen,
|
||||
const uint8_t *sm, int32_t smlen,
|
||||
const uint8_t *pk);
|
||||
|
||||
#endif
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "core_io.h"
|
||||
#include "crosschain.h"
|
||||
|
||||
bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,const CTransaction &txTo,unsigned int nIn);
|
||||
char *CClib_name();
|
||||
|
||||
Eval* EVAL_TEST = 0;
|
||||
struct CCcontract_info CCinfos[0x100];
|
||||
@@ -38,8 +40,9 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
|
||||
pthread_mutex_lock(&KOMODO_CC_mutex);
|
||||
bool out = eval->Dispatch(cond, tx, nIn);
|
||||
pthread_mutex_unlock(&KOMODO_CC_mutex);
|
||||
//fprintf(stderr,"out %d vs %d isValid\n",(int32_t)out,(int32_t)eval->state.IsValid());
|
||||
assert(eval->state.IsValid() == out);
|
||||
if ( eval->state.IsValid() != out)
|
||||
fprintf(stderr,"out %d vs %d isValid\n",(int32_t)out,(int32_t)eval->state.IsValid());
|
||||
//assert(eval->state.IsValid() == out);
|
||||
|
||||
if (eval->state.IsValid()) return true;
|
||||
|
||||
@@ -64,13 +67,25 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
|
||||
return Invalid("empty-eval");
|
||||
|
||||
uint8_t ecode = cond->code[0];
|
||||
if ( ASSETCHAINS_CCDISABLES[ecode] != 0 )
|
||||
{
|
||||
fprintf(stderr,"%s evalcode.%d %02x\n",txTo.GetHash().GetHex().c_str(),ecode,ecode);
|
||||
return Invalid("disabled-code, -ac_ccenables didnt include this ecode");
|
||||
}
|
||||
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength);
|
||||
if ( ecode >= EVAL_FIRSTUSER && ecode <= EVAL_LASTUSER )
|
||||
{
|
||||
if ( ASSETCHAINS_CCLIB.size() > 0 && ASSETCHAINS_CCLIB == CClib_name() )
|
||||
return CClib_Dispatch(cond,this,vparams,txTo,nIn);
|
||||
else return Invalid("mismatched -ac_cclib vs CClib_name");
|
||||
}
|
||||
cp = &CCinfos[(int32_t)ecode];
|
||||
if ( cp->didinit == 0 )
|
||||
{
|
||||
CCinit(cp,ecode);
|
||||
cp->didinit = 1;
|
||||
}
|
||||
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength);
|
||||
|
||||
switch ( ecode )
|
||||
{
|
||||
case EVAL_IMPORTPAYOUT:
|
||||
@@ -139,46 +154,17 @@ int32_t Eval::GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t time
|
||||
return komodo_notaries(pubkeys, height, timestamp);
|
||||
}
|
||||
|
||||
|
||||
bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const
|
||||
{
|
||||
if (tx.vin.size() < 11) return false;
|
||||
|
||||
uint8_t seenNotaries[64] = {0};
|
||||
uint8_t notaries[64][33];
|
||||
int nNotaries = GetNotaries(notaries, height, timestamp);
|
||||
CrosschainAuthority auth;
|
||||
auth.requiredSigs = 11;
|
||||
auth.size = GetNotaries(auth.notaries, height, timestamp);
|
||||
|
||||
BOOST_FOREACH(const CTxIn &txIn, tx.vin)
|
||||
{
|
||||
// Get notary pubkey
|
||||
CTransaction tx;
|
||||
uint256 hashBlock;
|
||||
if (!GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false;
|
||||
if (tx.vout.size() < txIn.prevout.n) return false;
|
||||
CScript spk = tx.vout[txIn.prevout.n].scriptPubKey;
|
||||
if (spk.size() != 35) return false;
|
||||
std::vector<unsigned char> scriptVec = std::vector<unsigned char>(spk.begin(),spk.end());
|
||||
const unsigned char *pk = scriptVec.data();
|
||||
if (pk++[0] != 33) return false;
|
||||
if (pk[33] != OP_CHECKSIG) return false;
|
||||
|
||||
// Check it's a notary
|
||||
for (int i=0; i<nNotaries; i++) {
|
||||
if (!seenNotaries[i]) {
|
||||
if (memcmp(pk, notaries[i], 33) == 0) {
|
||||
seenNotaries[i] = 1;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
found:;
|
||||
}
|
||||
|
||||
return true;
|
||||
return CheckTxAuthority(tx, auth);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get MoM from a notarisation tx hash (on KMD)
|
||||
*/
|
||||
|
||||
@@ -55,9 +55,15 @@
|
||||
EVAL(EVAL_PEGS, 0xee) \
|
||||
EVAL(EVAL_MARMARA, 0xef) \
|
||||
EVAL(EVAL_PAYMENTS, 0xf0) \
|
||||
EVAL(EVAL_GATEWAYS, 0xf1)
|
||||
EVAL(EVAL_GATEWAYS, 0xf1) \
|
||||
EVAL(EVAL_TOKENS, 0xf2) \
|
||||
EVAL(EVAL_IMPORTGATEWAY, 0xf3) \
|
||||
|
||||
|
||||
// evalcodes 0x10 to 0x7f are reserved for cclib dynamic CC
|
||||
#define EVAL_FIRSTUSER 0x10
|
||||
#define EVAL_LASTUSER 0x7f
|
||||
|
||||
typedef uint8_t EvalCode;
|
||||
|
||||
|
||||
|
||||
@@ -118,15 +118,15 @@ bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
else if ( (hash[0] & 0xff) != 0 || (hash[31] & 0xff) != 0 )
|
||||
return eval->Invalid("invalid faucetget txid");
|
||||
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
|
||||
SetCCtxids(txids,destaddr);
|
||||
SetCCtxids(txids,destaddr,tx.vout[i].scriptPubKey.IsPayToCryptoCondition());
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
|
||||
{
|
||||
//int height = it->first.blockHeight;
|
||||
if ( CCduration(numblocks,it->first.txhash) > 0 && numblocks > 3 )
|
||||
{
|
||||
//fprintf(stderr,"would return error %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks);
|
||||
return eval->Invalid("faucet is only for brand new addresses");
|
||||
}
|
||||
//fprintf(stderr,"txid %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks);
|
||||
}
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
@@ -145,8 +145,12 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
|
||||
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+1);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
if ( maxinputs > CC_MAXVINS )
|
||||
maxinputs = CC_MAXVINS;
|
||||
if ( maxinputs > 0 )
|
||||
threshold = total/maxinputs;
|
||||
else threshold = total;
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -157,7 +161,7 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
|
||||
// no need to prevent dup
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsFaucetvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( (nValue= IsFaucetvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
|
||||
@@ -75,7 +75,7 @@ bool FSMExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
|
||||
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any FSM CC for now
|
||||
return eval->Invalid("no validation yet");
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
@@ -126,7 +126,7 @@ int64_t AddFSMInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey
|
||||
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);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
|
||||
289
src/cc/games/prices.c
Normal file
289
src/cc/games/prices.c
Normal file
@@ -0,0 +1,289 @@
|
||||
|
||||
#include "prices.h"
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#ifdef BUILD_GAMESCC
|
||||
#include "../rogue/cursesd.h"
|
||||
#else
|
||||
#include <curses.h>
|
||||
#endif
|
||||
|
||||
#define SATOSHIDEN ((uint64_t)100000000L)
|
||||
#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0)
|
||||
extern int64_t Net_change,Betsize;
|
||||
|
||||
int random_tetromino(struct games_state *rs)
|
||||
{
|
||||
rs->seed = _games_rngnext(rs->seed);
|
||||
return(rs->seed % NUM_TETROMINOS);
|
||||
}
|
||||
|
||||
int32_t pricesdata(struct games_player *P,void *ptr)
|
||||
{
|
||||
tetris_game *tg = (tetris_game *)ptr;
|
||||
P->gold = tg->points;
|
||||
P->dungeonlevel = tg->level;
|
||||
//fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void sleep_milli(int milliseconds)
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = milliseconds * 1000 * 1000;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
struct games_state globalR;
|
||||
extern char Gametxidstr[];
|
||||
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c);
|
||||
uint64_t get_btcusd();
|
||||
int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize);
|
||||
|
||||
void *gamesiterate(struct games_state *rs)
|
||||
{
|
||||
bool running = true; uint32_t eventid = 0; int64_t price;
|
||||
if ( rs->guiflag != 0 || rs->sleeptime != 0 )
|
||||
{
|
||||
initscr(); // initialize curses
|
||||
cbreak(); // pass key presses to program, but not signals
|
||||
noecho(); // don't echo key presses to screen
|
||||
timeout(0);
|
||||
}
|
||||
while ( running != 0 )
|
||||
{
|
||||
//running = tg_tick(rs,tg,move);
|
||||
if ( rs->guiflag != 0 || rs->sleeptime != 0 )
|
||||
{
|
||||
}
|
||||
if ( rs->guiflag != 0 )
|
||||
{
|
||||
#ifdef STANDALONE
|
||||
price = get_btcusd();
|
||||
//fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000);
|
||||
//issue_games_events(rs,Gametxidstr,eventid,price);
|
||||
issue_bet(rs,price,Betsize);
|
||||
eventid++;
|
||||
doupdate();
|
||||
sleep(10);
|
||||
switch ( getch() )
|
||||
{
|
||||
case '+': Net_change++; break;
|
||||
case '-': Net_change--; break;
|
||||
case '0': Net_change = 0; break;
|
||||
case '$': Betsize = SATOSHIDEN; break;
|
||||
case '^': Betsize += (Betsize >> 3); break;
|
||||
case '/': Betsize -= (Betsize >> 3); break;
|
||||
}
|
||||
/*if ( (counter++ % 10) == 0 )
|
||||
doupdate();
|
||||
c = games_readevent(rs);
|
||||
if ( c <= 0x7f || skipcount == 0x3fff )
|
||||
{
|
||||
if ( skipcount > 0 )
|
||||
issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000);
|
||||
if ( c <= 0x7f )
|
||||
issue_games_events(rs,Gametxidstr,eventid,c);
|
||||
if ( tg->level != prevlevel )
|
||||
{
|
||||
flushkeystrokes(rs,0);
|
||||
prevlevel = tg->level;
|
||||
}
|
||||
skipcount = 0;
|
||||
} else skipcount++;*/
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rs->replaydone != 0 )
|
||||
break;
|
||||
if ( rs->sleeptime != 0 )
|
||||
{
|
||||
sleep_milli(1);
|
||||
}
|
||||
/*if ( skipcount == 0 )
|
||||
{
|
||||
c = games_readevent(rs);
|
||||
//fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level);
|
||||
if ( (c & 0x4000) == 0x4000 )
|
||||
{
|
||||
skipcount = (c & 0x3fff);
|
||||
c = 'S';
|
||||
}
|
||||
}
|
||||
if ( skipcount > 0 )
|
||||
skipcount--;*/
|
||||
}
|
||||
eventid++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
#include <ncurses.h>
|
||||
#include "dapps/dappstd.c"
|
||||
int64_t Net_change,Betsize = SATOSHIDEN;
|
||||
|
||||
char *send_curl(char *url,char *fname)
|
||||
{
|
||||
char *retstr;
|
||||
retstr = issue_curl(url);
|
||||
return(retstr);
|
||||
}
|
||||
|
||||
cJSON *get_urljson(char *url,char *fname)
|
||||
{
|
||||
char *jsonstr; cJSON *json = 0;
|
||||
if ( (jsonstr= send_curl(url,fname)) != 0 )
|
||||
{
|
||||
//printf("(%s) -> (%s)\n",url,jsonstr);
|
||||
json = cJSON_Parse(jsonstr);
|
||||
free(jsonstr);
|
||||
}
|
||||
return(json);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// start of dapp
|
||||
//////////////////////////////////////////////
|
||||
|
||||
uint64_t get_btcusd()
|
||||
{
|
||||
cJSON *pjson,*bpi,*usd; char str[512]; uint64_t x,newprice,mult,btcusd = 0;
|
||||
if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json",(char *)"/tmp/oraclefeed.json")) != 0 )
|
||||
{
|
||||
if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 )
|
||||
{
|
||||
btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN;
|
||||
mult = 10000 + Net_change*10;
|
||||
newprice = (btcusd * mult) / 10000;
|
||||
x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff);
|
||||
sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f Net %.1f%% [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice),(double)100*(mult-10000)/10000);
|
||||
mvaddstr(0, 0, str);
|
||||
clrtoeol();
|
||||
doupdate();
|
||||
}
|
||||
free_json(pjson);
|
||||
}
|
||||
return(x);
|
||||
}
|
||||
|
||||
char *clonestr(char *str)
|
||||
{
|
||||
char *clone; int32_t len;
|
||||
if ( str == 0 || str[0] == 0 )
|
||||
{
|
||||
printf("warning cloning nullstr.%p\n",str);
|
||||
#ifdef __APPLE__
|
||||
while ( 1 ) sleep(1);
|
||||
#endif
|
||||
str = (char *)"<nullstr>";
|
||||
}
|
||||
len = strlen(str);
|
||||
clone = (char *)calloc(1,len+16);
|
||||
strcpy(clone,str);
|
||||
return(clone);
|
||||
}
|
||||
|
||||
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c)
|
||||
{
|
||||
static FILE *fp;
|
||||
char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1;
|
||||
if ( fp == 0 )
|
||||
fp = fopen("events.log","wb");
|
||||
rs->buffered[rs->num++] = c;
|
||||
if ( 1 )
|
||||
{
|
||||
if ( sizeof(c) == 1 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid);
|
||||
else if ( sizeof(c) == 2 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid);
|
||||
else if ( sizeof(c) == 4 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid);
|
||||
else if ( sizeof(c) == 8 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid);
|
||||
if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 )
|
||||
{
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( (resobj= jobj(retjson,(char *)"result")) != 0 )
|
||||
{
|
||||
retval = 0;
|
||||
if ( fp != 0 )
|
||||
{
|
||||
fprintf(fp,"%s\n",jprint(resobj,0));
|
||||
fflush(fp);
|
||||
}
|
||||
}
|
||||
free_json(retjson);
|
||||
} else fprintf(fp,"error parsing %s\n",retstr);
|
||||
free(retstr);
|
||||
} else fprintf(fp,"error issuing method %s\n",params);
|
||||
return(retval);
|
||||
} else return(0);
|
||||
}
|
||||
|
||||
int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize)
|
||||
{
|
||||
char params[512],hexstr[64],*retstr; cJSON *retjson,*resobj; int32_t i,retval = -1;
|
||||
memset(hexstr,0,sizeof(hexstr));
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
sprintf(&hexstr[i<<1],"%02x",(uint8_t)(x & 0xff));
|
||||
x >>= 8;
|
||||
}
|
||||
sprintf(params,"[\"bet\",\"17\",\"[%.8f,%%22%s%%22]\"]",dstr(betsize),hexstr);
|
||||
if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 )
|
||||
{
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( (resobj= jobj(retjson,(char *)"result")) != 0 )
|
||||
{
|
||||
retval = 0;
|
||||
//fprintf(stderr,"%s\n",jprint(resobj,0));
|
||||
}
|
||||
free_json(retjson);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
int prices(int argc, char **argv)
|
||||
{
|
||||
struct games_state *rs = &globalR;
|
||||
int32_t c,skipcount=0; uint32_t eventid = 0;
|
||||
memset(rs,0,sizeof(*rs));
|
||||
rs->guiflag = 1;
|
||||
rs->sleeptime = 1; // non-zero to allow refresh()
|
||||
if ( argc >= 2 && strlen(argv[2]) == 64 )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
rs->origseed = _strtoui64(argv[1], NULL, 10);
|
||||
#else
|
||||
rs->origseed = atol(argv[1]); // windows, but not MSVC
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
rs->origseed = atol(argv[1]); // non-windows
|
||||
#endif // _WIN32
|
||||
rs->seed = rs->origseed;
|
||||
if ( argc >= 3 )
|
||||
{
|
||||
strcpy(Gametxidstr,argv[2]);
|
||||
fprintf(stderr,"setplayerdata %s\n",Gametxidstr);
|
||||
if ( games_setplayerdata(rs,Gametxidstr) < 0 )
|
||||
{
|
||||
fprintf(stderr,"invalid gametxid, or already started\n");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
} else rs->seed = 777;
|
||||
gamesiterate(rs);
|
||||
//gamesbailout(rs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
281
src/cc/games/prices.cpp
Normal file
281
src/cc/games/prices.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
std::string MYCCLIBNAME = (char *)"prices";
|
||||
|
||||
#define PRICES_BETPERIOD 3
|
||||
UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag);
|
||||
extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
|
||||
#define bstr(x) ((double)((uint32_t)x) / 10000.)
|
||||
|
||||
struct prices_bar
|
||||
{
|
||||
uint64_t open,high,low,close,sum;
|
||||
int32_t num;
|
||||
};
|
||||
|
||||
int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits)
|
||||
{
|
||||
uint32_t uprice,timestamp;
|
||||
timestamp = (uint32_t)(pricebits >> 32);
|
||||
uprice = (uint32_t)pricebits;
|
||||
bar->sum += uprice, bar->num++;
|
||||
if ( bar->open == 0 )
|
||||
bar->open = bar->high = bar->low = pricebits;
|
||||
if ( uprice > (uint32_t)bar->high )
|
||||
bar->high = pricebits;
|
||||
else if ( uprice < (uint32_t)bar->low )
|
||||
bar->low = pricebits;
|
||||
bar->close = pricebits;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits)
|
||||
{
|
||||
int64_t a,dist = 0;
|
||||
if ( aveprice != 0 )
|
||||
{
|
||||
a = (pricebits & 0xffffffff);
|
||||
dist = (a - aveprice);
|
||||
dist *= dist;
|
||||
//fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice);
|
||||
}
|
||||
return(dist);
|
||||
}
|
||||
|
||||
void prices_bardisp(struct prices_bar *bar)
|
||||
{
|
||||
if ( bar->num == 0 )
|
||||
fprintf(stderr,"BAR null\n");
|
||||
else fprintf(stderr,"BAR ave %.4f (O %.4f, H %.4f, L %.4f, C %.4f)\n",bstr(bar->sum/bar->num),bstr(bar->open),bstr(bar->high),bstr(bar->low),bstr(bar->close));
|
||||
}
|
||||
|
||||
int64_t prices_blockinfo(int32_t height,char *acaddr)
|
||||
{
|
||||
std::vector<uint8_t> vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,mindist=(1LL<<60),prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar;
|
||||
if ( (pindex= komodo_chainactive(height)) != 0 )
|
||||
{
|
||||
if ( komodo_blockload(block,pindex) == 0 )
|
||||
{
|
||||
n = block.vtx.size();
|
||||
vini = 0;
|
||||
memset(&refbar,0,sizeof(refbar));
|
||||
for (iter=0; iter<2; iter++)
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
tx = block.vtx[i];
|
||||
if ( myGetTransaction(tx.vin[vini].prevout.hash,vintx,hashBlock) == 0 )
|
||||
continue;
|
||||
else if ( tx.vin[vini].prevout.n >= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 )
|
||||
continue;
|
||||
else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a )
|
||||
{
|
||||
GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
|
||||
if ( vopret.size() == 8 )
|
||||
{
|
||||
E_UNMARSHAL(vopret,ss >> pricebits);
|
||||
timestamp = (uint32_t)(pricebits >> 32);
|
||||
uprice = (uint32_t)pricebits;
|
||||
if ( iter == 0 )
|
||||
{
|
||||
prizefund += tx.vout[0].nValue;
|
||||
if ( strcmp(acaddr,destaddr) == 0 )
|
||||
{
|
||||
//fprintf(stderr,"REF ");
|
||||
prices_barupdate(&refbar,pricebits);
|
||||
}
|
||||
}
|
||||
else if ( strcmp(acaddr,destaddr) != 0 )
|
||||
{
|
||||
dist = prices_bardist(&refbar,aveprice,pricebits);
|
||||
if ( dist < mindist )
|
||||
{
|
||||
mindist = dist;
|
||||
mini = i;
|
||||
}
|
||||
fprintf(stderr,"mini.%d i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",mini,i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)dist);
|
||||
}
|
||||
} else return(-3);
|
||||
}
|
||||
}
|
||||
if ( iter == 0 )
|
||||
{
|
||||
prices_bardisp(&refbar);
|
||||
if ( refbar.num != 0 )
|
||||
aveprice = (uint32_t)refbar.sum / refbar.num;
|
||||
}
|
||||
}
|
||||
return(prizefund);
|
||||
} else return(-2);
|
||||
} else return(-1);
|
||||
}
|
||||
|
||||
UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight();
|
||||
if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error"," no -ac_pubkey for price reference"));
|
||||
return(result);
|
||||
}
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
gamespk = GetUnspendable(cp,0);
|
||||
acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33);
|
||||
Getscriptaddress(acaddr,CScript() << ParseHex(HexStr(acpk)) << OP_CHECKSIG);
|
||||
if ( params != 0 && cJSON_GetArraySize(params) == 1 )
|
||||
{
|
||||
height = juint(jitem(params,0),0);
|
||||
result.push_back(Pair("height",(int64_t)height));
|
||||
if ( (prizefund= prices_blockinfo(height,acaddr)) < 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("errorcode",prizefund));
|
||||
result.push_back(Pair("error","blockinfo error"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// display bets
|
||||
if ( height <= nextheight-PRICES_BETPERIOD )
|
||||
{
|
||||
// settle bets by first nonzero reference bar
|
||||
}
|
||||
result.push_back(Pair("prizefund",ValueFromAmount(prizefund)));
|
||||
result.push_back(Pair("result","success"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt parse"));
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk;
|
||||
if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error"," no -ac_pubkey for price reference"));
|
||||
return(result);
|
||||
}
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
gamespk = GetUnspendable(cp,0);
|
||||
acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33);
|
||||
if ( params != 0 && cJSON_GetArraySize(params) == 2 )
|
||||
{
|
||||
amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049;
|
||||
if ( cclib_parsehash((uint8_t *)&price,jitem(params,1),8) < 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt parsehash"));
|
||||
return(result);
|
||||
}
|
||||
if ( mypk == acpk )
|
||||
{
|
||||
amount = 0; // i am the reference price feed
|
||||
//fprintf(stderr,"i am the reference\n");
|
||||
}
|
||||
//fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price);
|
||||
if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk));
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price);
|
||||
return(games_rawtxresult(result,rawtx,1));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","not enough funds"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt parse"));
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine)
|
||||
{
|
||||
//fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)((uint64_t)timestamp<<32) | uprice);
|
||||
}
|
||||
|
||||
// game specific code for daemon
|
||||
void games_packitemstr(char *packitemstr,struct games_packitem *item)
|
||||
{
|
||||
strcpy(packitemstr,"");
|
||||
}
|
||||
|
||||
int64_t games_cashout(struct games_player *P)
|
||||
{
|
||||
int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0;
|
||||
cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel;
|
||||
return(cashout);
|
||||
}
|
||||
|
||||
void pricesplayerjson(UniValue &obj,struct games_player *P)
|
||||
{
|
||||
obj.push_back(Pair("packsize",(int64_t)P->packsize));
|
||||
obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints));
|
||||
obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff)));
|
||||
obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16)));
|
||||
obj.push_back(Pair("level",(int64_t)P->level));
|
||||
obj.push_back(Pair("experience",(int64_t)P->experience));
|
||||
obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel));
|
||||
}
|
||||
|
||||
int32_t disp_gamesplayer(char *str,struct games_player *P)
|
||||
{
|
||||
str[0] = 0;
|
||||
//if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 )
|
||||
// return(-1);
|
||||
sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector<uint8_t> payload)
|
||||
{
|
||||
uint256 gametxid; int32_t i,len; char str[67]; int64_t price; uint32_t eventid = 0;
|
||||
if ( (len= payload.size()) > 36 )
|
||||
{
|
||||
len -= 36;
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)&gametxid)[i] = payload[len+i];
|
||||
eventid = (uint32_t)payload[len+32];
|
||||
eventid |= (uint32_t)payload[len+33] << 8;
|
||||
eventid |= (uint32_t)payload[len+34] << 16;
|
||||
eventid |= (uint32_t)payload[len+35] << 24;
|
||||
for (i=0; i<len&&i<sizeof(price); i++)
|
||||
((uint8_t *)&price)[7-i] = payload[i];
|
||||
prices_update((uint32_t)(price >> 32),(uint32_t)(price & 0xffffffff),pk == pubkey2pk(Mypubkey()));
|
||||
//fprintf(stderr,"%llu -> t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000);
|
||||
//fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid);
|
||||
return(0);
|
||||
} else return(-1);
|
||||
}
|
||||
|
||||
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
208
src/cc/games/prices.h
Normal file
208
src/cc/games/prices.h
Normal file
@@ -0,0 +1,208 @@
|
||||
|
||||
#ifndef H_PRICES_H
|
||||
#define H_PRICES_H
|
||||
|
||||
/***************************************************************************/
|
||||
/** https://github.com/brenns10/tetris
|
||||
@file main.c
|
||||
@author Stephen Brennan
|
||||
@date Created Wednesday, 10 June 2015
|
||||
@brief Main program for tetris.
|
||||
@copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised
|
||||
BSD License. See LICENSE.txt for details.
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
Convert a tetromino type to its corresponding cell.
|
||||
*/
|
||||
#define TYPE_TO_CELL(x) ((x)+1)
|
||||
|
||||
/*
|
||||
Strings for how you would print a tetris board.
|
||||
*/
|
||||
#define TC_EMPTY_STR " "
|
||||
#define TC_BLOCK_STR "\u2588"
|
||||
|
||||
/*
|
||||
Questions about a tetris cell.
|
||||
*/
|
||||
#define TC_IS_EMPTY(x) ((x) == TC_EMPTY)
|
||||
#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x))
|
||||
|
||||
/*
|
||||
How many cells in a tetromino?
|
||||
*/
|
||||
#define TETRIS 4
|
||||
/*
|
||||
How many tetrominos?
|
||||
*/
|
||||
#define NUM_TETROMINOS 7
|
||||
/*
|
||||
How many orientations of a tetromino?
|
||||
*/
|
||||
#define NUM_ORIENTATIONS 4
|
||||
|
||||
/*
|
||||
Level constants.
|
||||
*/
|
||||
#define MAX_LEVEL 19
|
||||
#define LINES_PER_LEVEL 10
|
||||
|
||||
/*
|
||||
A "cell" is a 1x1 block within a tetris board.
|
||||
*/
|
||||
typedef enum {
|
||||
TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ
|
||||
} tetris_cell;
|
||||
|
||||
/*
|
||||
A "type" is a type/shape of a tetromino. Not including orientation.
|
||||
*/
|
||||
typedef enum {
|
||||
TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z
|
||||
} tetris_type;
|
||||
|
||||
/*
|
||||
A row,column pair. Negative numbers allowed, because we need them for
|
||||
offsets.
|
||||
*/
|
||||
typedef struct {
|
||||
int row;
|
||||
int col;
|
||||
} tetris_location;
|
||||
|
||||
/*
|
||||
A "block" is a struct that contains information about a tetromino.
|
||||
Specifically, what type it is, what orientation it has, and where it is.
|
||||
*/
|
||||
typedef struct {
|
||||
int typ;
|
||||
int ori;
|
||||
tetris_location loc;
|
||||
} tetris_block;
|
||||
|
||||
/*
|
||||
All possible moves to give as input to the game.
|
||||
*/
|
||||
typedef enum {
|
||||
TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE
|
||||
} tetris_move;
|
||||
|
||||
/*
|
||||
A game object!
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
Game board stuff:
|
||||
*/
|
||||
int rows;
|
||||
int cols;
|
||||
/*
|
||||
Scoring information:
|
||||
*/
|
||||
int points;
|
||||
int level;
|
||||
/*
|
||||
Falling block is the one currently going down. Next block is the one that
|
||||
will be falling after this one. Stored is the block that you can swap out.
|
||||
*/
|
||||
tetris_block falling;
|
||||
tetris_block next;
|
||||
tetris_block stored;
|
||||
/*
|
||||
Number of game ticks until the block will move down.
|
||||
*/
|
||||
int ticks_till_gravity;
|
||||
/*
|
||||
Number of lines until you advance to the next level.
|
||||
*/
|
||||
int lines_remaining;
|
||||
char board[];
|
||||
} tetris_game;
|
||||
|
||||
/*
|
||||
This array stores all necessary information about the cells that are filled by
|
||||
each tetromino. The first index is the type of the tetromino (i.e. shape,
|
||||
e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final
|
||||
array contains 4 tetris_location objects, each mapping to an offset from a
|
||||
point on the upper left that is the tetromino "origin".
|
||||
*/
|
||||
extern const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS];
|
||||
|
||||
/*
|
||||
This array tells you how many ticks per gravity by level. Decreases as level
|
||||
increases, to add difficulty.
|
||||
*/
|
||||
extern const int GRAVITY_LEVEL[MAX_LEVEL+1];
|
||||
|
||||
// Data structure manipulation.
|
||||
void tg_init(tetris_game *obj, int rows, int cols);
|
||||
tetris_game *tg_create(struct games_state *rs,int rows, int cols);
|
||||
void tg_destroy(tetris_game *obj);
|
||||
void tg_delete(tetris_game *obj);
|
||||
tetris_game *tg_load(FILE *f);
|
||||
void tg_save(tetris_game *obj, FILE *f);
|
||||
|
||||
// Public methods not related to memory:
|
||||
char tg_get(tetris_game *obj, int row, int col);
|
||||
bool tg_check(tetris_game *obj, int row, int col);
|
||||
bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move);
|
||||
void tg_print(tetris_game *obj, FILE *f);
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
#define GAMENAME "prices" // name of executable
|
||||
#define GAMEMAIN prices // main program of game
|
||||
#define GAMEPLAYERJSON pricesplayerjson // displays game specific json
|
||||
#define GAMEDATA pricesdata // extracts data from game specific variables into games_state
|
||||
#define CHAINNAME "PRICES" // -ac_name=
|
||||
typedef uint64_t gamesevent; // can be 8, 16, 32, or 64 bits
|
||||
|
||||
#define MAXPACK 23
|
||||
struct games_packitem
|
||||
{
|
||||
int32_t type,launch,count,which,hplus,dplus,arm,flags,group;
|
||||
char damage[8],hurldmg[8];
|
||||
};
|
||||
|
||||
struct games_player
|
||||
{
|
||||
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet;
|
||||
struct games_packitem gamespack[MAXPACK];
|
||||
};
|
||||
|
||||
struct games_state
|
||||
{
|
||||
uint64_t seed,origseed;
|
||||
char *keystrokeshex;
|
||||
uint32_t needflush,replaydone;
|
||||
int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum;
|
||||
FILE *logfp;
|
||||
struct games_player P;
|
||||
gamesevent buffered[5000],*keystrokes;
|
||||
uint8_t playerdata[8192];
|
||||
};
|
||||
extern struct games_state globalR;
|
||||
void *gamesiterate(struct games_state *rs);
|
||||
int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag);
|
||||
|
||||
void games_packitemstr(char *packitemstr,struct games_packitem *item);
|
||||
uint64_t _games_rngnext(uint64_t initseed);
|
||||
int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis);
|
||||
gamesevent games_revendian(gamesevent revx);
|
||||
int32_t disp_gamesplayer(char *str,struct games_player *P);
|
||||
|
||||
#endif
|
||||
|
||||
904
src/cc/games/tetris.c
Normal file
904
src/cc/games/tetris.c
Normal file
@@ -0,0 +1,904 @@
|
||||
|
||||
#include "tetris.h"
|
||||
|
||||
/*
|
||||
In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure.
|
||||
|
||||
also, the standalone game needs to support argv of seed gametxid, along with replay args
|
||||
*/
|
||||
|
||||
int random_tetromino(struct games_state *rs)
|
||||
{
|
||||
rs->seed = _games_rngnext(rs->seed);
|
||||
return(rs->seed % NUM_TETROMINOS);
|
||||
}
|
||||
|
||||
int32_t tetrisdata(struct games_player *P,void *ptr)
|
||||
{
|
||||
tetris_game *tg = (tetris_game *)ptr;
|
||||
P->gold = tg->points;
|
||||
P->dungeonlevel = tg->level;
|
||||
//fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/** https://github.com/brenns10/tetris
|
||||
@file main.c
|
||||
@author Stephen Brennan
|
||||
@date Created Wednesday, 10 June 2015
|
||||
@brief Main program for tetris.
|
||||
@copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised
|
||||
BSD License. See LICENSE.txt for details.
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h> // for FILE
|
||||
#include <stdbool.h> // for bool
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef BUILD_GAMESCC
|
||||
#include "../rogue/cursesd.h"
|
||||
#else
|
||||
#include <curses.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
|
||||
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
|
||||
|
||||
/*******************************************************************************
|
||||
Array Definitions
|
||||
*******************************************************************************/
|
||||
|
||||
const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] =
|
||||
{
|
||||
// I
|
||||
{{{1, 0}, {1, 1}, {1, 2}, {1, 3}},
|
||||
{{0, 2}, {1, 2}, {2, 2}, {3, 2}},
|
||||
{{3, 0}, {3, 1}, {3, 2}, {3, 3}},
|
||||
{{0, 1}, {1, 1}, {2, 1}, {3, 1}}},
|
||||
// J
|
||||
{{{0, 0}, {1, 0}, {1, 1}, {1, 2}},
|
||||
{{0, 1}, {0, 2}, {1, 1}, {2, 1}},
|
||||
{{1, 0}, {1, 1}, {1, 2}, {2, 2}},
|
||||
{{0, 1}, {1, 1}, {2, 0}, {2, 1}}},
|
||||
// L
|
||||
{{{0, 2}, {1, 0}, {1, 1}, {1, 2}},
|
||||
{{0, 1}, {1, 1}, {2, 1}, {2, 2}},
|
||||
{{1, 0}, {1, 1}, {1, 2}, {2, 0}},
|
||||
{{0, 0}, {0, 1}, {1, 1}, {2, 1}}},
|
||||
// O
|
||||
{{{0, 1}, {0, 2}, {1, 1}, {1, 2}},
|
||||
{{0, 1}, {0, 2}, {1, 1}, {1, 2}},
|
||||
{{0, 1}, {0, 2}, {1, 1}, {1, 2}},
|
||||
{{0, 1}, {0, 2}, {1, 1}, {1, 2}}},
|
||||
// S
|
||||
{{{0, 1}, {0, 2}, {1, 0}, {1, 1}},
|
||||
{{0, 1}, {1, 1}, {1, 2}, {2, 2}},
|
||||
{{1, 1}, {1, 2}, {2, 0}, {2, 1}},
|
||||
{{0, 0}, {1, 0}, {1, 1}, {2, 1}}},
|
||||
// T
|
||||
{{{0, 1}, {1, 0}, {1, 1}, {1, 2}},
|
||||
{{0, 1}, {1, 1}, {1, 2}, {2, 1}},
|
||||
{{1, 0}, {1, 1}, {1, 2}, {2, 1}},
|
||||
{{0, 1}, {1, 0}, {1, 1}, {2, 1}}},
|
||||
// Z
|
||||
{{{0, 0}, {0, 1}, {1, 1}, {1, 2}},
|
||||
{{0, 2}, {1, 1}, {1, 2}, {2, 1}},
|
||||
{{1, 0}, {1, 1}, {2, 1}, {2, 2}},
|
||||
{{0, 1}, {1, 0}, {1, 1}, {2, 0}}},
|
||||
};
|
||||
|
||||
const int GRAVITY_LEVEL[MAX_LEVEL+1] = {
|
||||
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
50, 48, 46, 44, 42, 40, 38, 36, 34, 32,
|
||||
//10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
30, 28, 26, 24, 22, 20, 16, 12, 8, 4
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
Helper Functions for Blocks
|
||||
*******************************************************************************/
|
||||
|
||||
void sleep_milli(int milliseconds)
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = milliseconds * 1000 * 1000;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
Return the block at the given row and column.
|
||||
*/
|
||||
char tg_get(tetris_game *obj, int row, int column)
|
||||
{
|
||||
return obj->board[obj->cols * row + column];
|
||||
}
|
||||
|
||||
/*
|
||||
Set the block at the given row and column.
|
||||
*/
|
||||
static void tg_set(tetris_game *obj, int row, int column, char value)
|
||||
{
|
||||
obj->board[obj->cols * row + column] = value;
|
||||
}
|
||||
|
||||
/*
|
||||
Check whether a row and column are in bounds.
|
||||
*/
|
||||
bool tg_check(tetris_game *obj, int row, int col)
|
||||
{
|
||||
return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols;
|
||||
}
|
||||
|
||||
/*
|
||||
Place a block onto the board.
|
||||
*/
|
||||
static void tg_put(tetris_game *obj, tetris_block block)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < TETRIS; i++) {
|
||||
tetris_location cell = TETROMINOS[block.typ][block.ori][i];
|
||||
tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col,
|
||||
TYPE_TO_CELL(block.typ));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Clear a block out of the board.
|
||||
*/
|
||||
static void tg_remove(tetris_game *obj, tetris_block block)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < TETRIS; i++) {
|
||||
tetris_location cell = TETROMINOS[block.typ][block.ori][i];
|
||||
tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check if a block can be placed on the board.
|
||||
*/
|
||||
static bool tg_fits(tetris_game *obj, tetris_block block)
|
||||
{
|
||||
int i, r, c;
|
||||
for (i = 0; i < TETRIS; i++) {
|
||||
tetris_location cell = TETROMINOS[block.typ][block.ori][i];
|
||||
r = block.loc.row + cell.row;
|
||||
c = block.loc.col + cell.col;
|
||||
if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Create a new falling block and populate the next falling block with a random
|
||||
one.
|
||||
*/
|
||||
static void tg_new_falling(struct games_state *rs,tetris_game *obj)
|
||||
{
|
||||
// Put in a new falling tetromino.
|
||||
obj->falling = obj->next;
|
||||
obj->next.typ = random_tetromino(rs);
|
||||
obj->next.ori = 0;
|
||||
obj->next.loc.row = 0;
|
||||
obj->next.loc.col = obj->cols/2 - 2;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Game Turn Helpers
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
Tick gravity, and move the block down if gravity should act.
|
||||
*/
|
||||
static void tg_do_gravity_tick(struct games_state *rs,tetris_game *obj)
|
||||
{
|
||||
obj->ticks_till_gravity--;
|
||||
if (obj->ticks_till_gravity <= 0) {
|
||||
tg_remove(obj, obj->falling);
|
||||
obj->falling.loc.row++;
|
||||
if (tg_fits(obj, obj->falling)) {
|
||||
obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level];
|
||||
} else {
|
||||
obj->falling.loc.row--;
|
||||
tg_put(obj, obj->falling);
|
||||
|
||||
tg_new_falling(rs,obj);
|
||||
}
|
||||
tg_put(obj, obj->falling);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Move the falling tetris block left (-1) or right (+1).
|
||||
*/
|
||||
static void tg_move(tetris_game *obj, int direction)
|
||||
{
|
||||
tg_remove(obj, obj->falling);
|
||||
obj->falling.loc.col += direction;
|
||||
if (!tg_fits(obj, obj->falling)) {
|
||||
obj->falling.loc.col -= direction;
|
||||
}
|
||||
tg_put(obj, obj->falling);
|
||||
}
|
||||
|
||||
/*
|
||||
Send the falling tetris block to the bottom.
|
||||
*/
|
||||
static void tg_down(struct games_state *rs,tetris_game *obj)
|
||||
{
|
||||
tg_remove(obj, obj->falling);
|
||||
while (tg_fits(obj, obj->falling)) {
|
||||
obj->falling.loc.row++;
|
||||
}
|
||||
obj->falling.loc.row--;
|
||||
tg_put(obj, obj->falling);
|
||||
tg_new_falling(rs,obj);
|
||||
}
|
||||
|
||||
/*
|
||||
Rotate the falling block in either direction (+/-1).
|
||||
*/
|
||||
static void tg_rotate(tetris_game *obj, int direction)
|
||||
{
|
||||
tg_remove(obj, obj->falling);
|
||||
|
||||
while (true) {
|
||||
obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS;
|
||||
|
||||
// If the new orientation fits, we're done.
|
||||
if (tg_fits(obj, obj->falling))
|
||||
break;
|
||||
|
||||
// Otherwise, try moving left to make it fit.
|
||||
obj->falling.loc.col--;
|
||||
if (tg_fits(obj, obj->falling))
|
||||
break;
|
||||
|
||||
// Finally, try moving right to make it fit.
|
||||
obj->falling.loc.col += 2;
|
||||
if (tg_fits(obj, obj->falling))
|
||||
break;
|
||||
|
||||
// Put it back in its original location and try the next orientation.
|
||||
obj->falling.loc.col--;
|
||||
// Worst case, we come back to the original orientation and it fits, so this
|
||||
// loop will terminate.
|
||||
}
|
||||
|
||||
tg_put(obj, obj->falling);
|
||||
}
|
||||
|
||||
/*
|
||||
Swap the falling block with the block in the hold buffer.
|
||||
*/
|
||||
static void tg_hold(struct games_state *rs,tetris_game *obj)
|
||||
{
|
||||
tg_remove(obj, obj->falling);
|
||||
if (obj->stored.typ == -1) {
|
||||
obj->stored = obj->falling;
|
||||
tg_new_falling(rs,obj);
|
||||
} else {
|
||||
int typ = obj->falling.typ, ori = obj->falling.ori;
|
||||
obj->falling.typ = obj->stored.typ;
|
||||
obj->falling.ori = obj->stored.ori;
|
||||
obj->stored.typ = typ;
|
||||
obj->stored.ori = ori;
|
||||
while (!tg_fits(obj, obj->falling)) {
|
||||
obj->falling.loc.row--;
|
||||
if (tg_fits(obj, obj->falling)) {
|
||||
break;
|
||||
}
|
||||
obj->falling.loc.col--;
|
||||
if (tg_fits(obj, obj->falling)) {
|
||||
break;
|
||||
}
|
||||
obj->falling.loc.col += 2;
|
||||
}
|
||||
}
|
||||
tg_put(obj, obj->falling);
|
||||
}
|
||||
|
||||
/*
|
||||
Perform the action specified by the move.
|
||||
*/
|
||||
static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move move)
|
||||
{
|
||||
switch (move) {
|
||||
case TM_LEFT:
|
||||
//fprintf(stderr,"LEFT ");
|
||||
tg_move(obj, -1);
|
||||
break;
|
||||
case TM_RIGHT:
|
||||
//fprintf(stderr,"RIGHT ");
|
||||
tg_move(obj, 1);
|
||||
break;
|
||||
case TM_DROP:
|
||||
tg_down(rs,obj);
|
||||
break;
|
||||
case TM_CLOCK:
|
||||
tg_rotate(obj, 1);
|
||||
break;
|
||||
case TM_COUNTER:
|
||||
tg_rotate(obj, -1);
|
||||
break;
|
||||
case TM_HOLD:
|
||||
tg_hold(rs,obj);
|
||||
break;
|
||||
default:
|
||||
// pass
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Return true if line i is full.
|
||||
*/
|
||||
static bool tg_line_full(tetris_game *obj, int i)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < obj->cols; j++) {
|
||||
if (TC_IS_EMPTY(tg_get(obj, i, j)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Shift every row above r down one.
|
||||
*/
|
||||
static void tg_shift_lines(tetris_game *obj, int r)
|
||||
{
|
||||
int i, j;
|
||||
for (i = r-1; i >= 0; i--) {
|
||||
for (j = 0; j < obj->cols; j++) {
|
||||
tg_set(obj, i+1, j, tg_get(obj, i, j));
|
||||
tg_set(obj, i, j, TC_EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Find rows that are filled, remove them, shift, and return the number of
|
||||
cleared rows.
|
||||
*/
|
||||
static int tg_check_lines(tetris_game *obj)
|
||||
{
|
||||
int i, nlines = 0;
|
||||
tg_remove(obj, obj->falling); // don't want to mess up falling block
|
||||
|
||||
for (i = obj->rows-1; i >= 0; i--) {
|
||||
if (tg_line_full(obj, i)) {
|
||||
tg_shift_lines(obj, i);
|
||||
i++; // do this line over again since they're shifted
|
||||
nlines++;
|
||||
}
|
||||
}
|
||||
|
||||
tg_put(obj, obj->falling); // replace
|
||||
return nlines;
|
||||
}
|
||||
|
||||
/*
|
||||
Adjust the score for the game, given how many lines were just cleared.
|
||||
*/
|
||||
static void tg_adjust_score(tetris_game *obj, int lines_cleared)
|
||||
{
|
||||
static int line_multiplier[] = {0, 40, 100, 300, 1200};
|
||||
obj->points += line_multiplier[lines_cleared] * (obj->level + 1);
|
||||
if (lines_cleared >= obj->lines_remaining) {
|
||||
obj->level = MIN(MAX_LEVEL, obj->level + 1);
|
||||
lines_cleared -= obj->lines_remaining;
|
||||
obj->lines_remaining = LINES_PER_LEVEL - lines_cleared;
|
||||
} else {
|
||||
obj->lines_remaining -= lines_cleared;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Return true if the game is over.
|
||||
*/
|
||||
static bool tg_game_over(tetris_game *obj)
|
||||
{
|
||||
int i, j;
|
||||
bool over = false;
|
||||
tg_remove(obj, obj->falling);
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < obj->cols; j++) {
|
||||
if (TC_IS_FILLED(tg_get(obj, i, j))) {
|
||||
over = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
tg_put(obj, obj->falling);
|
||||
return over;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Main Public Functions
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
Do a single game tick: process gravity, user input, and score. Return true if
|
||||
the game is still running, false if it is over.
|
||||
*/
|
||||
bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move)
|
||||
{
|
||||
int lines_cleared;
|
||||
// Handle gravity.
|
||||
tg_do_gravity_tick(rs,obj);
|
||||
|
||||
// Handle input.
|
||||
tg_handle_move(rs,obj, move);
|
||||
|
||||
// Check for cleared lines
|
||||
lines_cleared = tg_check_lines(obj);
|
||||
|
||||
tg_adjust_score(obj, lines_cleared);
|
||||
|
||||
// Return whether the game will continue (NOT whether it's over)
|
||||
return !tg_game_over(obj);
|
||||
}
|
||||
|
||||
void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols)
|
||||
{
|
||||
// Initialization logic
|
||||
obj->rows = rows;
|
||||
obj->cols = cols;
|
||||
//obj->board = (char *)malloc(rows * cols);
|
||||
memset(obj->board, TC_EMPTY, rows * cols);
|
||||
obj->points = 0;
|
||||
obj->level = 0;
|
||||
obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level];
|
||||
obj->lines_remaining = LINES_PER_LEVEL;
|
||||
//srand(time(NULL));
|
||||
tg_new_falling(rs,obj);
|
||||
tg_new_falling(rs,obj);
|
||||
obj->stored.typ = -1;
|
||||
obj->stored.ori = 0;
|
||||
obj->stored.loc.row = 0;
|
||||
obj->next.loc.col = obj->cols/2 - 2;
|
||||
//printf("%d", obj->falling.loc.col);
|
||||
}
|
||||
|
||||
tetris_game *tg_create(struct games_state *rs,int rows, int cols)
|
||||
{
|
||||
tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game) + rows*cols);
|
||||
tg_init(rs,obj, rows, cols);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*void tg_destroy(tetris_game *obj)
|
||||
{
|
||||
// Cleanup logic
|
||||
free(obj->board);
|
||||
}*/
|
||||
|
||||
void tg_delete(tetris_game *obj) {
|
||||
//tg_destroy(obj);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
Load a game from a file.
|
||||
|
||||
tetris_game *tg_load(FILE *f)
|
||||
{
|
||||
tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game));
|
||||
if (fread(obj, sizeof(tetris_game), 1, f) != 1 )
|
||||
{
|
||||
fprintf(stderr,"read game error\n");
|
||||
free(obj);
|
||||
obj = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj->board = (char *)malloc(obj->rows * obj->cols);
|
||||
if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols )
|
||||
{
|
||||
fprintf(stderr,"fread error\n");
|
||||
free(obj->board);
|
||||
free(obj);
|
||||
obj = 0;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}*/
|
||||
|
||||
/*
|
||||
Save a game to a file.
|
||||
|
||||
void tg_save(tetris_game *obj, FILE *f)
|
||||
{
|
||||
if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 )
|
||||
fprintf(stderr,"error writing tetrisgame\n");
|
||||
else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols )
|
||||
fprintf(stderr,"error writing board\n");
|
||||
}*/
|
||||
|
||||
/*
|
||||
Print a game board to a file. Really just for early debugging.
|
||||
*/
|
||||
void tg_print(tetris_game *obj, FILE *f) {
|
||||
int i, j;
|
||||
for (i = 0; i < obj->rows; i++) {
|
||||
for (j = 0; j < obj->cols; j++) {
|
||||
if (TC_IS_EMPTY(tg_get(obj, i, j))) {
|
||||
fputs(TC_EMPTY_STR, f);
|
||||
} else {
|
||||
fputs(TC_BLOCK_STR, f);
|
||||
}
|
||||
}
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
2 columns per cell makes the game much nicer.
|
||||
*/
|
||||
#define COLS_PER_CELL 2
|
||||
/*
|
||||
Macro to print a cell of a specific type to a window.
|
||||
*/
|
||||
#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \
|
||||
waddch((w),' '|A_REVERSE|COLOR_PAIR(x))
|
||||
#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ')
|
||||
|
||||
/*
|
||||
Print the tetris board onto the ncurses window.
|
||||
*/
|
||||
void display_board(WINDOW *w, tetris_game *obj)
|
||||
{
|
||||
int i, j;
|
||||
box(w, 0, 0);
|
||||
for (i = 0; i < obj->rows; i++) {
|
||||
wmove(w, 1 + i, 1);
|
||||
for (j = 0; j < obj->cols; j++) {
|
||||
if (TC_IS_FILLED(tg_get(obj, i, j))) {
|
||||
ADD_BLOCK(w,tg_get(obj, i, j));
|
||||
} else {
|
||||
ADD_EMPTY(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
wnoutrefresh(w);
|
||||
}
|
||||
|
||||
/*
|
||||
Display a tetris piece in a dedicated window.
|
||||
*/
|
||||
void display_piece(WINDOW *w, tetris_block block)
|
||||
{
|
||||
int b;
|
||||
tetris_location c;
|
||||
wclear(w);
|
||||
box(w, 0, 0);
|
||||
if (block.typ == -1) {
|
||||
wnoutrefresh(w);
|
||||
return;
|
||||
}
|
||||
for (b = 0; b < TETRIS; b++) {
|
||||
c = TETROMINOS[block.typ][block.ori][b];
|
||||
wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1);
|
||||
ADD_BLOCK(w, TYPE_TO_CELL(block.typ));
|
||||
}
|
||||
wnoutrefresh(w);
|
||||
}
|
||||
|
||||
/*
|
||||
Display score information in a dedicated window.
|
||||
*/
|
||||
void display_score(WINDOW *w, tetris_game *tg)
|
||||
{
|
||||
wclear(w);
|
||||
box(w, 0, 0);
|
||||
wprintw(w, (char *)"Score\n%d\n", tg->points);
|
||||
wprintw(w, (char *)"Level\n%d\n", tg->level);
|
||||
wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining);
|
||||
wnoutrefresh(w);
|
||||
}
|
||||
|
||||
/*
|
||||
Save and exit the game.
|
||||
|
||||
void save(tetris_game *game, WINDOW *w)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
wclear(w);
|
||||
box(w, 0, 0); // return the border
|
||||
wmove(w, 1, 1);
|
||||
wprintw(w, (char *)"Save and exit? [Y/n] ");
|
||||
wrefresh(w);
|
||||
timeout(-1);
|
||||
if (getch() == 'n') {
|
||||
timeout(0);
|
||||
return;
|
||||
}
|
||||
f = fopen("tetris.save", "w");
|
||||
tg_save(game, f);
|
||||
fclose(f);
|
||||
tg_delete(game);
|
||||
endwin();
|
||||
fprintf(stderr,"Game saved to \"tetris.save\".\n");
|
||||
fprintf(stderr,"Resume by passing the filename as an argument to this program.\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}*/
|
||||
|
||||
/*
|
||||
Do the NCURSES initialization steps for color blocks.
|
||||
*/
|
||||
void init_colors(void)
|
||||
{
|
||||
start_color();
|
||||
//init_color(COLOR_ORANGE, 1000, 647, 0);
|
||||
init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK);
|
||||
init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK);
|
||||
init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK);
|
||||
init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK);
|
||||
init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK);
|
||||
init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK);
|
||||
init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK);
|
||||
}
|
||||
|
||||
struct games_state globalR;
|
||||
extern char Gametxidstr[];
|
||||
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c);
|
||||
gamesevent games_readevent(struct games_state *rs);
|
||||
|
||||
void *gamesiterate(struct games_state *rs)
|
||||
{
|
||||
uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE;
|
||||
gamesevent c; uint16_t skipcount=0; int32_t prevlevel; uint32_t eventid = 0; tetris_game *tg;
|
||||
WINDOW *board, *next, *hold, *score;
|
||||
if ( rs->guiflag != 0 || rs->sleeptime != 0 )
|
||||
{
|
||||
// NCURSES initialization:
|
||||
initscr(); // initialize curses
|
||||
cbreak(); // pass key presses to program, but not signals
|
||||
noecho(); // don't echo key presses to screen
|
||||
keypad(stdscr, TRUE); // allow arrow keys
|
||||
timeout(0); // no blocking on getch()
|
||||
curs_set(0); // set the cursor to invisible
|
||||
init_colors(); // setup tetris colors
|
||||
}
|
||||
tg = tg_create(rs,22, 10);
|
||||
prevlevel = tg->level;
|
||||
// Create windows for each section of the interface.
|
||||
board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0);
|
||||
next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1);
|
||||
hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1);
|
||||
score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1);
|
||||
while ( running != 0 )
|
||||
{
|
||||
running = tg_tick(rs,tg,move);
|
||||
if ( 1 && (rs->guiflag != 0 || rs->sleeptime != 0) )
|
||||
{
|
||||
display_board(board,tg);
|
||||
display_piece(next,tg->next);
|
||||
display_piece(hold,tg->stored);
|
||||
display_score(score,tg);
|
||||
}
|
||||
if ( rs->guiflag != 0 )
|
||||
{
|
||||
#ifdef STANDALONE
|
||||
sleep_milli(15);
|
||||
if ( (counter++ % 10) == 0 )
|
||||
doupdate();
|
||||
c = games_readevent(rs);
|
||||
if ( c <= 0x7f || skipcount == 0x3fff )
|
||||
{
|
||||
if ( skipcount > 0 )
|
||||
issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000);
|
||||
if ( c <= 0x7f )
|
||||
issue_games_events(rs,Gametxidstr,eventid,c);
|
||||
if ( tg->level != prevlevel )
|
||||
{
|
||||
flushkeystrokes(rs,0);
|
||||
prevlevel = tg->level;
|
||||
}
|
||||
skipcount = 0;
|
||||
} else skipcount++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rs->replaydone != 0 )
|
||||
break;
|
||||
if ( rs->sleeptime != 0 )
|
||||
{
|
||||
sleep_milli(1);
|
||||
if ( (counter++ % 20) == 0 )
|
||||
doupdate();
|
||||
}
|
||||
if ( skipcount == 0 )
|
||||
{
|
||||
c = games_readevent(rs);
|
||||
//fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level);
|
||||
if ( (c & 0x4000) == 0x4000 )
|
||||
{
|
||||
skipcount = (c & 0x3fff);
|
||||
c = 'S';
|
||||
}
|
||||
}
|
||||
if ( skipcount > 0 )
|
||||
skipcount--;
|
||||
}
|
||||
eventid++;
|
||||
switch ( c )
|
||||
{
|
||||
case 'h':
|
||||
move = TM_LEFT;
|
||||
break;
|
||||
case 'l':
|
||||
move = TM_RIGHT;
|
||||
break;
|
||||
case 'k':
|
||||
move = TM_CLOCK;
|
||||
break;
|
||||
case 'j':
|
||||
move = TM_DROP;
|
||||
break;
|
||||
case 'q':
|
||||
running = false;
|
||||
move = TM_NONE;
|
||||
break;
|
||||
/*case 'p':
|
||||
wclear(board);
|
||||
box(board, 0, 0);
|
||||
wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2);
|
||||
wprintw(board, "PAUSED");
|
||||
wrefresh(board);
|
||||
timeout(-1);
|
||||
getch();
|
||||
timeout(0);
|
||||
move = TM_NONE;
|
||||
break;
|
||||
case 's':
|
||||
save(tg, board);
|
||||
move = TM_NONE;
|
||||
break;*/
|
||||
case ' ':
|
||||
move = TM_HOLD;
|
||||
break;
|
||||
default:
|
||||
move = TM_NONE;
|
||||
}
|
||||
}
|
||||
return(tg);
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
/*
|
||||
Main tetris game!
|
||||
*/
|
||||
#include "dapps/dappstd.c"
|
||||
|
||||
|
||||
char *clonestr(char *str)
|
||||
{
|
||||
char *clone; int32_t len;
|
||||
if ( str == 0 || str[0] == 0 )
|
||||
{
|
||||
printf("warning cloning nullstr.%p\n",str);
|
||||
#ifdef __APPLE__
|
||||
while ( 1 ) sleep(1);
|
||||
#endif
|
||||
str = (char *)"<nullstr>";
|
||||
}
|
||||
len = strlen(str);
|
||||
clone = (char *)calloc(1,len+16);
|
||||
strcpy(clone,str);
|
||||
return(clone);
|
||||
}
|
||||
|
||||
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c)
|
||||
{
|
||||
static FILE *fp;
|
||||
char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1;
|
||||
if ( fp == 0 )
|
||||
fp = fopen("events.log","wb");
|
||||
rs->buffered[rs->num++] = c;
|
||||
if ( 0 )
|
||||
{
|
||||
if ( sizeof(c) == 1 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid);
|
||||
else if ( sizeof(c) == 2 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid);
|
||||
else if ( sizeof(c) == 4 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid);
|
||||
else if ( sizeof(c) == 8 )
|
||||
sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid);
|
||||
if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 )
|
||||
{
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( (resobj= jobj(retjson,(char *)"result")) != 0 )
|
||||
{
|
||||
retval = 0;
|
||||
if ( fp != 0 )
|
||||
{
|
||||
fprintf(fp,"%s\n",jprint(resobj,0));
|
||||
fflush(fp);
|
||||
}
|
||||
}
|
||||
free_json(retjson);
|
||||
} else fprintf(fp,"error parsing %s\n",retstr);
|
||||
free(retstr);
|
||||
} else fprintf(fp,"error issuing method %s\n",params);
|
||||
return(retval);
|
||||
} else return(0);
|
||||
}
|
||||
|
||||
int tetris(int argc, char **argv)
|
||||
{
|
||||
struct games_state *rs = &globalR;
|
||||
int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0;
|
||||
memset(rs,0,sizeof(*rs));
|
||||
rs->guiflag = 1;
|
||||
rs->sleeptime = 1; // non-zero to allow refresh()
|
||||
if ( argc >= 2 && strlen(argv[2]) == 64 )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
rs->origseed = _strtoui64(argv[1], NULL, 10);
|
||||
#else
|
||||
rs->origseed = atol(argv[1]); // windows, but not MSVC
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
rs->origseed = atol(argv[1]); // non-windows
|
||||
#endif // _WIN32
|
||||
rs->seed = rs->origseed;
|
||||
if ( argc >= 3 )
|
||||
{
|
||||
strcpy(Gametxidstr,argv[2]);
|
||||
fprintf(stderr,"setplayerdata %s\n",Gametxidstr);
|
||||
if ( games_setplayerdata(rs,Gametxidstr) < 0 )
|
||||
{
|
||||
fprintf(stderr,"invalid gametxid, or already started\n");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
} else rs->seed = 777;
|
||||
|
||||
/* Load file if given a filename.
|
||||
if (argc >= 2) {
|
||||
FILE *f = fopen(argv[1], "r");
|
||||
if (f == NULL) {
|
||||
perror("tetris");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
tg = tg_load(f);
|
||||
fclose(f);
|
||||
} else {
|
||||
// Otherwise create new game.
|
||||
tg = tg_create(rs,22, 10);
|
||||
}*/
|
||||
|
||||
// Game loop
|
||||
tg = (tetris_game *)gamesiterate(rs);
|
||||
gamesbailout(rs);
|
||||
// Deinitialize NCurses
|
||||
wclear(stdscr);
|
||||
endwin();
|
||||
// Output ending message.
|
||||
printf("Game over!\n");
|
||||
printf("You finished with %d points on level %d.\n", tg->points, tg->level);
|
||||
|
||||
// Deinitialize Tetris
|
||||
tg_delete(tg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
87
src/cc/games/tetris.cpp
Normal file
87
src/cc/games/tetris.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
std::string MYCCLIBNAME = (char *)"gamescc";
|
||||
|
||||
// game specific code for daemon
|
||||
void games_packitemstr(char *packitemstr,struct games_packitem *item)
|
||||
{
|
||||
strcpy(packitemstr,"");
|
||||
}
|
||||
|
||||
int64_t games_cashout(struct games_player *P)
|
||||
{
|
||||
int32_t dungeonlevel = P->dungeonlevel; int64_t mult=10000,cashout = 0;
|
||||
cashout = (uint64_t)P->gold * mult;
|
||||
return(cashout);
|
||||
}
|
||||
|
||||
void tetrisplayerjson(UniValue &obj,struct games_player *P)
|
||||
{
|
||||
obj.push_back(Pair("packsize",(int64_t)P->packsize));
|
||||
obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints));
|
||||
obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff)));
|
||||
obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16)));
|
||||
obj.push_back(Pair("level",(int64_t)P->level));
|
||||
obj.push_back(Pair("experience",(int64_t)P->experience));
|
||||
obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel));
|
||||
}
|
||||
|
||||
int32_t disp_gamesplayer(char *str,struct games_player *P)
|
||||
{
|
||||
str[0] = 0;
|
||||
//if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 )
|
||||
// return(-1);
|
||||
sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector<uint8_t> payload)
|
||||
{
|
||||
uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0;
|
||||
if ( (len= payload.size()) > 36 )
|
||||
{
|
||||
len -= 36;
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)&gametxid)[i] = payload[len+i];
|
||||
eventid = (uint32_t)payload[len+32];
|
||||
eventid |= (uint32_t)payload[len+33] << 8;
|
||||
eventid |= (uint32_t)payload[len+34] << 16;
|
||||
eventid |= (uint32_t)payload[len+35] << 24;
|
||||
//for (i=0; i<len; i++)
|
||||
// fprintf(stderr,"%02x",payload[i]);
|
||||
//fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid);
|
||||
return(0);
|
||||
} else return(-1);
|
||||
}
|
||||
|
||||
UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
UniValue result;
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
UniValue result;
|
||||
return(result);
|
||||
}
|
||||
|
||||
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
208
src/cc/games/tetris.h
Normal file
208
src/cc/games/tetris.h
Normal file
@@ -0,0 +1,208 @@
|
||||
|
||||
#ifndef H_TETRIS_H
|
||||
#define H_TETRIS_H
|
||||
|
||||
/***************************************************************************/
|
||||
/** https://github.com/brenns10/tetris
|
||||
@file main.c
|
||||
@author Stephen Brennan
|
||||
@date Created Wednesday, 10 June 2015
|
||||
@brief Main program for tetris.
|
||||
@copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised
|
||||
BSD License. See LICENSE.txt for details.
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
Convert a tetromino type to its corresponding cell.
|
||||
*/
|
||||
#define TYPE_TO_CELL(x) ((x)+1)
|
||||
|
||||
/*
|
||||
Strings for how you would print a tetris board.
|
||||
*/
|
||||
#define TC_EMPTY_STR " "
|
||||
#define TC_BLOCK_STR "\u2588"
|
||||
|
||||
/*
|
||||
Questions about a tetris cell.
|
||||
*/
|
||||
#define TC_IS_EMPTY(x) ((x) == TC_EMPTY)
|
||||
#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x))
|
||||
|
||||
/*
|
||||
How many cells in a tetromino?
|
||||
*/
|
||||
#define TETRIS 4
|
||||
/*
|
||||
How many tetrominos?
|
||||
*/
|
||||
#define NUM_TETROMINOS 7
|
||||
/*
|
||||
How many orientations of a tetromino?
|
||||
*/
|
||||
#define NUM_ORIENTATIONS 4
|
||||
|
||||
/*
|
||||
Level constants.
|
||||
*/
|
||||
#define MAX_LEVEL 19
|
||||
#define LINES_PER_LEVEL 10
|
||||
|
||||
/*
|
||||
A "cell" is a 1x1 block within a tetris board.
|
||||
*/
|
||||
typedef enum {
|
||||
TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ
|
||||
} tetris_cell;
|
||||
|
||||
/*
|
||||
A "type" is a type/shape of a tetromino. Not including orientation.
|
||||
*/
|
||||
typedef enum {
|
||||
TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z
|
||||
} tetris_type;
|
||||
|
||||
/*
|
||||
A row,column pair. Negative numbers allowed, because we need them for
|
||||
offsets.
|
||||
*/
|
||||
typedef struct {
|
||||
int row;
|
||||
int col;
|
||||
} tetris_location;
|
||||
|
||||
/*
|
||||
A "block" is a struct that contains information about a tetromino.
|
||||
Specifically, what type it is, what orientation it has, and where it is.
|
||||
*/
|
||||
typedef struct {
|
||||
int typ;
|
||||
int ori;
|
||||
tetris_location loc;
|
||||
} tetris_block;
|
||||
|
||||
/*
|
||||
All possible moves to give as input to the game.
|
||||
*/
|
||||
typedef enum {
|
||||
TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE
|
||||
} tetris_move;
|
||||
|
||||
/*
|
||||
A game object!
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
Game board stuff:
|
||||
*/
|
||||
int rows;
|
||||
int cols;
|
||||
/*
|
||||
Scoring information:
|
||||
*/
|
||||
int points;
|
||||
int level;
|
||||
/*
|
||||
Falling block is the one currently going down. Next block is the one that
|
||||
will be falling after this one. Stored is the block that you can swap out.
|
||||
*/
|
||||
tetris_block falling;
|
||||
tetris_block next;
|
||||
tetris_block stored;
|
||||
/*
|
||||
Number of game ticks until the block will move down.
|
||||
*/
|
||||
int ticks_till_gravity;
|
||||
/*
|
||||
Number of lines until you advance to the next level.
|
||||
*/
|
||||
int lines_remaining;
|
||||
char board[];
|
||||
} tetris_game;
|
||||
|
||||
/*
|
||||
This array stores all necessary information about the cells that are filled by
|
||||
each tetromino. The first index is the type of the tetromino (i.e. shape,
|
||||
e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final
|
||||
array contains 4 tetris_location objects, each mapping to an offset from a
|
||||
point on the upper left that is the tetromino "origin".
|
||||
*/
|
||||
extern const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS];
|
||||
|
||||
/*
|
||||
This array tells you how many ticks per gravity by level. Decreases as level
|
||||
increases, to add difficulty.
|
||||
*/
|
||||
extern const int GRAVITY_LEVEL[MAX_LEVEL+1];
|
||||
|
||||
// Data structure manipulation.
|
||||
void tg_init(tetris_game *obj, int rows, int cols);
|
||||
tetris_game *tg_create(struct games_state *rs,int rows, int cols);
|
||||
void tg_destroy(tetris_game *obj);
|
||||
void tg_delete(tetris_game *obj);
|
||||
tetris_game *tg_load(FILE *f);
|
||||
void tg_save(tetris_game *obj, FILE *f);
|
||||
|
||||
// Public methods not related to memory:
|
||||
char tg_get(tetris_game *obj, int row, int col);
|
||||
bool tg_check(tetris_game *obj, int row, int col);
|
||||
bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move);
|
||||
void tg_print(tetris_game *obj, FILE *f);
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
#define GAMENAME "tetris" // name of executable
|
||||
#define GAMEMAIN tetris // main program of game
|
||||
#define GAMEPLAYERJSON tetrisplayerjson // displays game specific json
|
||||
#define GAMEDATA tetrisdata // extracts data from game specific variables into games_state
|
||||
#define CHAINNAME "GTEST" // -ac_name=
|
||||
typedef uint16_t gamesevent; // can be 8, 16, 32, or 64 bits
|
||||
|
||||
#define MAXPACK 23
|
||||
struct games_packitem
|
||||
{
|
||||
int32_t type,launch,count,which,hplus,dplus,arm,flags,group;
|
||||
char damage[8],hurldmg[8];
|
||||
};
|
||||
|
||||
struct games_player
|
||||
{
|
||||
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet;
|
||||
struct games_packitem gamespack[MAXPACK];
|
||||
};
|
||||
|
||||
struct games_state
|
||||
{
|
||||
uint64_t seed,origseed;
|
||||
char *keystrokeshex;
|
||||
uint32_t needflush,replaydone;
|
||||
int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum;
|
||||
FILE *logfp;
|
||||
struct games_player P;
|
||||
gamesevent buffered[5000],*keystrokes;
|
||||
uint8_t playerdata[8192];
|
||||
};
|
||||
extern struct games_state globalR;
|
||||
void *gamesiterate(struct games_state *rs);
|
||||
int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag);
|
||||
|
||||
void games_packitemstr(char *packitemstr,struct games_packitem *item);
|
||||
uint64_t _games_rngnext(uint64_t initseed);
|
||||
int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis);
|
||||
gamesevent games_revendian(gamesevent revx);
|
||||
int32_t disp_gamesplayer(char *str,struct games_player *P);
|
||||
|
||||
#endif
|
||||
|
||||
1811
src/cc/gamescc.cpp
Normal file
1811
src/cc/gamescc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
120
src/cc/gamescc.h
Normal file
120
src/cc/gamescc.h
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef H_GAMESCC_H
|
||||
#define H_GAMESCC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#define GAMES_RNGMULT 11109
|
||||
#define GAMES_RNGOFFSET 13849
|
||||
#define GAMES_MAXRNGS 10000
|
||||
|
||||
#ifndef STANDALONE
|
||||
|
||||
#define ENABLE_WALLET
|
||||
extern CWallet* pwalletMain;
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "secp256k1.h"
|
||||
|
||||
|
||||
#define EVAL_GAMES (EVAL_FAUCET2+1)
|
||||
#define GAMES_TXFEE 10000
|
||||
#define GAMES_MAXITERATIONS 777
|
||||
#define GAMES_MAXKEYSTROKESGAP 60
|
||||
#define GAMES_MAXPLAYERS 64
|
||||
#define GAMES_REGISTRATIONSIZE (100 * 10000)
|
||||
#define GAMES_REGISTRATION 1
|
||||
|
||||
|
||||
#define MYCCNAME "games"
|
||||
|
||||
std::string Games_pname;
|
||||
|
||||
#define RPC_FUNCS \
|
||||
{ (char *)MYCCNAME, (char *)"rng", (char *)"hash,playerid", 1, 2, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"rngnext", (char *)"seed", 1, 1, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"fund", (char *)"amount", 1, 1, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"players", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"games", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"pending", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"setname", (char *)"pname", 1, 1, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"newgame", (char *)"maxplayers,buyin", 2, 2, 'C', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"playerinfo", (char *)"playertxid", 1, 1, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"gameinfo", (char *)"gametxid", 1, 1, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"keystrokes", (char *)"txid,hexstr", 2, 2, 'K', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"bailout", (char *)"gametxid", 1, 1, 'Q', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"events", (char *)"eventshex [gametxid [eventid]]", 1, 3, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"bet", (char *)"amount hexstr", 2, 2, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"settle", (char *)"height", 1, 1, ' ', EVAL_GAMES }, \
|
||||
{ (char *)MYCCNAME, (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_GAMES },
|
||||
|
||||
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
|
||||
UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
||||
|
||||
#define CUSTOM_DISPATCH \
|
||||
if ( cp->evalcode == EVAL_GAMES ) \
|
||||
{ \
|
||||
if ( strcmp(method,"rng") == 0 ) \
|
||||
return(games_rng(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"rngnext") == 0 ) \
|
||||
return(games_rngnext(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"newgame") == 0 ) \
|
||||
return(games_newgame(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"gameinfo") == 0 ) \
|
||||
return(games_gameinfo(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"register") == 0 ) \
|
||||
return(games_register(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"events") == 0 ) \
|
||||
return(games_events(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"players") == 0 ) \
|
||||
return(games_players(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"games") == 0 ) \
|
||||
return(games_games(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"pending") == 0 ) \
|
||||
return(games_pending(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"setname") == 0 ) \
|
||||
return(games_setname(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"playerinfo") == 0 ) \
|
||||
return(games_playerinfo(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"keystrokes") == 0 ) \
|
||||
return(games_keystrokes(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"extract") == 0 ) \
|
||||
return(games_extract(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"bailout") == 0 ) \
|
||||
return(games_bailout(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"highlander") == 0 ) \
|
||||
return(games_highlander(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"fund") == 0 ) \
|
||||
return(games_fund(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"bet") == 0 ) \
|
||||
return(games_bet(txfee,cp,params)); \
|
||||
else if ( strcmp(method,"settle") == 0 ) \
|
||||
return(games_settle(txfee,cp,params)); \
|
||||
else \
|
||||
{ \
|
||||
result.push_back(Pair("result","error")); \
|
||||
result.push_back(Pair("error","invalid gamescc method")); \
|
||||
return(result); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1609
src/cc/gateways.cpp
1609
src/cc/gateways.cpp
File diff suppressed because it is too large
Load Diff
1375
src/cc/heir.cpp
1375
src/cc/heir.cpp
File diff suppressed because it is too large
Load Diff
670
src/cc/heir_validate.h
Normal file
670
src/cc/heir_validate.h
Normal file
@@ -0,0 +1,670 @@
|
||||
#ifndef HEIR_VALIDATE_H
|
||||
#define HEIR_VALIDATE_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "CCHeir.h"
|
||||
|
||||
#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos)
|
||||
|
||||
// makes coin initial tx opret
|
||||
vscript_t EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo);
|
||||
vscript_t EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan);
|
||||
|
||||
uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan);
|
||||
//uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false);
|
||||
//uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
|
||||
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging = false);
|
||||
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging = false);
|
||||
|
||||
inline static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); }
|
||||
inline static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); }
|
||||
|
||||
// helper class to allow polymorphic behaviour for HeirXXX() functions in case of coins
|
||||
class CoinHelper {
|
||||
public:
|
||||
|
||||
static uint8_t getMyEval() { return EVAL_HEIR; }
|
||||
static int64_t addOwnerInputs(uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
|
||||
return AddNormalinputs(mtx, ownerPubkey, total, maxinputs);
|
||||
}
|
||||
|
||||
static CScript makeCreateOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {
|
||||
return CScript() << OP_RETURN << EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo);
|
||||
}
|
||||
static CScript makeAddOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return CScript() << OP_RETURN << EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan);
|
||||
}
|
||||
static CScript makeClaimOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return CScript() << OP_RETURN << EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan);
|
||||
}
|
||||
static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
return MakeCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey);
|
||||
}
|
||||
static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) {
|
||||
return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG);
|
||||
}
|
||||
/* static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) {
|
||||
return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG);
|
||||
} */
|
||||
static bool GetCoinsOrTokensCCaddress1of2(char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
struct CCcontract_info *cpHeir, heirC;
|
||||
cpHeir = CCinit(&heirC, EVAL_HEIR);
|
||||
return GetCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey);
|
||||
}
|
||||
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr)
|
||||
{
|
||||
uint8_t mypriv[32];
|
||||
Myprivkey(mypriv);
|
||||
CCaddr1of2set(cp, ownerPubkey, heirPubkey,mypriv, coinaddr);
|
||||
}
|
||||
};
|
||||
|
||||
// helper class to allow polymorphic behaviour for HeirXXX() functions in case of tokens
|
||||
class TokenHelper {
|
||||
public:
|
||||
static uint8_t getMyEval() { return EVAL_TOKENS; }
|
||||
static int64_t addOwnerInputs(uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
|
||||
struct CCcontract_info *cpHeir, heirC;
|
||||
cpHeir = CCinit(&heirC, EVAL_TOKENS);
|
||||
return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs);
|
||||
}
|
||||
|
||||
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {
|
||||
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_HEIRDATA, EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo)));
|
||||
}
|
||||
static CScript makeAddOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_HEIRDATA, EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan)));
|
||||
}
|
||||
static CScript makeClaimOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
|
||||
std::make_pair(OPRETID_HEIRDATA, EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan)));
|
||||
}
|
||||
|
||||
static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
return MakeTokensCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey);
|
||||
}
|
||||
static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) {
|
||||
return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); // yes EVAL_TOKENS
|
||||
}
|
||||
/* static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) {
|
||||
return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); // yes EVAL_TOKENS
|
||||
} */
|
||||
static bool GetCoinsOrTokensCCaddress1of2(char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
struct CCcontract_info *cpHeir, heirC;
|
||||
cpHeir = CCinit(&heirC, EVAL_HEIR);
|
||||
return GetTokensCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey);
|
||||
}
|
||||
|
||||
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) {
|
||||
|
||||
CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Small framework for vins and vouts validation implementing a variation of 'chain of responsibility' pattern:
|
||||
* It consists of two classes CInputValidationPlan and COutputValidationPlan which both are configured with an array of vectors of validators
|
||||
* (These validators are derived from the class CValidatorBase).
|
||||
*
|
||||
* A example of a validator may verify for a vout if its public key corresponds to the public key which is stored in opreturn.
|
||||
* Or, vin validator may check if this vin depicts correctly to the CC contract's address.
|
||||
*
|
||||
* For validating vins CInputValidator additionally is provided with an instance of a class derived from the CInputIdentifierBase class.
|
||||
* this identifier class allows to select identical vins (for example, normal vins or cc input vins) and apply validators from the corresponding vector to it.
|
||||
* Note: CInputValidator treats that at least one identified vin should be present, otherwise it returns eval->invalid() and false.
|
||||
*
|
||||
* For validating vouts COutputValidator is configured for each vector of validators with the vout index to which these validators are applied
|
||||
* (see constructors of both CInputValidator and COutputValidator)
|
||||
*/
|
||||
|
||||
/**
|
||||
* base class for all validators
|
||||
*/
|
||||
class CValidatorBase
|
||||
{
|
||||
public:
|
||||
CValidatorBase(CCcontract_info* cp) : m_cp(cp) {}
|
||||
virtual bool isVinValidator() const = 0;
|
||||
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const = 0;
|
||||
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const = 0;
|
||||
|
||||
protected:
|
||||
CCcontract_info * m_cp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for classes which identify vins as normal or cc inputs
|
||||
*/
|
||||
class CInputIdentifierBase
|
||||
{
|
||||
public:
|
||||
CInputIdentifierBase(CCcontract_info* cp) : m_cp(cp) {}
|
||||
virtual std::string inputName() const = 0;
|
||||
virtual bool identifyInput(CTxIn vin) const = 0;
|
||||
protected:
|
||||
CCcontract_info * m_cp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates an array containing rows of validators
|
||||
* Each row is a vector of validators (zero is possible) for validating vins or prev tx's vouts
|
||||
* this validation plan is used for validating tx inputs
|
||||
*/
|
||||
template <typename TValidatorBase>
|
||||
class CInputValidationPlan
|
||||
{
|
||||
using ValidatorsRow = std::vector<TValidatorBase*>;
|
||||
|
||||
public:
|
||||
|
||||
// Pushes a row of validators for validating a vin or vout
|
||||
// @param CInputIdentifierBase* pointer to class-identifier which determines several identical adjacent vins (like in schema "vin.0+: normal inputs")
|
||||
// @param pargs parameter pack of zero or more pointer to validator objects
|
||||
// Why pointers? because we store the base class in validators' row and then call its virtual functions
|
||||
template <typename TValidatorBaseX, typename... ARGS>
|
||||
void pushValidators(CInputIdentifierBase *identifier, ARGS*... pargs) // validators row passed as variadic arguments CValidatorX *val1, CValidatorY *val2 ...
|
||||
{
|
||||
ValidatorsRow vValidators({ (TValidatorBase*)pargs... });
|
||||
m_arrayValidators.push_back(std::make_pair(identifier, vValidators));
|
||||
}
|
||||
|
||||
// validate tx inputs and corresponding prev tx vouts
|
||||
bool validate(const CTransaction& tx, Eval* eval)
|
||||
{
|
||||
std::string message = "<empty>";
|
||||
//std::cerr << "CInputValidationPlan::validate() starting vins validation..." << std::endl;
|
||||
|
||||
int32_t ival = 0;
|
||||
int32_t iv = 0;
|
||||
int32_t numv = tx.vin.size();
|
||||
int32_t numValidators = m_arrayValidators.size();
|
||||
|
||||
// run over vins:
|
||||
while (iv < numv && ival < numValidators) {
|
||||
|
||||
int32_t identifiedCount = 0;
|
||||
CInputIdentifierBase *identifier = m_arrayValidators[ival].first;
|
||||
// check if this is 'our' input:
|
||||
while (iv < numv && identifier->identifyInput(tx.vin[iv])) {
|
||||
|
||||
// get prev tx:
|
||||
CTransaction prevTx, *pPrevTxOrNull = NULL;
|
||||
uint256 hashBlock;
|
||||
|
||||
if (!eval->GetTxUnconfirmed(tx.vin[iv].prevout.hash, prevTx, hashBlock)) {
|
||||
std::ostringstream stream;
|
||||
stream << "can't find vinTx for vin=" << iv << ".";
|
||||
return eval->Invalid(stream.str().c_str());
|
||||
}
|
||||
pPrevTxOrNull = &prevTx; // TODO: get prev tx only if it required (i.e. if vout validators are present)
|
||||
|
||||
// exec 'validators' from validator row of ival index, for tx.vin[iv]
|
||||
if (!execValidatorsInRow(&tx, pPrevTxOrNull, iv, ival, message)) {
|
||||
std::ostringstream stream;
|
||||
stream << "invalid tx vin[" << iv << "]:" << message;
|
||||
return eval->Invalid(stream.str().c_str()); // ... if not, return 'invalid'
|
||||
}
|
||||
|
||||
identifiedCount++; // how many vins we identified
|
||||
iv++; // advance to the next vin
|
||||
}
|
||||
|
||||
// CInputValidationPlan treats that there must be at least one identified vin for configured validators' row
|
||||
// like in 'vin.0: normal input'
|
||||
if (identifiedCount == 0) {
|
||||
std::ostringstream stream;
|
||||
stream << "can't find required vins for " << identifier->inputName() << ".";
|
||||
return eval->Invalid(stream.str().c_str());
|
||||
}
|
||||
|
||||
ival++; // advance to the next validator row
|
||||
// and it will try the same vin with the new CInputIdentifierBase and validators row
|
||||
}
|
||||
|
||||
// validation is successful if all validators have been used (i.e. ival = numValidators)
|
||||
if (ival < numValidators) {
|
||||
std::cerr << "CInputValidationPlan::validate() incorrect tx" << " ival=" << ival << " numValidators=" << numValidators << std::endl;
|
||||
return eval->Invalid("incorrect tx structure: not all required vins are present.");
|
||||
}
|
||||
|
||||
//std::cerr << "CInputValidationPlan::validate() returns with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Executes validators from the requested row of validators (selected by iValidators) for selected vin or vout (selected by iv)
|
||||
bool execValidatorsInRow(const CTransaction* pTx, const CTransaction* pPrevTx, int32_t iv, int32_t ival, std::string& refMessage) const
|
||||
{
|
||||
// check boundaries:
|
||||
if (ival < 0 || ival >= m_arrayValidators.size()) {
|
||||
std::cerr << "CInputValidationPlan::execValidatorsInRow() internal error: incorrect param ival=" << ival << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param ival index";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iv < 0 || iv >= pTx->vin.size()) {
|
||||
std::cerr << "CInputValidationPlan::execValidatorsInRow() internal error: incorrect param iv=" << iv << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param iv index";
|
||||
return false;
|
||||
}
|
||||
|
||||
// get requested row of validators:
|
||||
ValidatorsRow vValidators = m_arrayValidators[ival].second;
|
||||
|
||||
//std::cerr << "CInputValidationPlan::execValidatorsInRow() calling validators" << " for vin iv=" << iv << " ival=" << ival << std::endl;
|
||||
|
||||
for (auto v : vValidators) {
|
||||
bool result;
|
||||
|
||||
if (v->isVinValidator())
|
||||
// validate this vin and previous vout:
|
||||
result = v->validateVin(pTx->vin[iv], pPrevTx->vout, pTx->vin[iv].prevout.n, refMessage);
|
||||
else
|
||||
// if it is vout validator pass the previous tx vout:
|
||||
result = v->validateVout( pPrevTx->vout[pTx->vin[iv].prevout.n], pTx->vin[iv].prevout.n, refMessage);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return true; // validation OK
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
//std::map<CInputIdentifierBase*, ValidatorsRow> m_arrayValidators;
|
||||
std::vector< std::pair<CInputIdentifierBase*, ValidatorsRow> > m_arrayValidators;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates an array containing rows of validators
|
||||
* Each row is a vector of validators (zero is possible) for validating vouts
|
||||
* this validation plan is used for validating tx outputs
|
||||
*/
|
||||
template <typename TValidatorBase>
|
||||
class COutputValidationPlan
|
||||
{
|
||||
using ValidatorsRow = std::vector<TValidatorBase*>;
|
||||
|
||||
public:
|
||||
// Pushes a row of validators for validating a vout
|
||||
// @param ivout index to vout to validate
|
||||
// @param pargs parameter pack of zero or more pointer to validator objects
|
||||
// Why pointers? because we store base class and call its virtual functions
|
||||
|
||||
template <typename TValidatorBaseX, typename... ARGS>
|
||||
void pushValidators(int32_t ivout, ARGS*... pargs) // validators row passed as variadic arguments CValidatorX *val1, CValidatorY *val2 ...
|
||||
{
|
||||
ValidatorsRow vValidators({ (TValidatorBase*)pargs... });
|
||||
m_arrayValidators.push_back(std::make_pair(ivout, vValidators));
|
||||
}
|
||||
|
||||
// validate tx outputs
|
||||
bool validate(const CTransaction& tx, Eval* eval)
|
||||
{
|
||||
std::string message = "<empty>";
|
||||
//std::cerr << "COutputValidationPlan::validateOutputs() starting vouts validation..." << std::endl;
|
||||
|
||||
int32_t ival = 0;
|
||||
int32_t numVouts = tx.vout.size();
|
||||
int32_t numValidators = m_arrayValidators.size();
|
||||
|
||||
// run over vouts:
|
||||
while (ival < numValidators) {
|
||||
|
||||
int32_t ivout = m_arrayValidators[ival].first;
|
||||
if (ivout >= numVouts) {
|
||||
std::cerr << "COutputValidationPlan::validate() incorrect tx" << "for ival=" << ival << " in tx.vout no such ivout=" << ivout << std::endl;
|
||||
return eval->Invalid("incorrect tx structure: not all required vouts are present.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// exec 'validators' from validator row of ival index, for tx.vout[ivout]
|
||||
if (!execValidatorsInRow(&tx, ivout, ival, message)) {
|
||||
std::ostringstream stream;
|
||||
stream << "invalid tx vout[" << ivout << "]:" << message;
|
||||
return eval->Invalid(stream.str().c_str()); // ... if not, return 'invalid'
|
||||
}
|
||||
}
|
||||
ival++; // advance to the next vout
|
||||
}
|
||||
//std::cerr << "COutputValidationPlan::validate() returns with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Executes validators from the requested row of validators (selected by iValidators) for selected vin or vout (selected by iv)
|
||||
bool execValidatorsInRow(const CTransaction* pTx, int32_t iv, int32_t ival, std::string& refMessage) const
|
||||
{
|
||||
// check boundaries:
|
||||
if (ival < 0 || ival >= m_arrayValidators.size()) {
|
||||
std::cerr << "COutputValidationPlan::execValidatorsInRow() internal error: incorrect param ival=" << ival << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param ival index";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iv < 0 || iv >= pTx->vout.size()) {
|
||||
std::cerr << "COutputValidationPlan::execValidatorsInRow() internal error: incorrect param iv=" << iv << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param iv index";
|
||||
return false;
|
||||
}
|
||||
|
||||
// get requested row of validators:
|
||||
ValidatorsRow vValidators = m_arrayValidators[ival].second;
|
||||
|
||||
//std::cerr << "COutputValidationPlan::execRow() calling validators" << " for vout iv=" << iv << " ival=" << ival << std::endl;
|
||||
|
||||
for (auto v : vValidators) {
|
||||
|
||||
if (!v->isVinValidator()) {
|
||||
// if this is a 'in' validation plan then pass the previous tx vout:
|
||||
bool result = v->validateVout(pTx->vout[iv], iv, refMessage);
|
||||
if (!result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return true; // validation OK
|
||||
}
|
||||
|
||||
private:
|
||||
//std::map<int32_t, ValidatorsRow> m_mapValidators;
|
||||
std::vector< std::pair<int32_t, ValidatorsRow> > m_arrayValidators;
|
||||
|
||||
};
|
||||
|
||||
class CNormalInputIdentifier : CInputIdentifierBase {
|
||||
public:
|
||||
CNormalInputIdentifier(CCcontract_info* cp) : CInputIdentifierBase(cp) {}
|
||||
virtual std::string inputName() const { return std::string("normal input"); }
|
||||
virtual bool identifyInput(CTxIn vin) const {
|
||||
return !IsCCInput(vin.scriptSig);
|
||||
}
|
||||
};
|
||||
|
||||
class CCCInputIdentifier : CInputIdentifierBase {
|
||||
public:
|
||||
CCCInputIdentifier(CCcontract_info* cp) : CInputIdentifierBase(cp) {}
|
||||
virtual std::string inputName() const { return std::string("CC input"); }
|
||||
virtual bool identifyInput(CTxIn vin) const {
|
||||
return IsCCInput(vin.scriptSig);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Validates 1of2address for vout (may be used for either this or prev tx)
|
||||
*/
|
||||
template <class Helper> class CCC1of2AddressValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CCC1of2AddressValidator(CCcontract_info* cp, CScript opRetScript, std::string customMessage = "") :
|
||||
m_fundingOpretScript(opRetScript), m_customMessage(customMessage), CValidatorBase(cp) {}
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
|
||||
{
|
||||
//std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl;
|
||||
CPubKey ownerPubkey, heirPubkey;
|
||||
int64_t inactivityTime;
|
||||
std::string heirName, memo;
|
||||
uint256 tokenid;
|
||||
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
|
||||
if (funcId == 0) {
|
||||
message = m_customMessage + std::string(" invalid opreturn format");
|
||||
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
char shouldBeAddr[65], ccAddr[65];
|
||||
|
||||
//GetCCaddress1of2(m_cp, shouldBeAddr, ownerPubkey, heirPubkey);
|
||||
Helper::GetCoinsOrTokensCCaddress1of2(shouldBeAddr, ownerPubkey, heirPubkey);
|
||||
|
||||
if (vout.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
if (Getscriptaddress(ccAddr, vout.scriptPubKey) && strcmp(shouldBeAddr, ccAddr) == 0) {
|
||||
//std::cerr << "CCC1of2AddressValidator::validateVout() exits with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
message = m_customMessage + std::string(" incorrect heir funding address: incorrect pubkey(s)");
|
||||
}
|
||||
}
|
||||
else {
|
||||
message = m_customMessage + std::string(" incorrect heir funding address: not a 1of2addr");
|
||||
}
|
||||
|
||||
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
|
||||
return false;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return false; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
std::string m_customMessage;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Validates if this is vout to owner or heir from opret (funding or change)
|
||||
*/
|
||||
template <class Helper> class CMyPubkeyVoutValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CMyPubkeyVoutValidator(CCcontract_info* cp, CScript opRetScript, bool checkNormals)
|
||||
: m_fundingOpretScript(opRetScript), m_checkNormals(checkNormals), CValidatorBase(cp) { }
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
|
||||
{
|
||||
//std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl;
|
||||
|
||||
CPubKey ownerPubkey, heirPubkey;
|
||||
int64_t inactivityTime;
|
||||
std::string heirName, memo;
|
||||
uint256 tokenid;
|
||||
|
||||
///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl;
|
||||
|
||||
// get both pubkeys:
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
|
||||
if (funcId == 0) {
|
||||
message = std::string("invalid opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
CScript ownerScript;
|
||||
CScript heirScript;
|
||||
if (m_checkNormals) { //not used, incorrect check, too strict
|
||||
ownerScript = CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey;
|
||||
heirScript = CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey;
|
||||
std::cerr << "CMyPubkeyVoutValidator::validateVout() vout.scriptPubKey=" << vout.scriptPubKey.ToString() << " makeUserVout(coin,owner)=" << CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey.ToString() << " makeUserVout(coin,heir)=" << CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey.ToString() << std::endl;
|
||||
}
|
||||
else {
|
||||
ownerScript = Helper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey;
|
||||
heirScript = Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey;
|
||||
std::cerr << "CMyPubkeyVoutValidator::validateVout() vout.scriptPubKey=" << vout.scriptPubKey.ToString() << " makeUserVout(owner)=" << Helper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey.ToString() << " makeUserVout(heir)=" << Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey.ToString() << std::endl;
|
||||
}
|
||||
|
||||
// recreate scriptPubKey for owner and heir and compare it with that of the vout to check:
|
||||
if (vout.scriptPubKey == ownerScript || vout.scriptPubKey == heirScript) {
|
||||
// this is vout to owner or heir addr:
|
||||
//std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with false (not the owner's or heir's addresses)" << std::endl;
|
||||
message = std::string("invalid pubkey");
|
||||
return false;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
//uint256 m_lasttxid;
|
||||
bool m_checkNormals;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the user is the heir and the heir is allowed to spend (duration > inactivityTime)
|
||||
*/
|
||||
template <class Helper> class CHeirSpendValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CHeirSpendValidator(CCcontract_info* cp, CScript opRetScript, uint256 latesttxid, uint8_t isHeirSpendingBegan)
|
||||
: m_fundingOpretScript(opRetScript), m_latesttxid(latesttxid), m_isHeirSpendingBegan(isHeirSpendingBegan), CValidatorBase(cp) {}
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
|
||||
{
|
||||
//std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl;
|
||||
|
||||
CPubKey ownerPubkey, heirPubkey;
|
||||
int64_t inactivityTime;
|
||||
std::string heirName, memo;
|
||||
uint256 tokenid;
|
||||
|
||||
// get heir pubkey:
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
|
||||
if (funcId == 0) {
|
||||
message = std::string("invalid opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t numblocks;
|
||||
int64_t durationSec = CCduration(numblocks, m_latesttxid);
|
||||
|
||||
// recreate scriptPubKey for heir and compare it with that of the vout:
|
||||
if (vout.scriptPubKey == Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey) {
|
||||
// this is the heir is trying to spend
|
||||
if (!m_isHeirSpendingBegan && durationSec <= inactivityTime) {
|
||||
message = "heir is not allowed yet to spend funds";
|
||||
std::cerr << "CHeirSpendValidator::validateVout() heir is not allowed yet to spend funds" << std::endl;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// heir is allowed to spend
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "CHeirSpendValidator::validateVout() exits with true" << std::endl;
|
||||
|
||||
// this is not heir:
|
||||
return true;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
uint256 m_latesttxid;
|
||||
uint8_t m_isHeirSpendingBegan;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates this opreturn and compares it with the opreturn from the previous tx
|
||||
*/
|
||||
template <class Helper> class COpRetValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
COpRetValidator(CCcontract_info* cp, CScript opret)
|
||||
: m_fundingOpretScript(opret), CValidatorBase(cp) {}
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
|
||||
{
|
||||
//std::cerr << "COpRetValidator::validateVout() entered" << std::endl;
|
||||
|
||||
uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid;
|
||||
uint8_t dummyIsHeirSpendingBegan;
|
||||
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true);
|
||||
if (funcId == 0) {
|
||||
message = std::string("invalid opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t initialFuncId = DecodeHeirEitherOpRet(m_fundingOpretScript, initialTokenid, dummyTxid, dummyIsHeirSpendingBegan, true);
|
||||
if (initialFuncId == 0) {
|
||||
message = std::string("invalid initial tx opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
// validation rules:
|
||||
if (!isMyFuncId(funcId)) {
|
||||
message = std::string("invalid funcid in opret");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeid(Helper) == typeid(TokenHelper)) {
|
||||
if (tokenid != initialTokenid) {
|
||||
message = std::string("invalid tokenid in opret");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* marker spending prevention validator,
|
||||
* returns false if for tx with funcid=F vout.1 is being tried to spend
|
||||
*/
|
||||
template <class Helper> class CMarkerValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CMarkerValidator(CCcontract_info* cp)
|
||||
: CValidatorBase(cp) { }
|
||||
|
||||
virtual bool isVinValidator() const { return true; } // this is vin validator
|
||||
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; }
|
||||
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const {
|
||||
|
||||
uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid;
|
||||
uint8_t dummyIsHeirSpendingBegan;
|
||||
|
||||
//std::cerr << "CMarkerValidator::validateVin() prevVout.size()=" << prevVout.size() << " prevN=" << prevN << std::endl;
|
||||
if (prevVout.size() > 0) {
|
||||
|
||||
// get funcId for prev tx:
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(prevVout[prevVout.size()-1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true);
|
||||
|
||||
//std::cerr << "CMarkerValidator::validateVin() funcId=" << (funcId?funcId:' ') << std::endl;
|
||||
|
||||
if (funcId == 'F' && prevN == 1) { // do not allow to spend 'F' marker's vout
|
||||
message = std::string("spending marker not allowed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//std::cerr << "CMarkerValidator::validateVin() exits with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* empty validator always returns true
|
||||
*/
|
||||
template <class Helper> class CNullValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CNullValidator(CCcontract_info* cp)
|
||||
: CValidatorBase(cp) { }
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; }
|
||||
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -19,77 +19,366 @@
|
||||
#include "crosschain.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "cc/CCinclude.h"
|
||||
#include <openssl/sha.h>
|
||||
|
||||
/*
|
||||
* CC Eval method for import coin.
|
||||
*
|
||||
* This method should control every parameter of the ImportCoin transaction, since it has no signature
|
||||
* to protect it from malleability.
|
||||
|
||||
##### 0xffffffff is a special CCid for single chain/dual daemon imports
|
||||
*/
|
||||
#include "key_io.h"
|
||||
#define CODA_BURN_ADDRESS "KPrrRoPfHOnNpZZQ6laHXdQDkSQDkVHaN0V+LizLlHxz7NaA59sBAAAA"
|
||||
|
||||
extern std::string ASSETCHAINS_SELFIMPORT;
|
||||
extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT;
|
||||
extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
|
||||
int32_t GetSelfimportProof(std::string source,CMutableTransaction &mtx,CScript &scriptPubKey,TxProof &proof,uint64_t burnAmount,std::vector<uint8_t> rawtx,uint256 txid,std::vector<uint8_t> rawproof) // find burnTx with hash from "other" daemon
|
||||
// utilities from gateways.cpp
|
||||
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids);
|
||||
uint256 GatewaysReverseScan(uint256 &txid, int32_t height, uint256 reforacletxid, uint256 batontxid);
|
||||
int32_t GatewaysCointxidExists(struct CCcontract_info *cp, uint256 cointxid);
|
||||
uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector<CPubKey> &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype);
|
||||
char *nonportable_path(char *str);
|
||||
char *portable_path(char *str);
|
||||
void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep);
|
||||
void *filestr(long *allocsizep,char *_fname);
|
||||
|
||||
// ac_import=chain support:
|
||||
// encode opret for gateways import
|
||||
CScript EncodeImportTxOpRet(uint32_t targetCCid, std::string coin, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
MerkleBranch newBranch; CMutableTransaction tmpmtx; CTransaction tx,vintx; uint256 blockHash; char destaddr[64],pkaddr[64];
|
||||
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_nextheight());
|
||||
if ( source == "BEAM" )
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint256 bindtxid, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
CScript EncodeCodaImportTxOpRet(uint32_t targetCCid, std::string coin, std::string burntx, uint256 bindtxid, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << burntx << bindtxid << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2,char const *arg3,char const *arg4,char const *arg5)
|
||||
{
|
||||
char cmdstr[5000],fname[256],*jsonstr;
|
||||
long fsize;
|
||||
cJSON *retjson=NULL;
|
||||
|
||||
sprintf(fname,"/tmp/coda.%s",arg0);
|
||||
sprintf(cmdstr,"coda.exe client %s %s %s %s %s %s > %s 2>&1",arg0,arg1,arg2,arg3,arg4,arg5,fname);
|
||||
*retstr = 0;
|
||||
if (system(cmdstr)<0) return (retjson);
|
||||
if ( (jsonstr=(char *)filestr(&fsize,fname)) != 0 )
|
||||
{
|
||||
if ( ASSETCHAINS_BEAMPORT == 0 )
|
||||
return(-1);
|
||||
// confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn
|
||||
// return(0);
|
||||
jsonstr[strlen(jsonstr)-1]='\0';
|
||||
if ( (strncmp(jsonstr,"Merkle List of transactions:",28)!=0) || (retjson= cJSON_Parse(jsonstr+29)) == 0)
|
||||
*retstr=jsonstr;
|
||||
else free(jsonstr);
|
||||
}
|
||||
else if ( source == "CODA" )
|
||||
return(retjson);
|
||||
}
|
||||
|
||||
bool ImportCoinGatewaysVerify(CTransaction oracletx, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vector<uint8_t>proof, uint256 merkleroot)
|
||||
{
|
||||
std::vector<uint256> txids;
|
||||
uint256 proofroot;
|
||||
std::string name, description, format;
|
||||
int32_t i, numvouts;
|
||||
|
||||
if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin)
|
||||
{
|
||||
if ( ASSETCHAINS_CODAPORT == 0 )
|
||||
return(-1);
|
||||
// confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn
|
||||
// return(0);
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in trusted merkleroot" << std::endl);
|
||||
return true;
|
||||
}
|
||||
|
||||
// make import tx with burntx and its proof of existence
|
||||
// std::string MakeGatewaysImportTx(uint64_t txfee, uint256 oracletxid, int32_t height, std::string refcoin, std::vector<uint8_t> proof, std::string rawburntx, int32_t ivout, uint256 burntxid,std::string destaddr)
|
||||
// {
|
||||
// CMutableTransaction burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
// CTransaction oracletx,regtx; CPubKey regpk;
|
||||
// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts;
|
||||
// std::string name,desc,format; std::vector<CTxOut> vouts;
|
||||
// std::vector<CPubKey> pubkeys; std::vector<uint256>txids;
|
||||
// char markeraddr[64]; int64_t datafee;
|
||||
// std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
|
||||
// if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx))
|
||||
// return std::string("");
|
||||
// CAmount amount = GetCoinImportValue(burntx); // equal to int64_t
|
||||
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl);
|
||||
// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C')
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// if (name!=refcoin || format!="Ihh")
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// CCtxidaddr(markeraddr,oracletxid);
|
||||
// SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
// for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
// {
|
||||
// txid = it->first.txhash;
|
||||
// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0
|
||||
// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid )
|
||||
// {
|
||||
// pubkeys.push_back(regpk);
|
||||
// n++;
|
||||
// }
|
||||
// }
|
||||
// merkleroot = zeroid;
|
||||
// for (i = m = 0; i < n; i++)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl);
|
||||
// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
|
||||
// {
|
||||
// if (merkleroot == zeroid)
|
||||
// merkleroot = mhash, m = 1;
|
||||
// else if (mhash == merkleroot)
|
||||
// m ++;
|
||||
// txids.push_back(txid);
|
||||
// }
|
||||
// }
|
||||
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl);
|
||||
// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
|
||||
// return("");
|
||||
// }
|
||||
// proofroot = BitcoinGetProofMerkleRoot(proof, txids);
|
||||
// if (proofroot != merkleroot)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// // check the burntxid is in the proof:
|
||||
// if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid proof for this burntxid=" << burntxid.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// burntx.vout.push_back(MakeBurnOutput(amount,0xffffffff,refcoin,vouts,proof,oracletxid,height));
|
||||
// std::vector<uint256> leaftxids;
|
||||
// BitcoinGetProofMerkleRoot(proof, leaftxids);
|
||||
// MerkleBranch newBranch(0, leaftxids);
|
||||
// TxProof txProof = std::make_pair(burntxid, newBranch);
|
||||
// CTxDestination dest = DecodeDestination(destaddr.c_str());
|
||||
// CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
// vouts.push_back(CTxOut(amount,scriptPubKey));
|
||||
// return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts)));
|
||||
// }
|
||||
|
||||
// makes source tx for self import tx
|
||||
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx)
|
||||
{
|
||||
const int64_t txfee = 10000;
|
||||
int64_t inputs, change;
|
||||
CPubKey myPubKey = Mypubkey();
|
||||
struct CCcontract_info *cpDummy, C;
|
||||
|
||||
cpDummy = CCinit(&C, EVAL_TOKENS);
|
||||
|
||||
mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
|
||||
if( (inputs = AddNormalinputs(mtx, myPubKey, txfee, 4)) == 0 ) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx: cannot find normal imputs for txfee" << std::endl);
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
mtx.vout.push_back(CTxOut(txfee, scriptPubKey));
|
||||
change = inputs - txfee;
|
||||
if( change != 0 )
|
||||
mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG));
|
||||
|
||||
//make opret with amount:
|
||||
return FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount));
|
||||
}
|
||||
|
||||
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
|
||||
int32_t CheckVin0PubKey(const CTransaction &sourcetx)
|
||||
{
|
||||
CTransaction vintx;
|
||||
uint256 blockHash;
|
||||
char destaddr[64], pkaddr[64];
|
||||
|
||||
if( !myGetTransaction(sourcetx.vin[0].prevout.hash, vintx, blockHash) ) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() could not load vintx" << sourcetx.vin[0].prevout.hash.GetHex() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
if( sourcetx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[0].prevout.n].scriptPubKey) != 0 )
|
||||
{
|
||||
pubkey2addr(pkaddr, ASSETCHAINS_OVERRIDE_PUBKEY33);
|
||||
if (strcmp(pkaddr, destaddr) == 0) {
|
||||
return(0);
|
||||
}
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() mismatched vin0[prevout.n=" << sourcetx.vin[0].prevout.n << "] -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ac_import=PUBKEY support:
|
||||
// prepare a tx for creating import tx and quasi-burn tx
|
||||
int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount) // find burnTx with hash from "other" daemon
|
||||
{
|
||||
MerkleBranch newBranch;
|
||||
CMutableTransaction tmpmtx;
|
||||
CTransaction sourcetx;
|
||||
|
||||
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
|
||||
if (!E_UNMARSHAL(ParseHex(rawsourcetx), ss >> sourcetx)) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: could not unmarshal source tx" << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (sourcetx.vout.size() == 0) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: vout size is 0" << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ivout < 0) { // "ivout < 0" means "find"
|
||||
// try to find vout
|
||||
CPubKey myPubkey = Mypubkey();
|
||||
ivout = 0;
|
||||
// skip change:
|
||||
if (sourcetx.vout[ivout].scriptPubKey == (CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG))
|
||||
ivout++;
|
||||
}
|
||||
|
||||
if (ivout >= sourcetx.vout.size()) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: needed vout not found" << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl);
|
||||
|
||||
scriptPubKey = sourcetx.vout[ivout].scriptPubKey;
|
||||
|
||||
//mtx is template for import tx
|
||||
mtx = sourcetx;
|
||||
mtx.fOverwintered = tmpmtx.fOverwintered;
|
||||
|
||||
//malleability fix for burn tx:
|
||||
//mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
|
||||
mtx.nExpiryHeight = sourcetx.nExpiryHeight;
|
||||
|
||||
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
|
||||
mtx.nVersion = tmpmtx.nVersion;
|
||||
mtx.vout.clear();
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].nValue = burnAmount;
|
||||
mtx.vout[0].scriptPubKey = scriptPubKey;
|
||||
|
||||
// not sure we need this now as we create sourcetx ourselves:
|
||||
if (sourcetx.GetHash() != sourcetxid) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// check ac_pubkey:
|
||||
if (CheckVin0PubKey(sourcetx) < 0) {
|
||||
return -1;
|
||||
}
|
||||
proof = std::make_pair(sourcetxid, newBranch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make import tx with burntx and dual daemon
|
||||
std::string MakeCodaImportTx(uint64_t txfee, std::string receipt, std::string srcaddr, std::vector<CTxOut> vouts)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()),burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint256 codaburntxid; std::vector<unsigned char> dummyproof;
|
||||
int32_t i,numvouts,n,m; std::string coin,error; struct CCcontract_info *cp, C;
|
||||
cJSON *result,*tmp,*tmp1; unsigned char hash[SHA256_DIGEST_LENGTH+1];
|
||||
char out[SHA256_DIGEST_LENGTH*2+1],*retstr,*destaddr,*receiver; TxProof txProof; uint64_t amount;
|
||||
|
||||
cp = CCinit(&C, EVAL_GATEWAYS);
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
SHA256_CTX sha256;
|
||||
SHA256_Init(&sha256);
|
||||
SHA256_Update(&sha256, receipt.c_str(), receipt.size());
|
||||
SHA256_Final(hash, &sha256);
|
||||
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
|
||||
{
|
||||
sprintf(out + (i * 2), "%02x", hash[i]);
|
||||
}
|
||||
out[65]='\0';
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: hash=" << out << std::endl);
|
||||
codaburntxid.SetHex(out);
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receipt=" << receipt << " codaburntxid=" << codaburntxid.GetHex().data() << " amount=" << (double)amount / COIN << std::endl);
|
||||
result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),"");
|
||||
if (result==0)
|
||||
{
|
||||
if (retstr!=0)
|
||||
{
|
||||
CCerror=std::string("CodaRPC: ")+retstr;
|
||||
free(retstr);
|
||||
}
|
||||
return("");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !E_UNMARSHAL(rawtx, ss >> tx) )
|
||||
return(-1);
|
||||
scriptPubKey = tx.vout[0].scriptPubKey;
|
||||
mtx = tx;
|
||||
mtx.fOverwintered = tmpmtx.fOverwintered;
|
||||
mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
|
||||
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
|
||||
mtx.nVersion = tmpmtx.nVersion;
|
||||
mtx.vout.clear();
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].nValue = burnAmount;
|
||||
mtx.vout[0].scriptPubKey = scriptPubKey;
|
||||
if ( tx.GetHash() != txid )
|
||||
return(-1);
|
||||
if ( source == "PUBKEY" )
|
||||
if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))!=0 && (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))!=0 &&
|
||||
(receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))!=0 && (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))!=0)
|
||||
{
|
||||
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
|
||||
if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,blockHash) == 0 )
|
||||
return(-1);
|
||||
if ( tx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr,vintx.vout[tx.vin[0].prevout.n].scriptPubKey) != 0 )
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receiver=" << receiver << " destaddr=" << destaddr << " amount=" << amount << std::endl);
|
||||
if (strcmp(receiver,CODA_BURN_ADDRESS)!=0)
|
||||
{
|
||||
pubkey2addr(pkaddr,ASSETCHAINS_OVERRIDE_PUBKEY33);
|
||||
if ( strcmp(pkaddr,destaddr) == 0 )
|
||||
{
|
||||
proof = std::make_pair(txid,newBranch);
|
||||
return(0);
|
||||
}
|
||||
fprintf(stderr,"mismatched vin0[%d] -> %s vs %s\n",tx.vin[0].prevout.n,destaddr,pkaddr);
|
||||
CCerror="MakeCodaImportTx: invalid burn address, coins do not go to predefined burn address - ";
|
||||
CCerror+=CODA_BURN_ADDRESS;
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
|
||||
free(result);
|
||||
return("");
|
||||
}
|
||||
CTxDestination dest = DecodeDestination(destaddr);
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
if (vouts[0]!=CTxOut(amount*COIN,scriptPubKey))
|
||||
{
|
||||
CCerror="MakeCodaImportTx: invalid destination address, burnTx memo!=importTx destination";
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
|
||||
free(result);
|
||||
return("");
|
||||
}
|
||||
if (amount*COIN!=vouts[0].nValue)
|
||||
{
|
||||
CCerror="MakeCodaImportTx: invalid amount, burnTx amount!=importTx amount";
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
|
||||
free(result);
|
||||
return("");
|
||||
}
|
||||
burntx.vin.push_back(CTxIn(codaburntxid,0,CScript()));
|
||||
burntx.vout.push_back(MakeBurnOutput(amount*COIN,0xffffffff,"CODA",vouts,dummyproof,srcaddr,receipt));
|
||||
return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof,burntx,vouts)));
|
||||
}
|
||||
else if ( source == ASSETCHAINS_SELFIMPORT )
|
||||
else
|
||||
{
|
||||
// source is external coin is the assetchains symbol in the burnTx OP_RETURN
|
||||
// burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent
|
||||
CCerror="MakeCodaImportTx: invalid Coda burn tx";
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
|
||||
free(result);
|
||||
return("");
|
||||
}
|
||||
|
||||
}
|
||||
return(-1);
|
||||
CCerror="MakeCodaImportTx: error fetching Coda tx";
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl);
|
||||
free(result);
|
||||
return("");
|
||||
}
|
||||
|
||||
// use proof from the above functions to validate the import
|
||||
@@ -100,31 +389,202 @@ int32_t CheckBEAMimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int32_t CheckCODAimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
|
||||
int32_t CheckCODAimport(CTransaction importTx,CTransaction burnTx,std::vector<CTxOut> payouts,std::string srcaddr,std::string receipt)
|
||||
{
|
||||
cJSON *result,*tmp,*tmp1; char *retstr,out[SHA256_DIGEST_LENGTH*2+1]; unsigned char hash[SHA256_DIGEST_LENGTH+1]; int i,n,m;
|
||||
SHA256_CTX sha256; uint256 codaburntxid; char *destaddr,*receiver; uint64_t amount;
|
||||
|
||||
// check with dual-CODA daemon via ASSETCHAINS_CODAPORT for validity of burnTx
|
||||
return(-1);
|
||||
SHA256_Init(&sha256);
|
||||
SHA256_Update(&sha256, receipt.c_str(), receipt.size());
|
||||
SHA256_Final(hash, &sha256);
|
||||
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
|
||||
{
|
||||
sprintf(out + (i * 2), "%02x", hash[i]);
|
||||
}
|
||||
out[65]='\0';
|
||||
codaburntxid.SetHex(out);
|
||||
result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),"");
|
||||
if (result==0)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CodaRPC error: " << retstr << std::endl);
|
||||
free(retstr);
|
||||
return (-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))==0 || (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))==0 ||
|
||||
(receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))==0 || (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))==0)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid Coda burn tx" << jprint(result,1) << std::endl);
|
||||
free(result);
|
||||
return (-1);
|
||||
}
|
||||
CTxDestination dest = DecodeDestination(destaddr);
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
if (payouts[0]!=CTxOut(amount*COIN,scriptPubKey));
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Destination address in burn tx does not match destination in import tx" << std::endl);
|
||||
free(result);
|
||||
return (-1);
|
||||
}
|
||||
if (strcmp(receiver,CODA_BURN_ADDRESS)!=0)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid burn address " << jstr(tmp1,(char *)"receiver") << std::endl);
|
||||
free(result);
|
||||
return (-1);
|
||||
}
|
||||
if (amount*COIN!=payouts[0].nValue)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Burn amount and import amount not matching, " << j64bits(tmp,(char *)"amount") << " - " << payouts[0].nValue/COIN << std::endl);
|
||||
free(result);
|
||||
return (-1);
|
||||
}
|
||||
if (burnTx.vin[0].prevout.hash!=codaburntxid || importTx.vin[0].prevout.hash!=burnTx.GetHash())
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid import/burn tx vin" << std::endl);
|
||||
free(result);
|
||||
return (-1);
|
||||
}
|
||||
free(result);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t CheckGATEWAYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
|
||||
int32_t CheckGATEWAYimport(CTransaction importTx,CTransaction burnTx,std::string refcoin,std::vector<uint8_t> proof,
|
||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub)
|
||||
{
|
||||
// CTransaction oracletx,regtx; CPubKey regpk;
|
||||
// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts;
|
||||
// std::string name,desc,format; std::vector<CTxOut> vouts;
|
||||
// std::vector<CPubKey> pubkeys; std::vector<uint256>txids;
|
||||
// char markeraddr[64]; int64_t datafee;
|
||||
// std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
// ASSETCHAINS_SELFIMPORT is coin
|
||||
// check for valid burn from external coin blockchain and if valid return(0);
|
||||
return(-1);
|
||||
// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C')
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// if (name!=refcoin || format!="Ihh")
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// CCtxidaddr(markeraddr,oracletxid);
|
||||
// SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
// for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
// {
|
||||
// txid = it->first.txhash;
|
||||
// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0
|
||||
// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid )
|
||||
// {
|
||||
// pubkeys.push_back(regpk);
|
||||
// n++;
|
||||
// }
|
||||
// }
|
||||
// merkleroot = zeroid;
|
||||
// for (i = m = 0; i < n; i++)
|
||||
// {
|
||||
// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
|
||||
// {
|
||||
// if (merkleroot == zeroid)
|
||||
// merkleroot = mhash, m = 1;
|
||||
// else if (mhash == merkleroot)
|
||||
// m ++;
|
||||
// txids.push_back(txid);
|
||||
// }
|
||||
// }
|
||||
// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
|
||||
// return(-1);
|
||||
// }
|
||||
// proofroot = BitcoinGetProofMerkleRoot(proof, txids);
|
||||
// if (proofroot != merkleroot)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// // check the burntxid is in the proof:
|
||||
// if (std::find(txids.begin(), txids.end(), burnTx.GetHash()) == txids.end()) {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid proof for this burntxid=" << burnTx.GetHash().GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t CheckPUBKEYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
|
||||
{
|
||||
// if burnTx has ASSETCHAINS_PUBKEY vin, it is valid return(0);
|
||||
fprintf(stderr,"proof txid.%s\n",proof.first.GetHex().c_str());
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "proof txid=" << proof.first.GetHex() << std::endl);
|
||||
|
||||
uint256 sourcetxid = proof.first, hashBlock;
|
||||
CTransaction sourcetx;
|
||||
|
||||
if (!myGetTransaction(sourcetxid, sourcetx, hashBlock)) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "could not load source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sourcetx.vout.size() == 0) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no vouts in source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// might be malleable:
|
||||
if (burnTx.nExpiryHeight != sourcetx.nExpiryHeight) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "burntx nExpiryHeight incorrect for source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ac_pubkey check:
|
||||
if (CheckVin0PubKey(sourcetx) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get source tx opret:
|
||||
std::vector<uint8_t> vopret;
|
||||
uint8_t evalCode, funcId;
|
||||
int64_t amount;
|
||||
|
||||
GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret);
|
||||
if (vopret.size() == 0 || !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || evalCode != EVAL_IMPORTCOIN || funcId != 'A') {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "importTx amount=" << payouts[0].nValue << " burnTx amount=" << burnTx.vout[0].nValue << " opret amount=" << amount << " source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
|
||||
// amount malleability check with the opret from the source tx:
|
||||
if (payouts[0].nValue != amount) { // assume that burntx amount is checked in the common code in Eval::ImportCoin()
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "importTx amount != amount in the opret of source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* CC Eval method for import coin.
|
||||
*
|
||||
* This method should control every parameter of the ImportCoin transaction, since it has no signature
|
||||
* to protect it from malleability.
|
||||
|
||||
##### 0xffffffff is a special CCid for single chain/dual daemon imports
|
||||
*/
|
||||
bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &importTx,unsigned int nIn)
|
||||
{
|
||||
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; uint64_t txfee = 10000;
|
||||
uint32_t targetCcid; std::string targetSymbol; uint256 payoutsHash; std::vector<uint8_t> rawproof;
|
||||
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; uint64_t txfee = 10000; int32_t height,burnvout; std::vector<CPubKey> publishers;
|
||||
uint32_t targetCcid; std::string targetSymbol,srcaddr,destaddr,receipt,rawburntx; uint256 payoutsHash,bindtxid; std::vector<uint8_t> rawproof;
|
||||
std::vector<uint256> txids; CPubKey destpub;
|
||||
|
||||
if ( importTx.vout.size() < 2 )
|
||||
return Invalid("too-few-vouts");
|
||||
// params
|
||||
@@ -132,10 +592,10 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
|
||||
return Invalid("invalid-params");
|
||||
// Control all aspects of this transaction
|
||||
// It should not be at all malleable
|
||||
if (MakeImportCoinTransaction(proof, burnTx, payouts).GetHash() != importTx.GetHash())
|
||||
if (MakeImportCoinTransaction(proof, burnTx, payouts, importTx.nExpiryHeight).GetHash() != importTx.GetHash()) // ExistsImportTombstone prevents from duplication
|
||||
return Invalid("non-canonical");
|
||||
// burn params
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash,rawproof))
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof))
|
||||
return Invalid("invalid-burn-tx");
|
||||
// check burn amount
|
||||
{
|
||||
@@ -175,7 +635,7 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
|
||||
{
|
||||
if ( ASSETCHAINS_CODAPORT == 0 )
|
||||
return Invalid("CODA-import-without-port");
|
||||
else if ( CheckCODAimport(proof,rawproof,burnTx,payouts) < 0 )
|
||||
else if ( UnmarshalBurnTx(burnTx,srcaddr,receipt)==0 || CheckCODAimport(importTx,burnTx,payouts,srcaddr,receipt) < 0 )
|
||||
return Invalid("CODA-import-failure");
|
||||
}
|
||||
else if ( targetSymbol == "PUBKEY" )
|
||||
@@ -189,11 +649,9 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
|
||||
{
|
||||
if ( targetSymbol != ASSETCHAINS_SELFIMPORT )
|
||||
return Invalid("invalid-gateway-import-coin");
|
||||
else if ( CheckGATEWAYimport(proof,rawproof,burnTx,payouts) < 0 )
|
||||
else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub) < 0 )
|
||||
return Invalid("GATEWAY-import-failure");
|
||||
}
|
||||
}
|
||||
return Valid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
1292
src/cc/importgateway.cpp
Normal file
1292
src/cc/importgateway.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -35,8 +35,8 @@
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
#ifndef cJSON__ccih
|
||||
#define cJSON__ccih
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -115,7 +115,7 @@ bool LottoExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
|
||||
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any lotto CC for now
|
||||
return eval->Invalid("no validation yet");
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
@@ -166,7 +166,7 @@ int64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
|
||||
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);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -209,7 +209,7 @@ int64_t LottoPlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,u
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
lockedfunds = 0;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -266,7 +266,7 @@ UniValue LottoList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,hentropy; CTransaction vintx; uint64_t sbits; int32_t ticketsize,odds,firstheight,period; char str[65];
|
||||
cp = CCinit(&C,EVAL_LOTTO);
|
||||
SetCCtxids(addressIndex,cp->normaladdr);
|
||||
SetCCtxids(addressIndex,cp->normaladdr,true);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
|
||||
19
src/cc/makecclib
Executable file
19
src/cc/makecclib
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
rm *.so rogue/rogue games/tetris games/prices
|
||||
|
||||
echo rogue
|
||||
make -f Makefile_rogue
|
||||
./makerogue
|
||||
|
||||
echo sudoku/musig/dilithium
|
||||
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o sudokucc.so cclib.cpp
|
||||
|
||||
echo games tetris
|
||||
./maketetris
|
||||
|
||||
echo games prices
|
||||
./makeprices
|
||||
|
||||
echo customcc stub
|
||||
gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp
|
||||
|
||||
7
src/cc/makecustom
Executable file
7
src/cc/makecustom
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp
|
||||
cp customcc.so ../libcc.so
|
||||
cd ..
|
||||
make
|
||||
cd cc
|
||||
|
||||
7
src/cc/makegames
Executable file
7
src/cc/makegames
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp
|
||||
cp gamescc.so ../libcc.so
|
||||
cd ..
|
||||
make
|
||||
cd cc
|
||||
|
||||
8
src/cc/makeprices
Executable file
8
src/cc/makeprices
Executable file
@@ -0,0 +1,8 @@
|
||||
echo pricescc.so
|
||||
gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp
|
||||
echo prices
|
||||
cd games
|
||||
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES ../gamescc.cpp -lncurses -lcurl -o prices
|
||||
cd ..
|
||||
|
||||
|
||||
37
src/cc/makerogue
Executable file
37
src/cc/makerogue
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
cd rogue;
|
||||
make clean;
|
||||
|
||||
if [ "$HOST" = "x86_64-w64-mingw32" ]; then
|
||||
echo building rogue.exe...
|
||||
./configure --host=x86_64-w64-mingw32
|
||||
echo $PWD
|
||||
wget https://github.com/KomodoPlatform/rogue/releases/download/0.3.3b-01/x86_64-w64-mingw32.tar.gz
|
||||
tar xvfz x86_64-w64-mingw32.tar.gz && rm x86_64-w64-mingw32.tar.gz
|
||||
echo lib archive cleaned
|
||||
echo $PWD
|
||||
if make -f Makefile_win "$@"; then
|
||||
echo rogue.exe build SUCCESSFUL
|
||||
cd ..
|
||||
else
|
||||
echo rogue.exe build FAILED
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo building rogue...
|
||||
./configure
|
||||
if make "$@"; then
|
||||
echo rogue build SUCCESSFUL
|
||||
cd ..
|
||||
else
|
||||
echo rogue build FAILED
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if make -f Makefile_rogue "$@"; then
|
||||
echo ROGUE BUILD SUCCESSFUL
|
||||
else
|
||||
echo ROGUE BUILD FAILED
|
||||
exit 1
|
||||
fi
|
||||
7
src/cc/maketetris
Executable file
7
src/cc/maketetris
Executable file
@@ -0,0 +1,7 @@
|
||||
echo gamescc.so with tetris
|
||||
gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp
|
||||
echo tetris dapp
|
||||
cd games
|
||||
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE ../gamescc.cpp -lncurses -lcurl -o tetris
|
||||
cd ..
|
||||
|
||||
1125
src/cc/marmara.cpp
1125
src/cc/marmara.cpp
File diff suppressed because it is too large
Load Diff
868
src/cc/musig.cpp
Normal file
868
src/cc/musig.cpp
Normal file
@@ -0,0 +1,868 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
/* first make a combined pk:
|
||||
|
||||
./komodo-cli -ac_name=MUSIG cclib combine 18 '["02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28","0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4"]'
|
||||
{
|
||||
"pkhash": "5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",
|
||||
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
the combined_pk and pkhash will be needed for various other rpc calls
|
||||
|
||||
second, send 1 coin to the combined_pk
|
||||
./komodo-cli -ac_name=MUSIG cclib send 18 '["03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",1]'
|
||||
{
|
||||
"hex": "0400008085202f8901a980664dffc810725a79ffb89ac48be4c7b6bade9b789732fcf871acf8e81a2e010000006a47304402207e52763661ecd2c34a65d6623950be11794825db71576dc11894c606ddc317800220028fef46dc20630d0fdf22647b5d4ff0f1c47cf75f48702d0a91d5589eff99d001210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ffffffff031008f60500000000302ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cce09aa4350000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000266a2412782103f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b00000000920500000000000000000000000000",
|
||||
"txid": "5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
sendrawtransaction of the above hex.
|
||||
./komodo-cli -ac_name=MUSIG getrawtransaction 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c 1
|
||||
"vout": [
|
||||
{
|
||||
"value": 1.00010000,
|
||||
"valueSat": 100010000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "a22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401 OP_CHECKCRYPTOCONDITION",
|
||||
"hex": "2ea22c8020c71ddb3aac7f9b9e4bdacf032aaa8b8e4433c4ff9f8a43cebb9c1f5da96928a48103120c008203000401cc",
|
||||
"reqSigs": 1,
|
||||
"type": "cryptocondition",
|
||||
"addresses": [
|
||||
"RKWS7jxyjPX9iaJttk8iMKf1AumanKypez"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 8.99980000,
|
||||
"valueSat": 899980000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4 OP_CHECKSIG",
|
||||
"hex": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkey",
|
||||
"addresses": [
|
||||
"RVQjvGdRbYLJ49bfH4SAFseipvwE3UdoDw"
|
||||
]
|
||||
}
|
||||
|
||||
script: 210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac
|
||||
|
||||
sendtxid: 5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c
|
||||
|
||||
get the msg we need to sign:
|
||||
|
||||
./komodo-cli -ac_name=MUSIG cclib calcmsg 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac"]'
|
||||
|
||||
{
|
||||
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
the "msg" is what needs to be signed to create a valid spend
|
||||
|
||||
now on each signing node, a session needs to be created:
|
||||
5 args: ind, numsigners, combined_pk, pkhash, message to be signed
|
||||
|
||||
on node with pubkey: 02fb6aa0b96cad24d46b5da93eba3864c45ce07a73bba12da530ae841e140fcf28
|
||||
./komodo-cli -ac_name=MUSIG cclib session 18 '[0,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]'
|
||||
{
|
||||
"myind": 0,
|
||||
"numsigners": 2,
|
||||
"commitment": "bbea1f2562eca01b9a1393c5dc188bdd44551aebf684f4459930f59dde01f7ae",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
on node with pubkey: 0255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4
|
||||
./komodo-cli -ac_name=MUSIG cclib session 18 '[1,2,"03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75"]'
|
||||
{
|
||||
"myind": 1,
|
||||
"numsigners": 2,
|
||||
"commitment": "c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
now we need to get the commitment from each node to the other one. the session already put the commitment for each node into the global struct. Keep in mind there is a single global struct with session unique to each cclib session call. that means no restarting any deamon in the middle of the process on any of the nodes and only call cclib session a single time. this is an artificial restriction just to simplify the initial implementation of musig
|
||||
./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","c2291acb747a75b1a40014d8eb0cc90a1360f74d413f65f78e20a7de45eda851"]'
|
||||
{
|
||||
"added_index": 1,
|
||||
"myind": 0,
|
||||
"nonce": "02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
./komodo-cli -ac_name=MUSIG cclib commit 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"d242cff13fa8c9b83248e4219fda459ada146b885f2171481f1b0f66c66d94ad"]'
|
||||
{
|
||||
"added_index": 0,
|
||||
"myind": 1,
|
||||
"nonce": "039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
Now exchange the revealed nonces to each node:
|
||||
./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","039365deaaaea089d509ba4c9f846de2baf4aa04cf6b26fa2c1cd818553e47f80c"]'
|
||||
{
|
||||
"added_index": 1,
|
||||
"myind": 0,
|
||||
"partialsig": "1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
./komodo-cli -ac_name=MUSIG cclib nonce 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"02fec7a9310c959a0a97b86bc3f8c30d392d1fb51793915898c568f73f1f70476b"]'
|
||||
{
|
||||
"added_index": 0,
|
||||
"myind": 1,
|
||||
"partialsig": "4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
Almost there! final step is to exchange the partial sigs between signers
|
||||
./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b","1","4a3795e6801b355102c617390cf5a462061e082e35dc2ed8f8b1fab54cc0769e"]'
|
||||
{
|
||||
"added_index": 1,
|
||||
"result": "success",
|
||||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"
|
||||
}
|
||||
|
||||
./komodo-cli -ac_name=MUSIG cclib partialsig 18 '["5cb5a225064ca6ffc1438cb2a6ac2ac65fe2d5055dc7f6c7ebffb9a231f8912b",0,"1d65c09cd9bffe4f0604227e66cd7cd221480bbb08262fe885563a9df7cf8f5b"]'
|
||||
{
|
||||
"added_index": 0,
|
||||
"result": "success",
|
||||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"
|
||||
}
|
||||
|
||||
Notice both nodes generated the same combined signature!
|
||||
|
||||
Now for a sanity test, we can use the verify call to make sure this sig will work with the msg needed for the spend:
|
||||
|
||||
./komodo-cli -ac_name=MUSIG cclib verify 18 '["f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75","03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]'
|
||||
{
|
||||
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75",
|
||||
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",
|
||||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9",
|
||||
"result": "success"
|
||||
}
|
||||
|
||||
and finally the spend: sendtxid, scriptPubKey, musig
|
||||
|
||||
./komodo-cli -ac_name=MUSIG cclib spend 18 '["5ce74037a153ee210413b48d4e88638b99825a2de1a1f1aa0d36ebf93019824c","210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac","a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9"]'
|
||||
{
|
||||
"scriptpubkey": "210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac",
|
||||
"msg": "f7fb85d1412814e3c2f98b990802af6ee33dad368c6ba05c2050e9e5506fcd75",
|
||||
"combined_pk": "03f016c348437c7422eed92d865aa9789614f75327cada463eefc566126b54785b",
|
||||
"combinedsig": "a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f9",
|
||||
"hex": "0400008085202f89014c821930f9eb360daaf1a1e12d5a82998b63884e8db4130421ee53a13740e75c000000007b4c79a276a072a26ba067a5658021032d29d6545a2aafad795d9cf50912ecade549137
|
||||
163934dfb2895ebc0e211ce8a81409671a60db89b3bc58966f3acc80194479b1a43d868e95a11ebc5609646d18710341a8ff92a7817571980307f5d660cc00a2735ac6333e0a7191243f1263f1959a100af03800112
|
||||
a10001ffffffff0200e1f5050000000023210255c46dbce584e3751081b39d7fc054fc807100557e73fc444481618b5706afb4ac0000000000000000686a4c6512792103f016c348437c7422eed92d865aa9789614f
|
||||
75327cada463eefc566126b54785b40a76f2790747ed2436a281f2660bdbee21bad9ee130b9cab6e542fa618fba1512679d568359db33a008ca39b773c32134276613e93e025ec17e083553449005f900000000a805
|
||||
00000000000000000000000000",
|
||||
"txid": "910635bf69a047fc90567a83ff12e47b753f470658b6d0855ec96e07e7349a8a",
|
||||
"result": "success"
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
#define USE_BASIC_CONFIG
|
||||
#define ENABLE_MODULE_MUSIG
|
||||
#include "../secp256k1/src/basic-config.h"
|
||||
#include "../secp256k1/include/secp256k1.h"
|
||||
#include "../secp256k1/src/ecmult.h"
|
||||
#include "../secp256k1/src/ecmult_gen.h"
|
||||
|
||||
typedef struct { unsigned char data[64]; } secp256k1_schnorrsig;
|
||||
struct secp256k1_context_struct {
|
||||
secp256k1_ecmult_context ecmult_ctx;
|
||||
secp256k1_ecmult_gen_context ecmult_gen_ctx;
|
||||
secp256k1_callback illegal_callback;
|
||||
secp256k1_callback error_callback;
|
||||
};
|
||||
|
||||
|
||||
//#include "../secp256k1/include/secp256k1.h"
|
||||
//#include "../secp256k1/include/secp256k1_schnorrsig.h"
|
||||
#include "../secp256k1/include/secp256k1_musig.h"
|
||||
|
||||
|
||||
extern "C" int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
|
||||
extern "C" int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk);
|
||||
extern "C" int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64);
|
||||
extern "C" int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys);
|
||||
extern "C" int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey);
|
||||
extern "C" int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig);
|
||||
|
||||
#define MUSIG_PREVN 0 // for now, just use vout0 for the musig output
|
||||
#define MUSIG_TXFEE 10000
|
||||
|
||||
struct musig_info
|
||||
{
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_pubkey combined_pk;
|
||||
uint8_t *nonce_commitments,**commitment_ptrs; // 32*N_SIGNERS
|
||||
secp256k1_musig_session_signer_data *signer_data; //[N_SIGNERS];
|
||||
secp256k1_pubkey *nonces; //[N_SIGNERS];
|
||||
secp256k1_musig_partial_signature *partial_sig; //[N_SIGNERS];
|
||||
int32_t myind,num,numcommits,numnonces,numpartials;
|
||||
uint8_t msg[32],pkhash[32],combpk[33];
|
||||
};
|
||||
|
||||
std::vector <struct musig_info *> MUSIG;
|
||||
|
||||
struct musig_info *musig_infocreate(int32_t myind,int32_t num)
|
||||
{
|
||||
int32_t i; struct musig_info *mp = (struct musig_info *)calloc(1,sizeof(*mp));
|
||||
mp->myind = myind, mp->num = num;
|
||||
mp->nonce_commitments = (uint8_t *)calloc(num,32);
|
||||
mp->commitment_ptrs = (uint8_t **)calloc(num,sizeof(*mp->commitment_ptrs));
|
||||
for (i=0; i<num; i++)
|
||||
mp->commitment_ptrs[i] = &mp->nonce_commitments[i*32];
|
||||
mp->signer_data = (secp256k1_musig_session_signer_data *)calloc(num,sizeof(*mp->signer_data));
|
||||
mp->nonces = (secp256k1_pubkey *)calloc(num,sizeof(*mp->nonces));
|
||||
mp->partial_sig = (secp256k1_musig_partial_signature *)calloc(num,sizeof(*mp->partial_sig));
|
||||
return(mp);
|
||||
}
|
||||
|
||||
void musig_infofree(struct musig_info *mp)
|
||||
{
|
||||
if ( mp->partial_sig != 0 )
|
||||
{
|
||||
GetRandBytes((uint8_t *)mp->partial_sig,mp->num*sizeof(*mp->partial_sig));
|
||||
free(mp->partial_sig);
|
||||
}
|
||||
if ( mp->nonces != 0 )
|
||||
{
|
||||
GetRandBytes((uint8_t *)mp->nonces,mp->num*sizeof(*mp->nonces));
|
||||
free(mp->nonces);
|
||||
}
|
||||
if ( mp->signer_data != 0 )
|
||||
{
|
||||
GetRandBytes((uint8_t *)mp->signer_data,mp->num*sizeof(*mp->signer_data));
|
||||
free(mp->signer_data);
|
||||
}
|
||||
if ( mp->nonce_commitments != 0 )
|
||||
{
|
||||
GetRandBytes((uint8_t *)mp->nonce_commitments,mp->num*32);
|
||||
free(mp->nonce_commitments);
|
||||
}
|
||||
if ( mp->commitment_ptrs != 0 )
|
||||
{
|
||||
GetRandBytes((uint8_t *)mp->commitment_ptrs,mp->num*sizeof(*mp->commitment_ptrs));
|
||||
free(mp->commitment_ptrs);
|
||||
}
|
||||
GetRandBytes((uint8_t *)mp,sizeof(*mp));
|
||||
free(mp);
|
||||
}
|
||||
|
||||
CScript musig_sendopret(uint8_t funcid,CPubKey pk)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_MUSIG;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t musig_sendopretdecode(CPubKey &pk,CScript scriptPubKey)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t e,f;
|
||||
GetOpReturnData(scriptPubKey,vopret);
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_MUSIG && f == 'x' )
|
||||
{
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript musig_spendopret(uint8_t funcid,CPubKey pk,std::vector<uint8_t> musig64)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_MUSIG;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk << musig64);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t musig_spendopretdecode(CPubKey &pk,std::vector<uint8_t> &musig64,CScript scriptPubKey)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t e,f;
|
||||
GetOpReturnData(scriptPubKey,vopret);
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk; ss >> musig64) != 0 && e == EVAL_MUSIG && f == 'y' )
|
||||
{
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t musig_parsepubkey(secp256k1_context *ctx,secp256k1_pubkey &spk,cJSON *item)
|
||||
{
|
||||
char *hexstr;
|
||||
if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == 66 )
|
||||
{
|
||||
CPubKey pk(ParseHex(hexstr));
|
||||
if ( secp256k1_ec_pubkey_parse(ctx,&spk,pk.begin(),33) > 0 )
|
||||
return(1);
|
||||
} else return(-1);
|
||||
}
|
||||
|
||||
int32_t musig_msghash(uint8_t *msg,uint256 prevhash,int32_t prevn,CTxOut vout,CPubKey pk)
|
||||
{
|
||||
CScript data; uint256 hash; int32_t len = 0;
|
||||
data << E_MARSHAL(ss << prevhash << prevn << vout << pk);
|
||||
hash = Hash(data.begin(),data.end());
|
||||
memcpy(msg,&hash,sizeof(hash));
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t musig_prevoutmsg(uint8_t *msg,uint256 sendtxid,CScript scriptPubKey)
|
||||
{
|
||||
CTransaction vintx; uint256 hashBlock; int32_t numvouts; CTxOut vout; CPubKey pk;
|
||||
memset(msg,0,32);
|
||||
if ( myGetTransaction(sendtxid,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
|
||||
{
|
||||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
|
||||
{
|
||||
vout.nValue = vintx.vout[MUSIG_PREVN].nValue - MUSIG_TXFEE;
|
||||
vout.scriptPubKey = scriptPubKey;
|
||||
return(musig_msghash(msg,sendtxid,MUSIG_PREVN,vout,pk));
|
||||
}
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 sendtxid; int32_t i,zeros=0; uint8_t msg[32]; char *scriptstr,str[65]; int32_t n;
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
||||
{
|
||||
if ( n == 2 )
|
||||
{
|
||||
sendtxid = juint256(jitem(params,0));
|
||||
scriptstr = jstr(jitem(params,1),0);
|
||||
if ( is_hexstr(scriptstr,0) != 0 )
|
||||
{
|
||||
CScript scriptPubKey;
|
||||
scriptPubKey.resize(strlen(scriptstr)/2);
|
||||
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr);
|
||||
musig_prevoutmsg(msg,sendtxid,scriptPubKey);
|
||||
for (i=0; i<32; i++)
|
||||
{
|
||||
sprintf(&str[i<<1],"%02x",msg[i]);
|
||||
if ( msg[i] == 0 )
|
||||
zeros++;
|
||||
}
|
||||
str[64] = 0;
|
||||
if ( zeros != 32 )
|
||||
{
|
||||
result.push_back(Pair("msg",str));
|
||||
result.push_back(Pair("result","success"));
|
||||
return(result);
|
||||
} else return(cclib_error(result,"null result, make sure params are sendtxid, scriptPubKey"));
|
||||
} else return(cclib_error(result,"script is not hex"));
|
||||
} else return(cclib_error(result,"need exactly 2 parameters: sendtxid, scriptPubKey"));
|
||||
} else return(cclib_error(result,"couldnt parse params"));
|
||||
}
|
||||
|
||||
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
|
||||
UniValue result(UniValue::VOBJ); CPubKey pk; int32_t i,n; uint8_t pkhash[32]; char *hexstr,str[67]; secp256k1_pubkey combined_pk,spk; std::vector<secp256k1_pubkey> pubkeys;
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
||||
{
|
||||
//fprintf(stderr,"n.%d args.(%s)\n",n,jprint(params,0));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
if ( musig_parsepubkey(ctx,spk,jitem(params,i)) < 0 )
|
||||
return(cclib_error(result,"error parsing pk"));
|
||||
pubkeys.push_back(spk);
|
||||
}
|
||||
if ( secp256k1_musig_pubkey_combine(ctx,NULL,&combined_pk,pkhash,&pubkeys[0],n) > 0 )
|
||||
{
|
||||
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&combined_pk,SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
|
||||
{
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(&str[i<<1],"%02x",pkhash[i]);
|
||||
str[64] = 0;
|
||||
result.push_back(Pair("pkhash",str));
|
||||
|
||||
for (i=0; i<33; i++)
|
||||
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
|
||||
str[66] = 0;
|
||||
result.push_back(Pair("combined_pk",str));
|
||||
result.push_back(Pair("result","success"));
|
||||
return(result);
|
||||
} else return(cclib_error(result,"error serializeing combined_pk"));
|
||||
} else return(cclib_error(result,"error combining pukbeys"));
|
||||
} else return(cclib_error(result,"need pubkeys params"));
|
||||
}
|
||||
|
||||
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
UniValue result(UniValue::VOBJ); int32_t i,n,myind,num,musiglocation; char *pkstr,*pkhashstr,*msgstr; uint8_t session[32],msg[32],pkhash[32],privkey[32],pub33[33]; CPubKey pk; char str[67];
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 5 )
|
||||
{
|
||||
myind = juint(jitem(params,0),0);
|
||||
num = juint(jitem(params,1),0);
|
||||
if ( myind < 0 || myind >= num || num <= 0 )
|
||||
return(cclib_error(result,"illegal myindex and numsigners"));
|
||||
if ( n > 5 )
|
||||
musiglocation = juint(jitem(params,5),0);
|
||||
else if ( n == 5 )
|
||||
musiglocation = 0;
|
||||
//printf("number of params.%i musiglocation.%i\n",n,musiglocation);
|
||||
if ( MUSIG.size() > musiglocation )
|
||||
{
|
||||
for (int i = 0; i < MUSIG.size()-1; i++)
|
||||
musig_infofree(MUSIG[i]);
|
||||
MUSIG.clear();
|
||||
}
|
||||
struct musig_info *temp_musig = musig_infocreate(myind,num);
|
||||
MUSIG.push_back(temp_musig);
|
||||
if ( musig_parsepubkey(ctx,MUSIG[musiglocation]->combined_pk,jitem(params,2)) < 0 )
|
||||
return(cclib_error(result,"error parsing combined_pubkey"));
|
||||
else if ( cclib_parsehash(MUSIG[musiglocation]->pkhash,jitem(params,3),32) < 0 )
|
||||
return(cclib_error(result,"error parsing pkhash"));
|
||||
else if ( cclib_parsehash(MUSIG[musiglocation]->msg,jitem(params,4),32) < 0 )
|
||||
return(cclib_error(result,"error parsing msg"));
|
||||
Myprivkey(privkey);
|
||||
GetRandBytes(session,32);
|
||||
/** Initializes a signing session for a signer
|
||||
*
|
||||
* Returns: 1: session is successfully initialized
|
||||
* 0: session could not be initialized: secret key or secret nonce overflow
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot
|
||||
* be NULL)
|
||||
* Out: session: the session structure to initialize (cannot be NULL)
|
||||
* signers: an array of signers' data to be initialized. Array length must
|
||||
* equal to `n_signers` (cannot be NULL)
|
||||
* nonce_commitment32: filled with a 32-byte commitment to the generated nonce
|
||||
* (cannot be NULL)
|
||||
* In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be
|
||||
* NULL). If a non-unique session_id32 was given then a partial
|
||||
* signature will LEAK THE SECRET KEY.
|
||||
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you
|
||||
* require sharing public nonces before the message is known
|
||||
* because it reduces nonce misuse resistance. If NULL, must be
|
||||
* set with `musig_session_set_msg` before signing and verifying.
|
||||
* combined_pk: the combined public key of all signers (cannot be NULL)
|
||||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be
|
||||
* NULL)
|
||||
* n_signers: length of signers array. Number of signers participating in
|
||||
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
|
||||
* my_index: index of this signer in the signers array
|
||||
* seckey: the signer's 32-byte secret key (cannot be NULL)
|
||||
*/
|
||||
//fprintf(stderr, "SESSION: struct_size.%li using struct %i\n",MUSIG.size(), musiglocation);
|
||||
if ( secp256k1_musig_session_initialize(ctx,&MUSIG[musiglocation]->session,MUSIG[musiglocation]->signer_data, &MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind * 32],session,MUSIG[musiglocation]->msg,&MUSIG[musiglocation]->combined_pk,MUSIG[musiglocation]->pkhash,MUSIG[musiglocation]->num,MUSIG[musiglocation]->myind,privkey) > 0 )
|
||||
{
|
||||
memset(session,0,sizeof(session));
|
||||
result.push_back(Pair("myind",(int64_t)myind));
|
||||
result.push_back(Pair("numsigners",(int64_t)num));
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(&str[i<<1],"%02x",MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind*32 + i]);
|
||||
str[64] = 0;
|
||||
if ( n == 5 )
|
||||
MUSIG[musiglocation]->numcommits = 1;
|
||||
result.push_back(Pair("commitment",str));
|
||||
result.push_back(Pair("result","success"));
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(session,0,sizeof(session));
|
||||
return(cclib_error(result,"couldnt initialize session"));
|
||||
}
|
||||
} else return(cclib_error(result,"wrong number of params, need 5: myindex, numsigners, combined_pk, pkhash, msg32"));
|
||||
}
|
||||
|
||||
UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
|
||||
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32]; CPubKey pk; char str[67];
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
|
||||
{
|
||||
if ( n > 3 )
|
||||
myind = juint(jitem(params,3),0);
|
||||
else if ( n == 3 )
|
||||
myind = 0;
|
||||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
|
||||
return(cclib_error(result,"error parsing pkhash"));
|
||||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
|
||||
return(cclib_error(result,"pkhash doesnt match session pkhash"));
|
||||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
|
||||
return(cclib_error(result,"illegal ind for session"));
|
||||
else if ( cclib_parsehash(&MUSIG[myind]->nonce_commitments[ind*32],jitem(params,2),32) < 0 )
|
||||
return(cclib_error(result,"error parsing commitment"));
|
||||
/** Gets the signer's public nonce given a list of all signers' data with commitments
|
||||
*
|
||||
* Returns: 1: public nonce is written in nonce
|
||||
* 0: signer data is missing commitments or session isn't initialized
|
||||
* for signing
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: the signing session to get the nonce from (cannot be NULL)
|
||||
* signers: an array of signers' data initialized with
|
||||
* `musig_session_initialize`. Array length must equal to
|
||||
* `n_commitments` (cannot be NULL)
|
||||
* Out: nonce: the nonce (cannot be NULL)
|
||||
* In: commitments: array of 32-byte nonce commitments (cannot be NULL)
|
||||
* n_commitments: the length of commitments and signers array. Must be the total
|
||||
* number of signers participating in the MuSig.
|
||||
*/
|
||||
result.push_back(Pair("added_index",ind));
|
||||
//fprintf(stderr, "COMMIT: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
|
||||
MUSIG[myind]->numcommits++;
|
||||
if ( MUSIG[myind]->numcommits >= MUSIG[myind]->num && secp256k1_musig_session_get_public_nonce(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,&MUSIG[myind]->nonces[MUSIG[myind]->myind],MUSIG[myind]->commitment_ptrs,MUSIG[myind]->num) > 0 )
|
||||
{
|
||||
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&MUSIG[myind]->nonces[MUSIG[myind]->myind],SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
|
||||
{
|
||||
for (i=0; i<33; i++)
|
||||
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
|
||||
str[66] = 0;
|
||||
if ( n == 3 )
|
||||
MUSIG[myind]->numnonces = 1;
|
||||
result.push_back(Pair("myind",MUSIG[myind]->myind));
|
||||
result.push_back(Pair("nonce",str));
|
||||
result.push_back(Pair("result","success"));
|
||||
} else return(cclib_error(result,"error serializing nonce (pubkey)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("status","not enough commitments"));
|
||||
result.push_back(Pair("result","success"));
|
||||
}
|
||||
return(result);
|
||||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, commitment"));
|
||||
}
|
||||
|
||||
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32],psig[32]; CPubKey pk; char str[67];
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
|
||||
{
|
||||
if ( n > 3 )
|
||||
myind = juint(jitem(params,3),0);
|
||||
else if ( n == 3 )
|
||||
myind = 0;
|
||||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
|
||||
return(cclib_error(result,"error parsing pkhash"));
|
||||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
|
||||
return(cclib_error(result,"pkhash doesnt match session pkhash"));
|
||||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
|
||||
return(cclib_error(result,"illegal ind for session"));
|
||||
else if ( musig_parsepubkey(ctx,MUSIG[myind]->nonces[ind],jitem(params,2)) < 0 )
|
||||
return(cclib_error(result,"error parsing nonce"));
|
||||
result.push_back(Pair("added_index",ind));
|
||||
/** Checks a signer's public nonce against a commitment to said nonce, and update
|
||||
* data structure if they match
|
||||
*
|
||||
* Returns: 1: commitment was valid, data structure updated
|
||||
* 0: commitment was invalid, nothing happened
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* signer: pointer to the signer data to update (cannot be NULL). Must have
|
||||
* been used with `musig_session_get_public_nonce` or initialized
|
||||
* with `musig_session_initialize_verifier`.
|
||||
* In: nonce: signer's alleged public nonce (cannot be NULL)
|
||||
*/
|
||||
MUSIG[myind]->numnonces++;
|
||||
//fprintf(stderr, "NONCE: struct_size.%li using_struct.%i added_index.%i numnounces.%i num.%i\n",MUSIG.size(), myind, ind, MUSIG[myind]->numnonces, MUSIG[myind]->num);
|
||||
if ( MUSIG[myind]->numnonces < MUSIG[myind]->num )
|
||||
{
|
||||
result.push_back(Pair("status","not enough nonces"));
|
||||
result.push_back(Pair("result","success"));
|
||||
return(result);
|
||||
}
|
||||
for (i=0; i<MUSIG[myind]->num; i++)
|
||||
{
|
||||
if ( secp256k1_musig_set_nonce(ctx,&MUSIG[myind]->signer_data[i],&MUSIG[myind]->nonces[i]) == 0 )
|
||||
return(cclib_error(result,"error setting nonce"));
|
||||
}
|
||||
/** Updates a session with the combined public nonce of all signers. The combined
|
||||
* public nonce is the sum of every signer's public nonce.
|
||||
*
|
||||
* Returns: 1: nonces are successfully combined
|
||||
* 0: a signer's nonce is missing
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: session to update with the combined public nonce (cannot be
|
||||
* NULL)
|
||||
* signers: an array of signers' data, which must have had public nonces
|
||||
* set with `musig_set_nonce`. Array length must equal to `n_signers`
|
||||
* (cannot be NULL)
|
||||
* n_signers: the length of the signers array. Must be the total number of
|
||||
* signers participating in the MuSig.
|
||||
* Out: nonce_is_negated: a pointer to an integer that indicates if the combined
|
||||
* public nonce had to be negated.
|
||||
* adaptor: point to add to the combined public nonce. If NULL, nothing is
|
||||
* added to the combined nonce.
|
||||
*/
|
||||
if ( secp256k1_musig_session_combine_nonces(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,MUSIG[myind]->num,NULL,NULL) > 0 )
|
||||
{
|
||||
if ( secp256k1_musig_partial_sign(ctx,&MUSIG[myind]->session,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
|
||||
{
|
||||
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
|
||||
{
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(&str[i<<1],"%02x",psig[i]);
|
||||
str[64] = 0;
|
||||
result.push_back(Pair("myind",MUSIG[myind]->myind));
|
||||
result.push_back(Pair("partialsig",str));
|
||||
result.push_back(Pair("result","success"));
|
||||
if ( n == 3 )
|
||||
MUSIG[myind]->numpartials = 1;
|
||||
return(result);
|
||||
} else return(cclib_error(result,"error serializing partial sig"));
|
||||
} else return(cclib_error(result,"error making partial sig"));
|
||||
} else return(cclib_error(result,"error combining nonces"));
|
||||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, nonce"));
|
||||
}
|
||||
|
||||
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
UniValue result(UniValue::VOBJ); int32_t i,ind,n,myind; uint8_t pkhash[32],psig[32],out64[64]; char str[129]; secp256k1_schnorrsig sig;
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
|
||||
{
|
||||
if ( n > 3 )
|
||||
myind = juint(jitem(params,3),0);
|
||||
else if ( n == 3 )
|
||||
myind = 0;
|
||||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
|
||||
return(cclib_error(result,"error parsing pkhash"));
|
||||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
|
||||
return(cclib_error(result,"pkhash doesnt match session pkhash"));
|
||||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
|
||||
return(cclib_error(result,"illegal ind for session"));
|
||||
else if ( cclib_parsehash(psig,jitem(params,2),32) < 0 )
|
||||
return(cclib_error(result,"error parsing psig"));
|
||||
else if ( secp256k1_musig_partial_signature_parse(ctx,&MUSIG[myind]->partial_sig[ind],psig) == 0 )
|
||||
return(cclib_error(result,"error parsing partialsig"));
|
||||
result.push_back(Pair("added_index",ind));
|
||||
//fprintf(stderr, "SIG: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
|
||||
MUSIG[myind]->numpartials++;
|
||||
if ( MUSIG[myind]->numpartials >= MUSIG[myind]->num && secp256k1_musig_partial_sig_combine(ctx,&MUSIG[myind]->session,&sig,MUSIG[myind]->partial_sig,MUSIG[myind]->num) > 0 )
|
||||
{
|
||||
if ( secp256k1_schnorrsig_serialize(ctx,out64,&sig) > 0 )
|
||||
{
|
||||
result.push_back(Pair("result","success"));
|
||||
for (i=0; i<64; i++)
|
||||
sprintf(&str[i<<1],"%02x",out64[i]);
|
||||
str[128] = 0;
|
||||
result.push_back(Pair("combinedsig",str));
|
||||
} else return(cclib_error(result,"error serializing combinedsig"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
|
||||
{
|
||||
result.push_back(Pair("myind",ind));
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(&str[i<<1],"%02x",psig[i]);
|
||||
str[64] = 0;
|
||||
result.push_back(Pair("partialsig",str));
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("status","need more partialsigs"));
|
||||
} else return(cclib_error(result,"error generating my partialsig"));
|
||||
}
|
||||
return(result);
|
||||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, partialsig"));
|
||||
}
|
||||
|
||||
//int testmain(void);
|
||||
UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
UniValue result(UniValue::VOBJ); int32_t i,n; uint8_t msg[32],musig64[64]; secp256k1_pubkey combined_pk; secp256k1_schnorrsig musig; char str[129];
|
||||
//testmain();
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 )
|
||||
{
|
||||
if ( cclib_parsehash(msg,jitem(params,0),32) < 0 )
|
||||
return(cclib_error(result,"error parsing pkhash"));
|
||||
else if ( musig_parsepubkey(ctx,combined_pk,jitem(params,1)) < 0 )
|
||||
return(cclib_error(result,"error parsing combined_pk"));
|
||||
else if ( cclib_parsehash(musig64,jitem(params,2),64) < 0 )
|
||||
return(cclib_error(result,"error parsing musig64"));
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(&str[i*2],"%02x",msg[i]);
|
||||
str[64] = 0;
|
||||
result.push_back(Pair("msg",str));
|
||||
result.push_back(Pair("combined_pk",jstr(jitem(params,1),0)));
|
||||
for (i=0; i<64; i++)
|
||||
sprintf(&str[i*2],"%02x",musig64[i]);
|
||||
str[128] = 0;
|
||||
result.push_back(Pair("combinedsig",str));
|
||||
if ( secp256k1_schnorrsig_parse(ctx,&musig,&musig64[0]) > 0 )
|
||||
{
|
||||
if ( secp256k1_schnorrsig_verify(ctx,&musig,msg,&combined_pk) > 0 )
|
||||
{
|
||||
result.push_back(Pair("result","success"));
|
||||
return(result);
|
||||
} else return(cclib_error(result,"musig didnt verify"));
|
||||
} else return(cclib_error(result,"couldnt parse musig64"));
|
||||
} else return(cclib_error(result,"wrong number of params, need 3: msg, combined_pk, combinedsig"));
|
||||
}
|
||||
|
||||
// helpers for rpc calls that generate/validate onchain tx
|
||||
|
||||
UniValue musig_rawtxresult(UniValue &result,std::string rawtx)
|
||||
{
|
||||
CTransaction tx;
|
||||
if ( rawtx.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("hex",rawtx));
|
||||
if ( DecodeHexTx(tx,rawtx) != 0 )
|
||||
{
|
||||
//if ( broadcastflag != 0 && myAddtomempool(tx) != 0 )
|
||||
// RelayTransaction(tx);
|
||||
result.push_back(Pair("txid",tx.GetHash().ToString()));
|
||||
result.push_back(Pair("result","success"));
|
||||
} else result.push_back(Pair("error","decode hex"));
|
||||
} else result.push_back(Pair("error","couldnt finalize CCtx"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
UniValue result(UniValue::VOBJ); int32_t n; char *hexstr; std::string rawtx; int64_t amount; CPubKey musigpk,mypk;
|
||||
if ( txfee == 0 )
|
||||
txfee = MUSIG_TXFEE;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
musigpk = GetUnspendable(cp,0);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
||||
{
|
||||
if ( n == 2 && (hexstr= jstr(jitem(params,0),0)) != 0 && is_hexstr(hexstr,0) == 66 )
|
||||
{
|
||||
CPubKey pk(ParseHex(hexstr));
|
||||
amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049;
|
||||
if ( amount >= 3*txfee && AddNormalinputs(mtx,mypk,amount+2*txfee,64) >= amount+2*txfee )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount+txfee,musigpk));
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_sendopret('x',pk));
|
||||
return(musig_rawtxresult(result,rawtx));
|
||||
} else return(cclib_error(result,"couldnt find funds or less than 0.0003"));
|
||||
} else return(cclib_error(result,"must have 2 params: pk, amount"));
|
||||
} else return(cclib_error(result,"not enough parameters"));
|
||||
}
|
||||
|
||||
UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,pk; secp256k1_pubkey combined_pk; char *scriptstr,*musigstr; uint8_t msg[32]; CTransaction vintx; uint256 prevhash,hashBlock; int32_t i,n,numvouts; char str[129]; CTxOut vout; secp256k1_schnorrsig musig;
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
||||
{
|
||||
if ( n == 3 )
|
||||
{
|
||||
prevhash = juint256(jitem(params,0));
|
||||
scriptstr = jstr(jitem(params,1),0);
|
||||
musigstr = jstr(jitem(params,2),0);
|
||||
if ( is_hexstr(scriptstr,0) != 0 && is_hexstr(musigstr,0) == 128 )
|
||||
{
|
||||
if ( txfee == 0 )
|
||||
txfee = MUSIG_TXFEE;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
std::vector<uint8_t> musig64(ParseHex(musigstr));
|
||||
CScript scriptPubKey;
|
||||
scriptPubKey.resize(strlen(scriptstr)/2);
|
||||
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr);
|
||||
if ( myGetTransaction(prevhash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
|
||||
{
|
||||
vout.nValue = vintx.vout[0].nValue - txfee;
|
||||
vout.scriptPubKey = scriptPubKey;
|
||||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
|
||||
{
|
||||
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
|
||||
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
|
||||
{
|
||||
musig_prevoutmsg(msg,prevhash,vout.scriptPubKey);
|
||||
{
|
||||
for (i=0; i<32; i++)
|
||||
sprintf(&str[i*2],"%02x",msg[i]);
|
||||
str[64] = 0;
|
||||
result.push_back(Pair("msg",str));
|
||||
for (i=0; i<33; i++)
|
||||
sprintf(&str[i*2],"%02x",((uint8_t *)pk.begin())[i]);
|
||||
str[66] = 0;
|
||||
result.push_back(Pair("combined_pk",str));
|
||||
for (i=0; i<64; i++)
|
||||
sprintf(&str[i*2],"%02x",musig64[i]);
|
||||
str[128] = 0;
|
||||
result.push_back(Pair("combinedsig",str));
|
||||
}
|
||||
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) )
|
||||
{
|
||||
return(cclib_error(result,"musig didnt validate"));
|
||||
}
|
||||
mtx.vin.push_back(CTxIn(prevhash,MUSIG_PREVN));
|
||||
mtx.vout.push_back(vout);
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_spendopret('y',pk,musig64));
|
||||
return(musig_rawtxresult(result,rawtx));
|
||||
} else return(cclib_error(result,"couldnt parse pk or musig"));
|
||||
} else return(cclib_error(result,"couldnt decode send opret"));
|
||||
} else return(cclib_error(result,"couldnt find vin0"));
|
||||
} else return(cclib_error(result,"script or musig is not hex"));
|
||||
} else return(cclib_error(result,"need to have exactly 3 params sendtxid, scriptPubKey, musig"));
|
||||
} else return(cclib_error(result,"params parse error"));
|
||||
}
|
||||
|
||||
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
||||
{
|
||||
static secp256k1_context *ctx;
|
||||
secp256k1_pubkey combined_pk; CPubKey pk,checkpk; secp256k1_schnorrsig musig; uint256 hashBlock; CTransaction vintx; int32_t numvouts; std::vector<uint8_t> musig64; uint8_t msg[32];
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if ( tx.vout.size() != 2 )
|
||||
return eval->Invalid("numvouts != 2");
|
||||
else if ( tx.vin.size() != 1 )
|
||||
return eval->Invalid("numvins != 1");
|
||||
else if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
|
||||
return eval->Invalid("illegal normal vin0");
|
||||
else if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
|
||||
{
|
||||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
|
||||
{
|
||||
if ( musig_spendopretdecode(checkpk,musig64,tx.vout[tx.vout.size()-1].scriptPubKey) == 'y' )
|
||||
{
|
||||
if ( pk == checkpk )
|
||||
{
|
||||
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
|
||||
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
|
||||
{
|
||||
musig_prevoutmsg(msg,tx.vin[0].prevout.hash,tx.vout[0].scriptPubKey);
|
||||
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) )
|
||||
return eval->Invalid("failed schnorrsig_verify");
|
||||
else return(true);
|
||||
} else return eval->Invalid("couldnt parse pk or musig");
|
||||
} else return eval->Invalid("combined_pk didnt match send opret");
|
||||
} else return eval->Invalid("failed decode musig spendopret");
|
||||
} else return eval->Invalid("couldnt decode send opret");
|
||||
} else return eval->Invalid("couldnt find vin0 tx");
|
||||
}
|
||||
@@ -171,7 +171,7 @@ CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp)
|
||||
if ( ctx == 0 )
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
Myprivkey(priv);
|
||||
cp->evalcode2 = EVAL_ORACLES;
|
||||
cp->unspendableEvalcode2 = EVAL_ORACLES;
|
||||
for (i=0; i<32; i++)
|
||||
cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]);
|
||||
while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 )
|
||||
@@ -197,7 +197,7 @@ int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publ
|
||||
{
|
||||
uint256 txid,oracletxid,hashBlock; int64_t datafee=0,dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,markeraddr);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -260,7 +260,7 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora
|
||||
{
|
||||
uint256 txid,oracletxid,hashBlock,btxid,batontxid = zeroid; int64_t dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk; uint8_t *ptr; std::vector<uint8_t> vopret,data;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,batonaddr);
|
||||
SetCCunspents(unspentOutputs,batonaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -294,7 +294,7 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( myIsutxo_spentinmempool(batontxid,1) != 0 )
|
||||
while ( myIsutxo_spentinmempool(ignoretxid,ignorevin,batontxid,1) != 0 )
|
||||
batontxid = myIs_baton_spentinmempool(batontxid,1);
|
||||
return(batontxid);
|
||||
}
|
||||
@@ -306,7 +306,7 @@ uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
|
||||
batontxid = zeroid;
|
||||
cp = CCinit(&C,EVAL_ORACLES);
|
||||
CCtxidaddr(markeraddr,reforacletxid);
|
||||
SetCCunspents(unspentOutputs,markeraddr);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
//char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk));
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
@@ -525,14 +525,14 @@ int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey
|
||||
} else return(0);
|
||||
}
|
||||
|
||||
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
|
||||
/*int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
|
||||
{
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
CTransaction regtx; uint256 hash,txid,oracletxid,batontxid; CPubKey pk; int32_t i,ht,maxheight=0; int64_t datafee,price; char batonaddr[64]; std::vector <uint8_t> data; struct CCcontract_info *cp,C; std::vector <struct oracleprice_info> publishers; std::vector <int64_t> prices;
|
||||
if ( format[0] != 'L' )
|
||||
return(0);
|
||||
cp = CCinit(&C,EVAL_ORACLES);
|
||||
SetCCunspents(unspentOutputs,markeraddr);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -562,7 +562,7 @@ int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *
|
||||
return(OracleCorrelatedPrice(height,prices));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}*/
|
||||
|
||||
int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
|
||||
{
|
||||
@@ -708,7 +708,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,uint
|
||||
char coinaddr[64],funcid; int64_t nValue,price,totalinputs = 0; uint256 tmporacletxid,tmpbatontxid,txid,hashBlock; std::vector<uint8_t> origpubkey,data; CTransaction vintx; int32_t numvouts,vout,n = 0;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; CPubKey tmppk; int64_t tmpnum;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
//fprintf(stderr,"addoracleinputs from (%s)\n",coinaddr);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
@@ -724,7 +724,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,uint
|
||||
else if (tmporacletxid==oracletxid)
|
||||
{
|
||||
// get valid CC payments
|
||||
if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
@@ -746,7 +746,7 @@ int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubK
|
||||
char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock,subtxid; CTransaction subtx;
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
|
||||
GetCCaddress(cp,coinaddr,publisher);
|
||||
SetCCtxids(addressIndex,coinaddr);
|
||||
SetCCtxids(addressIndex,coinaddr,true);
|
||||
//fprintf(stderr,"scan lifetime of %s\n",coinaddr);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
@@ -971,7 +971,8 @@ UniValue OracleInfo(uint256 origtxid)
|
||||
UniValue result(UniValue::VOBJ),a(UniValue::VARR);
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
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;
|
||||
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 )
|
||||
@@ -991,7 +992,7 @@ UniValue OracleInfo(uint256 origtxid)
|
||||
result.push_back(Pair("description",description));
|
||||
result.push_back(Pair("format",format));
|
||||
result.push_back(Pair("marker",markeraddr));
|
||||
SetCCunspents(unspentOutputs,markeraddr);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -1027,7 +1028,7 @@ UniValue OraclesList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65];
|
||||
cp = CCinit(&C,EVAL_ORACLES);
|
||||
SetCCtxids(addressIndex,cp->normaladdr);
|
||||
SetCCtxids(addressIndex,cp->normaladdr,true);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
|
||||
1007
src/cc/payments.cpp
1007
src/cc/payments.cpp
File diff suppressed because it is too large
Load Diff
@@ -16,17 +16,72 @@
|
||||
#include "CCPegs.h"
|
||||
|
||||
/*
|
||||
Pegs CC builds on top of Prices CC and would bind a pricefeed to a token bid/ask automated marketmaking.
|
||||
pegs CC is able to create a coin backed (by any supported coin with gateways CC deposits) and pegged to any synthetic price that is able to be calculated based on prices CC
|
||||
|
||||
Funds deposited into CC address for a specific peg would then be used to fund the bid/ask as the pricefeed changes the price. Profits/losses would accumulate in the associated address.
|
||||
First, the prices CC needs to be understood, so the extensive comments at the top of ~/src/cc/prices.cpp needs to be understood.
|
||||
|
||||
In the event funds exceed a specified level, it can be spent into a collection address. The idea is that the collection address can further be used for revshares.
|
||||
The second aspect is the ability to import coins, as used by the crosschain burn/import and the -ac_import chains.
|
||||
|
||||
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
|
||||
<one hour later...>
|
||||
|
||||
OK, now we are ready to describe the pegs CC. Let us imagine an -ac_import sidechain with KMD gateways CC. Now we have each native coin fungible with the real KMD via the gateways deposit/withdraw mechanism. Let us start with that and make a pegged and backed USD chain.
|
||||
|
||||
<alternatively we can start from a CC enabled chain with external value>
|
||||
|
||||
Here the native coin is KMD, but we want USD, so there needs to be a way to convert the KMD amounts into USD amounts. Something like "KMDBTC, BTCUSD, *, 1" which is the prices CC syntax to calculate KMD/USD, which is exactly what we need. So now we can assume that we have a block by block usable KMD/USD price. implementationwise, there can be an -ac option like -ac_peg="KMDBTC, BTCUSD, *, 1" and in conjunction with -ac_import=KMD gateways CC sidechain, we now have a chain where deposit of KMD issues the correct USD coins and redeem of USD coins releases the correct number of KMD coins.
|
||||
|
||||
Are we done yet?
|
||||
|
||||
Not quite, as the prices of KMD will be quite volatile relative to USD, which is good during bull markets, not so happy during bear markets. There are 2 halves to this problem, how to deal with massive price increase (easy to solve), how to solve 90% price drop (a lot harder).
|
||||
|
||||
In order to solve both, what is needed is an "account" based tracking which updates based on both price change, coins issued, payments made. So let us create an account that is based on a specific pubkey, where all relevant deposits, issuances, withdraws are tracked via appropriate vin/vout markers.
|
||||
|
||||
Let us modify the USD chain above so that only 80% of the possible USD is issued and 20% held in reserve. This 80% should be at least some easily changeable #define, or even an -ac parameter. We want the issued coins to be released without any encumberances, but the residual 20% value is still controlled (owned) but the depositor. This account has the amount of KMD deposited and USD issued. At the moment of deposit, there will still be 20% equity left. Let us start with 1000 KMD deposit, $1.5 per KMD -> 800 KMD converted to 1200 USD into depositor pubkey and the account of (1000 KMD, -1200 USD) = 200 KMD or $300 equity.
|
||||
|
||||
Now it becomes easy for the bull market case, which is to allow (for a fee like 1%) issuance of more USD as the equity increases, so let us imagine KMD at $10:
|
||||
|
||||
(1000 KMD, -1200 USD, 200KMD reserve) -> $2000 equity, issue 80% -> $1600 using 160 KMD
|
||||
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve)
|
||||
|
||||
we have $2800 USD in circulation, 40 KMD reserve left against $10000 marketcap of the original deposit. It it easy to see that there are never any problems with lack of KMD to redeem the issued USD in a world where prices only go up. Total USD issuance can be limited by using a decentralized account tracking based on each deposit.
|
||||
|
||||
What is evident though is that with the constantly changing price and the various times that all the various deposits issue USD, the global reserves are something that will be hard to predict and in fact needs to be specifically tracked. Let us combine all accounts exposure in to a global reserves factor. This factor will control various max/min/ allowed and fee percentages.
|
||||
|
||||
Now we are prepared to handle the price goes down scenario. We can rely on the global equity/reserve ratio to be changing relatively slowly as the reference price is the smooted trustless oracles price. This means there will be enough blocks to adjust the global reserves percentage. What we need to do is liquidate specific positions that have the least reserves.
|
||||
|
||||
What does liquidation mean? It means a specific account will be purchased at below its current value and the KMD withdrawn. Let us assume the price drops to $5:
|
||||
|
||||
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve) 1000 KMD with 2800 USD issued so $2200 reserves. Let us assume it can be liquidated at a 10% discount, so for $2000 in addition to the $2800, the 5000 KMD is able to be withdrawn. This removes 4800 USD coins for 1000 KMD, which is a very low reserve amount of 4%. If a low reserve amount is removed from the system, then the global reserve amount must be improved.
|
||||
|
||||
In addition to the global reserves calculation, there needs to be a trigger percentage that enables positions to be liquidated. We also want to liquidate the worst positions, so in addition to the trigger percentage, there should be a liquidation threshold, and the liquidator would need to find 3 or more better positions that are beyond the liquidation threshold, to be able to liquidate. This will get us to at most 3 accounts that could be liquidated but are not able to, so some method to allow those to also be liquidated. The liquidating nodes are making instant profits, so they should be expected to do whatever blockchain scanning and proving to make things easy for the rest of the nodes.
|
||||
|
||||
One last issue is the normal redemption case where we are not liquidating. In this case, it should be done at the current marketprice, should improve the global reserves metrics and not cause anybody whose position was modified to have cause for complaint. Ideally, there would be an account that has the identical to the global reserve percentage and also at the same price as current marketprice, but this is not realistic, so we need to identify classes of accounts and consider which ones can be fully or partially liquidated to satisfy the constraints.
|
||||
|
||||
looking at our example account:
|
||||
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve)
|
||||
|
||||
OraclePrice is very useful for pegs.
|
||||
what sort of non-liquidation withdraw would be acceptable? if the base amount 1000 KMD is reduced along with USD owed, then the reserve status will go up for the account. but that would seem to allow extra USD to be able to be issued. there should be no disadvantage from funding a withdraw, but also not any large advantage. it needs to be a neutral event....
|
||||
|
||||
*/
|
||||
One solution is to allow for the chance for any account to be liquidated, but the equity compensated for with a premium based on the account reserves. So in the above case, a premium of 5% on the 40KMD reserve is paid to liquidate its account. Instead of 5% premium, a lower 1% can be done if based on the MAX(correlated[daywindow],smoothed) so we get something that is close to the current marketprice. To prevent people taking advantage of the slowness of the smoothed price to adjust, there would need to be a one day delay in the withdraw.
|
||||
|
||||
From a practical sense, it seems a day is a long time, so maybe having a way to pay a premium like 10%, or wait a day to get the MAX(correlated[daywindow],smoothed) price. This price "jumping" might also be taken advantage of in the deposit side, so similar to prices CC it seems good to have the MAX(correlated[daywindow],smoothed) method.
|
||||
|
||||
Now, we have a decentralized mechanism to handle the price going lower! Combined with the fully decentralized method new USD coins are issued, makes this argubably the first decentralized blockchain that is both backed and pegged. There is the reliance on the gateways CC multisig signers, so there is a fundamental federated trust for chains without intrinsic value.
|
||||
|
||||
Also, notice that the flexibly syntax of prices CC allows to define pegs easily for virtually any type of synthetic, and all the ECB fiats can easily get a backed and pegged coin.
|
||||
|
||||
Let us now consider how to enforce a peg onto a specific gateways CC token. If this can also be achieved, then a full DEX for all the different gateways CC supported coins can be created onto a single fiat denominated chain.
|
||||
|
||||
I think just having a pegscreate rpc call that binds an existing gateways create to a price CC syntax price will be almost enough to support this. Let us assume a USD stablechain and we have a BTC token, then pegscreate <btc gateways txid> "BTCUSD, 1"
|
||||
that will specify using the BTCUSD price, so now we need to create a <txid> based way to do tokenbid/tokenask. For a <txid> based price, the smoothed price is substituted.
|
||||
|
||||
There is the issue of the one day delay, so it might make sense to allow specific bid/ask to be based on some simple combinations of the three possible prices. it might even be possible to go a bit overboard and make a forth like syntax to define the dynamic price for a bid, which maybe at times wont be valid, like it is only valid if the three prices are within 1% of each other. But all that seems over complex and for initial release it can just use the mined, correlated or smoothed price, with some specified percentage offset
|
||||
|
||||
Implementation notes:
|
||||
make sure that fees and markers that can be sent to an unspendable address are sent to: RNdqHx26GWy9bk8MtmH1UiXjQcXE4RKK2P, this is the address for BOTS
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// start of consensus code
|
||||
|
||||
@@ -82,7 +137,7 @@ bool PegsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
bool PegsValidate(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);
|
||||
return eval->Invalid("no validation yet");
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
@@ -126,7 +181,7 @@ int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe
|
||||
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);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -134,7 +189,7 @@ int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe
|
||||
// no need to prevent dup
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsPegsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( (nValue= IsPegsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -203,7 +203,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
|
||||
else
|
||||
{
|
||||
txid = tx.GetHash();
|
||||
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
|
||||
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
|
||||
{
|
||||
if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find fundingtxid");
|
||||
@@ -255,15 +255,23 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
|
||||
return eval->Invalid("unexpected normal vin for unlock");
|
||||
}
|
||||
if ( numvouts == 2 && numvins == 1 )
|
||||
if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) )
|
||||
return eval->Invalid("txfee is too high");
|
||||
amount = vinTx.vout[0].nValue;
|
||||
reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit);
|
||||
if ( reward == 0 )
|
||||
return eval->Invalid("no eligible rewards");
|
||||
if ( numvins == 1 && tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
{
|
||||
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
return eval->Invalid("unlock recover tx vout.0 is not normal output");
|
||||
if ( tx.vout[1].nValue != 10000 )
|
||||
return eval->Invalid("wrong marker vout value");
|
||||
else if ( tx.vout[1].scriptPubKey != tx.vout[0].scriptPubKey )
|
||||
return eval->Invalid("unlock recover tx vout.1 mismatched scriptPubKey");
|
||||
else if ( tx.vout[0].scriptPubKey != vinTx.vout[1].scriptPubKey )
|
||||
return eval->Invalid("unlock recover tx vout.0 mismatched scriptPubKey");
|
||||
else if ( tx.vout[0].nValue > vinTx.vout[0].nValue )
|
||||
return eval->Invalid("unlock recover tx vout.0 mismatched amounts");
|
||||
else if ( tx.vout[1].nValue > 0 )
|
||||
else if ( tx.vout[2].nValue > 0 )
|
||||
return eval->Invalid("unlock recover tx vout.1 nonz amount");
|
||||
else return(true);
|
||||
}
|
||||
@@ -277,8 +285,6 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
|
||||
return eval->Invalid("unlock tx vout.1 is CC output");
|
||||
else if ( tx.vout[1].scriptPubKey != vinTx.vout[1].scriptPubKey )
|
||||
return eval->Invalid("unlock tx vout.1 mismatched scriptPubKey");
|
||||
amount = vinTx.vout[0].nValue;
|
||||
reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit);
|
||||
if ( RewardsExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue,sbits,fundingtxid) == 0 )
|
||||
return false;
|
||||
else if ( tx.vout[1].nValue > amount+reward )
|
||||
@@ -310,7 +316,7 @@ static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t r
|
||||
if ( tx.vout.size() > 0 && tx.vout[0].nValue >= needed )
|
||||
{
|
||||
const uint256 &hash = tx.GetHash();
|
||||
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(hash,0) == 0 )
|
||||
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,hash,0) == 0 )
|
||||
{
|
||||
if ( (funcid= DecodeRewardsOpRet(hash,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) == 'U' && sbits == refsbits && fundingtxid == reffundingtxid )
|
||||
{
|
||||
@@ -332,8 +338,12 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont
|
||||
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+1);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
if ( maxinputs > CC_MAXVINS )
|
||||
maxinputs = CC_MAXVINS;
|
||||
if ( maxinputs > 0 )
|
||||
threshold = total/maxinputs;
|
||||
else threshold = total;
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -346,7 +356,7 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont
|
||||
break;
|
||||
if ( j != mtx.vin.size() )
|
||||
continue;
|
||||
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
|
||||
{
|
||||
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
|
||||
{
|
||||
@@ -393,7 +403,7 @@ int64_t RewardsPlanFunds(uint64_t &lockedfunds,uint64_t refsbits,struct CCcontra
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
lockedfunds = 0;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
SetCCunspents(unspentOutputs,coinaddr,true);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -423,7 +433,7 @@ bool RewardsPlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey rewa
|
||||
char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
GetCCaddress(cp,CCaddr,rewardspk);
|
||||
SetCCtxids(txids,CCaddr);
|
||||
SetCCtxids(txids,CCaddr,true);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
|
||||
{
|
||||
//int height = it->first.blockHeight;
|
||||
@@ -483,7 +493,7 @@ UniValue RewardsList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; char str[65];
|
||||
cp = CCinit(&C,EVAL_REWARDS);
|
||||
SetCCtxids(addressIndex,cp->normaladdr);
|
||||
SetCCtxids(addressIndex,cp->normaladdr,false);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -640,7 +650,7 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
|
||||
else
|
||||
{
|
||||
GetCCaddress(cp,coinaddr,rewardspk);
|
||||
if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
|
||||
if ( (amount= CCutxovalue(coinaddr,locktxid,0,1)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
|
||||
CCerror = "locktxid/v0 is spent";
|
||||
@@ -677,8 +687,7 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
|
||||
}
|
||||
else
|
||||
{
|
||||
firstmtx.vout.push_back(CTxOut(amount-txfee,scriptPubKey));
|
||||
//CCerror = "cant find enough rewards inputs";
|
||||
firstmtx.vout.push_back(CTxOut(amount-txfee*2,scriptPubKey));
|
||||
fprintf(stderr,"not enough rewards funds to payout %.8f, recover mode tx\n",(double)(reward+txfee)/COIN);
|
||||
return(FinalizeCCTx(-1LL,cp,firstmtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid)));
|
||||
}
|
||||
@@ -703,4 +712,3 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
|
||||
fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
93
src/cc/rogue/LICENSE.TXT
Normal file
93
src/cc/rogue/LICENSE.TXT
Normal file
@@ -0,0 +1,93 @@
|
||||
Rogue: Exploring the Dungeons of Doom
|
||||
Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name(s) of the author(s) nor the names of other contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
===========================================================================
|
||||
|
||||
Portions of this software (state.c, mdport.c) are based on the work
|
||||
of Nicholas J. Kisseberth. Used under license:
|
||||
|
||||
Copyright (C) 1999, 2000, 2005 Nicholas J. Kisseberth
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name(s) of the author(s) nor the names of other contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
===========================================================================
|
||||
|
||||
Portions of this software (xcrypt.c) are based on the work
|
||||
of David Burren. Used under license:
|
||||
|
||||
FreeSec: libcrypt
|
||||
|
||||
Copyright (C) 1994 David Burren
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name(s) of the author(s) nor the names of other contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
222
src/cc/rogue/Makefile.in
Normal file
222
src/cc/rogue/Makefile.in
Normal file
@@ -0,0 +1,222 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Makefile for rogue
|
||||
#
|
||||
# Rogue: Exploring the Dungeons of Doom
|
||||
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
# All rights reserved.
|
||||
#
|
||||
# See the file LICENSE.TXT for full copyright and licensing information.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# Site configuration occurs beneath this comment
|
||||
# Typically ./configure (autoconf tools) configures this section
|
||||
# This section could be manually configured if autoconf/configure fails
|
||||
###############################################################################
|
||||
|
||||
DISTNAME=@PACKAGE_TARNAME@@PACKAGE_VERSION@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@-@PACKAGE_VERSION@
|
||||
PROGRAM=@PROGRAM@
|
||||
|
||||
O=o
|
||||
|
||||
#CC=gcc
|
||||
CC = @CC@
|
||||
|
||||
#CFLAGS=-O2
|
||||
CFLAGS= @CFLAGS@ -fPIC
|
||||
|
||||
LIBS=-lcurses -lcurl
|
||||
#LIBS = @LIBS@
|
||||
|
||||
#RM=rm -f
|
||||
RM = rm -f
|
||||
|
||||
#GROFF=groff
|
||||
GROFF = @GROFF@
|
||||
|
||||
#NROFF=nroff
|
||||
NROFF = @NROFF@
|
||||
|
||||
#TBL=tbl
|
||||
TBL = @TBL@
|
||||
|
||||
#COLCRT=colcrt
|
||||
COLCRT = @COLCRT@
|
||||
|
||||
#SED=sed
|
||||
SED = @SED@
|
||||
|
||||
#SCOREFILE=rogue54.scr
|
||||
SCOREFILE = @SCOREFILE@
|
||||
|
||||
#LOCKFILE=rogue54.lck
|
||||
LOCKFILE = @LOCKFILE@
|
||||
|
||||
#GROUPOWNER=games
|
||||
GROUPOWNER = @GROUPOWNER@
|
||||
|
||||
#CPPFLAGS=-DHAVE_CONFIG_H
|
||||
CPPFLAGS =@DEFS@ @CPPFLAGS@
|
||||
|
||||
#DISTFILE = $(PROGRAM)
|
||||
DISTFILE = $(DISTNAME)-@TARGET@
|
||||
|
||||
INSTALL=./install-sh
|
||||
|
||||
#INSTGROUP=-g games
|
||||
INSTGROUP=
|
||||
#INSTOWNER=-u root
|
||||
INSTOWNER=
|
||||
|
||||
CHGRP=chgrp
|
||||
|
||||
MKDIR=mkdir
|
||||
|
||||
TOUCH=touch
|
||||
|
||||
RMDIR=rmdir
|
||||
|
||||
CHMOD=chmod
|
||||
|
||||
DESTDIR=
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
datarootdir=@datarootdir@
|
||||
datadir=@datadir@
|
||||
bindir=@bindir@
|
||||
mandir=@mandir@
|
||||
docdir=@docdir@
|
||||
man6dir = $(mandir)/man6
|
||||
|
||||
###############################################################################
|
||||
# Site configuration occurs above this comment
|
||||
# It should not be necessary to change anything below this comment
|
||||
###############################################################################
|
||||
|
||||
HDRS = rogue.h extern.h score.h
|
||||
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
|
||||
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
|
||||
mach_dep.$(O) rogue.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
|
||||
move.$(O) new_level.$(O)
|
||||
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
|
||||
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
|
||||
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
|
||||
OBJS = main.$(O) $(OBJS1) $(OBJS2)
|
||||
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
|
||||
daemons.c fight.c init.c io.c list.c mach_dep.c \
|
||||
main.c mdport.c misc.c monsters.c move.c new_level.c \
|
||||
options.c pack.c passages.c potions.c rings.c rip.c \
|
||||
rooms.c save.c scrolls.c state.c sticks.c things.c \
|
||||
weapons.c wizard.c xcrypt.c
|
||||
MISC_C = findpw.c scedit.c scmisc.c
|
||||
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
|
||||
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
|
||||
$(PROGRAM).6
|
||||
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
|
||||
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
|
||||
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
|
||||
rogue.png rogue.desktop
|
||||
|
||||
.SUFFIXES: .obj
|
||||
|
||||
.c.obj:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) /c $*.c
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c
|
||||
|
||||
#$(RM) rogue.so ; $(CC) -shared -o rogue.so cursesd.c $(OBJS1) $(OBJS2); $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
|
||||
|
||||
$(PROGRAM): $(HDRS) $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS1); $(RM) main.$(O) ; $(RM) rogue.so
|
||||
$(RM) $(OBJS2)
|
||||
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe
|
||||
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
|
||||
$(RM) $(DISTNAME)/*
|
||||
-rmdir $(DISTNAME)
|
||||
|
||||
maintainer-clean:
|
||||
$(RM) config.h
|
||||
$(RM) Makefile
|
||||
$(RM) config.status
|
||||
$(RM) -r autom4te.cache
|
||||
$(RM) config.log
|
||||
$(RM) $(PROGRAM).scr $(PROGRAM).lck
|
||||
|
||||
stddocs:
|
||||
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.6.in > rogue.6
|
||||
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.me.in > rogue.me
|
||||
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.html.in > rogue,html
|
||||
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.doc.in > rogue.doc
|
||||
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.cat.in > rogue.cat
|
||||
|
||||
dist.src:
|
||||
$(MAKE) $(MAKEFILE) clean
|
||||
mkdir $(DISTNAME)
|
||||
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
|
||||
tar cf $(DISTNAME)-src.tar $(DISTNAME)
|
||||
gzip -f $(DISTNAME)-src.tar
|
||||
rm -fr $(DISTNAME)
|
||||
|
||||
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
|
||||
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
|
||||
|
||||
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
|
||||
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
|
||||
|
||||
scmisc.o scedit.o:
|
||||
$(CC) -O -c $(SF) $*.c
|
||||
|
||||
$(PROGRAM).doc: rogue.me
|
||||
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
|
||||
$(GROFF) -P-c -t -me -Tascii rogue.me | $(SED) -e 's/.\x08//g' > $(PROGRAM).doc ;\
|
||||
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
|
||||
tbl rogue.me | $(NROFF) -me | colcrt - > $(PROGRAM).doc ;\
|
||||
fi
|
||||
|
||||
$(PROGRAM).cat: rogue.6
|
||||
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
|
||||
$(GROFF) -Tascii -man rogue.6 | $(SED) -e 's/.\x08//g' > $(PROGRAM).cat ;\
|
||||
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
|
||||
$(NROFF) -man rogue.6 | $(COLCRT) - > $(PROGRAM).cat ;\
|
||||
fi
|
||||
|
||||
dist: clean $(PROGRAM)
|
||||
tar cf $(DISTFILE).tar $(PROGRAM) LICENSE.TXT $(DOCS)
|
||||
gzip -f $(DISTFILE).tar
|
||||
|
||||
install: $(PROGRAM)
|
||||
-$(TOUCH) test
|
||||
-if test ! -f $(DESTDIR)$(SCOREFILE) ; then $(INSTALL) -m 0664 test $(DESTDIR)$(SCOREFILE) ; fi
|
||||
-$(INSTALL) -m 0755 $(PROGRAM) $(DESTDIR)$(bindir)/$(PROGRAM)
|
||||
-if test "x$(GROUPOWNER)" != "x" ; then \
|
||||
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(SCOREFILE) ; \
|
||||
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(bindir)/$(PROGRAM) ; \
|
||||
$(CHMOD) 02755 $(DESTDIR)$(bindir)/$(PROGRAM) ; \
|
||||
$(CHMOD) 0464 $(DESTDIR)$(SCOREFILE) ; \
|
||||
fi
|
||||
-if test -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(man6dir)/$(PROGRAM).6 ; fi
|
||||
-if test ! -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(mandir)/$(PROGRAM).6 ; fi
|
||||
-$(INSTALL) -m 0644 rogue.doc $(DESTDIR)$(docdir)/$(PROGRAM).doc
|
||||
-$(INSTALL) -m 0644 rogue.html $(DESTDIR)$(docdir)/$(PROGRAM).html
|
||||
-$(INSTALL) -m 0644 rogue.cat $(DESTDIR)$(docdir)/$(PROGRAM).cat
|
||||
-$(INSTALL) -m 0644 LICENSE.TXT $(DESTDIR)$(docdir)/LICENSE.TXT
|
||||
-$(INSTALL) -m 0644 rogue.me $(DESTDIR)$(docdir)/$(PROGRAM).me
|
||||
-if test ! -f $(DESTDIR)$(LOCKFILE) ; then $(INSTALL) -m 0666 test $(DESTDIR)$(LOCKFILE) ; $(RM) $(DESTDIR)$(LOCKFILE) ; fi
|
||||
-$(RM) test
|
||||
|
||||
uninstall:
|
||||
-$(RM) $(DESTDIR)$(bindir)/$(PROGRAM)
|
||||
-$(RM) $(DESTDIR)$(man6dir)/$(PROGRAM).6
|
||||
-$(RM) $(DESTDIR)$(docdir)$(PROGRAM)/$(PROGRAM).doc
|
||||
-$(RM) $(DESTDIR)$(LOCKFILE)
|
||||
-$(RMDIR) $(DESTDIR)$(docdir)$(PROGRAM)
|
||||
|
||||
reinstall: uninstall install
|
||||
158
src/cc/rogue/Makefile.std
Executable file
158
src/cc/rogue/Makefile.std
Executable file
@@ -0,0 +1,158 @@
|
||||
#
|
||||
# Makefile for rogue
|
||||
# @(#)Makefile 4.21 (Berkeley) 02/04/99
|
||||
#
|
||||
# Rogue: Exploring the Dungeons of Doom
|
||||
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
# All rights reserved.
|
||||
#
|
||||
# See the file LICENSE.TXT for full copyright and licensing information.
|
||||
#
|
||||
|
||||
DISTNAME = rogue5.4.4
|
||||
PROGRAM = rogue54
|
||||
O = o
|
||||
HDRS = rogue.h extern.h score.h
|
||||
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
|
||||
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
|
||||
mach_dep.$(O) main.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
|
||||
move.$(O) new_level.$(O)
|
||||
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
|
||||
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
|
||||
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
|
||||
OBJS = $(OBJS1) $(OBJS2)
|
||||
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
|
||||
daemons.c fight.c init.c io.c list.c mach_dep.c \
|
||||
main.c mdport.c misc.c monsters.c move.c new_level.c \
|
||||
options.c pack.c passages.c potions.c rings.c rip.c \
|
||||
rooms.c save.c scrolls.c state.c sticks.c things.c \
|
||||
weapons.c wizard.c xcrypt.c
|
||||
MISC_C = findpw.c scedit.c scmisc.c
|
||||
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
|
||||
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
|
||||
$(PROGRAM).6
|
||||
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
|
||||
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
|
||||
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
|
||||
rogue.png rogue.desktop
|
||||
CC = gcc
|
||||
FEATURES = -DALLSCORES -DSCOREFILE=\"$(SCOREFILE)\" -DLOCKFILE=\"$(LOCKFILE)\"
|
||||
CPPFLAGS =
|
||||
CFLAGS = -O3
|
||||
LDFLAGS =
|
||||
LIBS = -lcurses
|
||||
RM = rm -f
|
||||
MAKEFILE = -f Makefile.std
|
||||
SCOREFILE= $(PROGRAM).scr
|
||||
LOCKFILE = $(PROGRAM).lck
|
||||
OUTFLAG = -o
|
||||
EXE =
|
||||
|
||||
.SUFFIXES: .obj
|
||||
|
||||
.c.obj:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURES) /c $*.c
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURES) -c $*.c
|
||||
|
||||
$(PROGRAM): $(HDRS) $(OBJS) fixdocs
|
||||
$(CC) $(LDFLAGS) $(OBJS) $(LIBS) $(OUTFLAG)$@$(EXE)
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS1)
|
||||
$(RM) $(OBJS2)
|
||||
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe $(PROGRAM).lck
|
||||
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
|
||||
$(RM) $(DISTNAME)/*
|
||||
|
||||
dist.src:
|
||||
$(MAKE) $(MAKEFILE) clean
|
||||
mkdir $(DISTNAME)
|
||||
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
|
||||
tar cf $(DISTNAME)-src.tar $(DISTNAME)
|
||||
gzip -f $(DISTNAME)-src.tar
|
||||
rm -fr $(DISTNAME)
|
||||
|
||||
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
|
||||
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
|
||||
|
||||
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
|
||||
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
|
||||
|
||||
scmisc.o scedit.o:
|
||||
$(CC) -O -c $(SF) $*.c
|
||||
|
||||
doc.nroff:
|
||||
tbl rogue.me | nroff -me | colcrt - > rogue.doc
|
||||
nroff -man rogue.6 | colcrt - > rogue.cat
|
||||
|
||||
doc.groff:
|
||||
groff -P-c -t -me -Tascii rogue.me | sed -e 's/.\x08//g' > rogue.doc
|
||||
groff -man rogue.6 | sed -e 's/.\x08//g' > rogue.cat
|
||||
|
||||
fixdocs:
|
||||
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.6.in > $(PROGRAM).6
|
||||
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.me.in > $(PROGRAM).me
|
||||
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.html.in > $(PROGRAM).html
|
||||
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.doc.in > $(PROGRAM).doc
|
||||
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.cat.in > $(PROGRAM).cat
|
||||
|
||||
dist.irix:
|
||||
$(MAKE) $(MAKEFILE) clean
|
||||
$(MAKE) $(MAKEFILE) CC=cc $(PROGRAM)
|
||||
tar cf $(DISTNAME)-irix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
|
||||
gzip -f $(DISTNAME)-irix.tar
|
||||
|
||||
dist.aix:
|
||||
$(MAKE) $(MAKEFILE) clean
|
||||
$(MAKE) $(MAKEFILE) CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM)
|
||||
tar cf $(DISTNAME)-aix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
|
||||
gzip -f $(DISTNAME)-aix.tar
|
||||
|
||||
dist.linux:
|
||||
$(MAKE) $(MAKEFILE) clean
|
||||
$(MAKE) $(MAKEFILE) $(PROGRAM)
|
||||
tar cf $(DISTNAME)-linux.tar $(PROGRAM) LICENSE.TXT $(DOCS)
|
||||
gzip -f $(DISTNAME)-linux.tar
|
||||
|
||||
dist.interix:
|
||||
@$(MAKE) $(MAKEFILE) clean
|
||||
@$(MAKE) $(MAKEFILE) CFLAGS="-ansi" $(PROGRAM)
|
||||
tar cf $(DISTNAME)-interix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
|
||||
gzip -f $(DISTNAME)-interix.tar
|
||||
|
||||
dist.cygwin:
|
||||
@$(MAKE) $(MAKEFILE) --no-print-directory clean
|
||||
@$(MAKE) $(MAKEFILE) CPPFLAGS="-I/usr/include/ncurses" --no-print-directory $(PROGRAM)
|
||||
tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe LICENSE.TXT $(DOCS)
|
||||
gzip -f $(DISTNAME)-cygwin.tar
|
||||
|
||||
#
|
||||
# Use MINGW32-MAKE to build this target
|
||||
#
|
||||
dist.mingw32:
|
||||
@$(MAKE) $(MAKEFILE) --no-print-directory RM="cmd /c del" clean
|
||||
@$(MAKE) $(MAKEFILE) --no-print-directory CPPFLAGS="-I../pdcurses" LIBS="../pdcurses/pdcurses.a" $(PROGRAM)
|
||||
cmd /c del $(DISTNAME)-mingw32.zip
|
||||
zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)
|
||||
|
||||
dist.djgpp:
|
||||
@$(MAKE) $(MAKEFILE) --no-print-directory clean
|
||||
@$(MAKE) $(MAKEFILE) --no-print-directory LDFLAGS="-L$(DJDIR)/LIB" \
|
||||
LIBS="-lpdcurses" $(PROGRAM)
|
||||
rm -f $(DISTNAME)-djgpp.zip
|
||||
zip $(DISTNAME)-djgpp.zip $(PROGRAM) LICENSE.TXT $(DOCS)
|
||||
|
||||
#
|
||||
# Use NMAKE to build this targer
|
||||
#
|
||||
|
||||
dist.win32:
|
||||
@$(MAKE) $(MAKEFILE) /NOLOGO O="obj" RM="-del" clean
|
||||
@$(MAKE) $(MAKEFILE) /NOLOGO O="obj" CC="CL" \
|
||||
LIBS="..\pdcurses\pdcurses.lib shell32.lib user32.lib Advapi32.lib" \
|
||||
EXE=".exe" OUTFLAG="/Fe" CPPFLAGS="-I..\pdcurses" \
|
||||
CFLAGS="-nologo -Ox -wd4033 -wd4716" $(PROGRAM)
|
||||
-del $(DISTNAME)-win32.zip
|
||||
zip $(DISTNAME)-win32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)
|
||||
222
src/cc/rogue/Makefile_win
Normal file
222
src/cc/rogue/Makefile_win
Normal file
@@ -0,0 +1,222 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Makefile for rogue
|
||||
#
|
||||
# Rogue: Exploring the Dungeons of Doom
|
||||
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
# All rights reserved.
|
||||
#
|
||||
# See the file LICENSE.TXT for full copyright and licensing information.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# Site configuration occurs beneath this comment
|
||||
# Typically ./configure (autoconf tools) configures this section
|
||||
# This section could be manually configured if autoconf/configure fails
|
||||
###############################################################################
|
||||
|
||||
DISTNAME=rogue5.4.4
|
||||
PACKAGE_TARNAME = rogue-5.4.4
|
||||
PROGRAM=rogue
|
||||
|
||||
O=o
|
||||
|
||||
#CC=gcc
|
||||
CC = x86_64-w64-mingw32-gcc
|
||||
|
||||
#CFLAGS=-O2
|
||||
CFLAGS= -g -O2 -I./x86_64-w64-mingw32/include -I./x86_64-w64-mingw32/include/ncursesw
|
||||
|
||||
#LIBS=-lcurses
|
||||
LIBS = -L./x86_64-w64-mingw32/lib -lncursesw -lcurl
|
||||
|
||||
#RM=rm -f
|
||||
RM = rm -f
|
||||
|
||||
#GROFF=groff
|
||||
GROFF = groff
|
||||
|
||||
#NROFF=nroff
|
||||
NROFF = nroff
|
||||
|
||||
#TBL=tbl
|
||||
TBL = tbl
|
||||
|
||||
#COLCRT=colcrt
|
||||
COLCRT = colcrt
|
||||
|
||||
#SED=sed
|
||||
SED = sed
|
||||
|
||||
#SCOREFILE=rogue54.scr
|
||||
SCOREFILE = rogue.scr
|
||||
|
||||
#LOCKFILE=rogue54.lck
|
||||
LOCKFILE = rogue.lck
|
||||
|
||||
#GROUPOWNER=games
|
||||
GROUPOWNER =
|
||||
|
||||
#CPPFLAGS=-DHAVE_CONFIG_H
|
||||
CPPFLAGS =-DHAVE_CONFIG_H
|
||||
|
||||
#DISTFILE = $(PROGRAM)
|
||||
DISTFILE = $(DISTNAME)-x86_64-w64-mingw32
|
||||
|
||||
INSTALL=./install-sh
|
||||
|
||||
#INSTGROUP=-g games
|
||||
INSTGROUP=
|
||||
#INSTOWNER=-u root
|
||||
INSTOWNER=
|
||||
|
||||
CHGRP=chgrp
|
||||
|
||||
MKDIR=mkdir
|
||||
|
||||
TOUCH=touch
|
||||
|
||||
RMDIR=rmdir
|
||||
|
||||
CHMOD=chmod
|
||||
|
||||
DESTDIR=
|
||||
|
||||
prefix=/usr/local
|
||||
exec_prefix=${prefix}
|
||||
datarootdir=${prefix}/share
|
||||
datadir=${datarootdir}
|
||||
bindir=${exec_prefix}/bin
|
||||
mandir=${datarootdir}/man
|
||||
docdir=${datarootdir}/doc/${PACKAGE_TARNAME}
|
||||
man6dir = $(mandir)/man6
|
||||
|
||||
###############################################################################
|
||||
# Site configuration occurs above this comment
|
||||
# It should not be necessary to change anything below this comment
|
||||
###############################################################################
|
||||
|
||||
HDRS = rogue.h extern.h score.h
|
||||
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
|
||||
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
|
||||
mach_dep.$(O) rogue.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
|
||||
move.$(O) new_level.$(O)
|
||||
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
|
||||
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
|
||||
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
|
||||
OBJS = main.$(O) $(OBJS1) $(OBJS2)
|
||||
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
|
||||
daemons.c fight.c init.c io.c list.c mach_dep.c \
|
||||
main.c mdport.c misc.c monsters.c move.c new_level.c \
|
||||
options.c pack.c passages.c potions.c rings.c rip.c \
|
||||
rooms.c save.c scrolls.c state.c sticks.c things.c \
|
||||
weapons.c wizard.c xcrypt.c
|
||||
MISC_C = findpw.c scedit.c scmisc.c
|
||||
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
|
||||
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
|
||||
$(PROGRAM).6
|
||||
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
|
||||
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
|
||||
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
|
||||
rogue.png rogue.desktop
|
||||
|
||||
.SUFFIXES: .obj
|
||||
|
||||
.c.obj:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) /c $*.c
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c
|
||||
|
||||
#$(RM) rogue.so ; $(CC) -shared -o rogue.so cursesd.c $(OBJS1) $(OBJS2); $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
|
||||
|
||||
$(PROGRAM): $(HDRS) $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@.exe
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS1); $(RM) main.$(O) ; $(RM) rogue.so
|
||||
$(RM) $(OBJS2)
|
||||
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe
|
||||
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
|
||||
$(RM) $(DISTNAME)/*
|
||||
-rmdir $(DISTNAME)
|
||||
|
||||
maintainer-clean:
|
||||
$(RM) config.h
|
||||
$(RM) Makefile
|
||||
$(RM) config.status
|
||||
$(RM) -r autom4te.cache
|
||||
$(RM) config.log
|
||||
$(RM) $(PROGRAM).scr $(PROGRAM).lck
|
||||
|
||||
stddocs:
|
||||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.6.in > rogue.6
|
||||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.me.in > rogue.me
|
||||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.html.in > rogue,html
|
||||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.doc.in > rogue.doc
|
||||
sed -e 's/rogue/rogue/' -e 's/rogue.scr/rogue.scr/' rogue.cat.in > rogue.cat
|
||||
|
||||
dist.src:
|
||||
$(MAKE) $(MAKEFILE) clean
|
||||
mkdir $(DISTNAME)
|
||||
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
|
||||
tar cf $(DISTNAME)-src.tar $(DISTNAME)
|
||||
gzip -f $(DISTNAME)-src.tar
|
||||
rm -fr $(DISTNAME)
|
||||
|
||||
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
|
||||
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
|
||||
|
||||
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
|
||||
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
|
||||
|
||||
scmisc.o scedit.o:
|
||||
$(CC) -O -c $(SF) $*.c
|
||||
|
||||
$(PROGRAM).doc: rogue.me
|
||||
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
|
||||
$(GROFF) -P-c -t -me -Tascii rogue.me | $(SED) -e 's/.\x08//g' > $(PROGRAM).doc ;\
|
||||
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
|
||||
tbl rogue.me | $(NROFF) -me | colcrt - > $(PROGRAM).doc ;\
|
||||
fi
|
||||
|
||||
$(PROGRAM).cat: rogue.6
|
||||
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
|
||||
$(GROFF) -Tascii -man rogue.6 | $(SED) -e 's/.\x08//g' > $(PROGRAM).cat ;\
|
||||
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
|
||||
$(NROFF) -man rogue.6 | $(COLCRT) - > $(PROGRAM).cat ;\
|
||||
fi
|
||||
|
||||
dist: clean $(PROGRAM)
|
||||
tar cf $(DISTFILE).tar $(PROGRAM) LICENSE.TXT $(DOCS)
|
||||
gzip -f $(DISTFILE).tar
|
||||
|
||||
install: $(PROGRAM)
|
||||
-$(TOUCH) test
|
||||
-if test ! -f $(DESTDIR)$(SCOREFILE) ; then $(INSTALL) -m 0664 test $(DESTDIR)$(SCOREFILE) ; fi
|
||||
-$(INSTALL) -m 0755 $(PROGRAM) $(DESTDIR)$(bindir)/$(PROGRAM)
|
||||
-if test "x$(GROUPOWNER)" != "x" ; then \
|
||||
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(SCOREFILE) ; \
|
||||
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(bindir)/$(PROGRAM) ; \
|
||||
$(CHMOD) 02755 $(DESTDIR)$(bindir)/$(PROGRAM) ; \
|
||||
$(CHMOD) 0464 $(DESTDIR)$(SCOREFILE) ; \
|
||||
fi
|
||||
-if test -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(man6dir)/$(PROGRAM).6 ; fi
|
||||
-if test ! -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(mandir)/$(PROGRAM).6 ; fi
|
||||
-$(INSTALL) -m 0644 rogue.doc $(DESTDIR)$(docdir)/$(PROGRAM).doc
|
||||
-$(INSTALL) -m 0644 rogue.html $(DESTDIR)$(docdir)/$(PROGRAM).html
|
||||
-$(INSTALL) -m 0644 rogue.cat $(DESTDIR)$(docdir)/$(PROGRAM).cat
|
||||
-$(INSTALL) -m 0644 LICENSE.TXT $(DESTDIR)$(docdir)/LICENSE.TXT
|
||||
-$(INSTALL) -m 0644 rogue.me $(DESTDIR)$(docdir)/$(PROGRAM).me
|
||||
-if test ! -f $(DESTDIR)$(LOCKFILE) ; then $(INSTALL) -m 0666 test $(DESTDIR)$(LOCKFILE) ; $(RM) $(DESTDIR)$(LOCKFILE) ; fi
|
||||
-$(RM) test
|
||||
|
||||
uninstall:
|
||||
-$(RM) $(DESTDIR)$(bindir)/$(PROGRAM)
|
||||
-$(RM) $(DESTDIR)$(man6dir)/$(PROGRAM).6
|
||||
-$(RM) $(DESTDIR)$(docdir)$(PROGRAM)/$(PROGRAM).doc
|
||||
-$(RM) $(DESTDIR)$(LOCKFILE)
|
||||
-$(RMDIR) $(DESTDIR)$(docdir)$(PROGRAM)
|
||||
|
||||
reinstall: uninstall install
|
||||
89
src/cc/rogue/armor.c
Normal file
89
src/cc/rogue/armor.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This file contains misc functions for dealing with armor
|
||||
* @(#)armor.c 4.14 (Berkeley) 02/05/99
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <curses.h>
|
||||
#include "rogue.h"
|
||||
|
||||
/*
|
||||
* wear:
|
||||
* The player wants to wear something, so let him/her put it on.
|
||||
*/
|
||||
void
|
||||
wear(struct rogue_state *rs)
|
||||
{
|
||||
register THING *obj;
|
||||
register char *sp;
|
||||
|
||||
if ((obj = get_item(rs,"wear", ARMOR)) == NULL)
|
||||
return;
|
||||
if (cur_armor != NULL)
|
||||
{
|
||||
addmsg(rs,"you are already wearing some");
|
||||
if (!terse)
|
||||
addmsg(rs,". You'll have to take it off first");
|
||||
endmsg(rs);
|
||||
after = FALSE;
|
||||
return;
|
||||
}
|
||||
if (obj->o_type != ARMOR)
|
||||
{
|
||||
msg(rs,"you can't wear that");
|
||||
return;
|
||||
}
|
||||
waste_time(rs);
|
||||
obj->o_flags |= ISKNOW;
|
||||
sp = inv_name(obj, TRUE);
|
||||
cur_armor = obj;
|
||||
if (!terse)
|
||||
addmsg(rs,"you are now ");
|
||||
msg(rs,"wearing %s", sp);
|
||||
}
|
||||
|
||||
/*
|
||||
* take_off:
|
||||
* Get the armor off of the players back
|
||||
*/
|
||||
void
|
||||
take_off(struct rogue_state *rs)
|
||||
{
|
||||
register THING *obj;
|
||||
|
||||
if ((obj = cur_armor) == NULL)
|
||||
{
|
||||
after = FALSE;
|
||||
if (terse)
|
||||
msg(rs,"not wearing armor");
|
||||
else
|
||||
msg(rs,"you aren't wearing any armor");
|
||||
return;
|
||||
}
|
||||
if (!dropcheck(rs,cur_armor))
|
||||
return;
|
||||
cur_armor = NULL;
|
||||
if (terse)
|
||||
addmsg(rs,"was");
|
||||
else
|
||||
addmsg(rs,"you used to be");
|
||||
msg(rs," wearing %c) %s", obj->o_packch, inv_name(obj, TRUE));
|
||||
}
|
||||
|
||||
/*
|
||||
* waste_time:
|
||||
* Do nothing but let other things happen
|
||||
*/
|
||||
void
|
||||
waste_time(struct rogue_state *rs)
|
||||
{
|
||||
do_daemons(rs,BEFORE);
|
||||
do_fuses(rs,BEFORE);
|
||||
do_daemons(rs,AFTER);
|
||||
do_fuses(rs,AFTER);
|
||||
}
|
||||
541
src/cc/rogue/chase.c
Normal file
541
src/cc/rogue/chase.c
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Code for one creature to chase another
|
||||
*
|
||||
* @(#)chase.c 4.57 (Berkeley) 02/05/99
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <stdlib.h>
|
||||
//#include <curses.h>
|
||||
#include "rogue.h"
|
||||
|
||||
#define DRAGONSHOT 5 /* one chance in DRAGONSHOT that a dragon will flame */
|
||||
|
||||
static coord ch_ret; /* Where chasing takes you */
|
||||
|
||||
/*
|
||||
* runners:
|
||||
* Make all the running monsters move.
|
||||
*/
|
||||
void
|
||||
runners(struct rogue_state *rs,int arg)
|
||||
{
|
||||
register THING *tp;
|
||||
THING *next;
|
||||
bool wastarget;
|
||||
static coord orig_pos;
|
||||
|
||||
for (tp = mlist; tp != NULL; tp = next)
|
||||
{
|
||||
/* remember this in case the monster's "next" is changed */
|
||||
next = next(tp);
|
||||
if (!on(*tp, ISHELD) && on(*tp, ISRUN))
|
||||
{
|
||||
orig_pos = tp->t_pos;
|
||||
wastarget = on(*tp, ISTARGET);
|
||||
if (move_monst(rs,tp) == -1)
|
||||
continue;
|
||||
if (on(*tp, ISFLY) && dist_cp(&hero, &tp->t_pos) >= 3)
|
||||
move_monst(rs,tp);
|
||||
if (wastarget && !ce(orig_pos, tp->t_pos))
|
||||
{
|
||||
tp->t_flags &= ~ISTARGET;
|
||||
to_death = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (has_hit)
|
||||
{
|
||||
endmsg(rs);
|
||||
has_hit = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* move_monst:
|
||||
* Execute a single turn of running for a monster
|
||||
*/
|
||||
int
|
||||
move_monst(struct rogue_state *rs,THING *tp)
|
||||
{
|
||||
if (!on(*tp, ISSLOW) || tp->t_turn)
|
||||
if (do_chase(rs,tp) == -1)
|
||||
return(-1);
|
||||
if (on(*tp, ISHASTE))
|
||||
if (do_chase(rs,tp) == -1)
|
||||
return(-1);
|
||||
tp->t_turn ^= TRUE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* relocate:
|
||||
* Make the monster's new location be the specified one, updating
|
||||
* all the relevant state.
|
||||
*/
|
||||
void
|
||||
relocate(struct rogue_state *rs,THING *th, coord *new_loc)
|
||||
{
|
||||
struct room *oroom;
|
||||
|
||||
if (!ce(*new_loc, th->t_pos))
|
||||
{
|
||||
mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
|
||||
th->t_room = roomin(rs,new_loc);
|
||||
set_oldch(th, new_loc);
|
||||
oroom = th->t_room;
|
||||
moat(th->t_pos.y, th->t_pos.x) = NULL;
|
||||
|
||||
if (oroom != th->t_room)
|
||||
th->t_dest = find_dest(rs,th);
|
||||
th->t_pos = *new_loc;
|
||||
moat(new_loc->y, new_loc->x) = th;
|
||||
}
|
||||
move(new_loc->y, new_loc->x);
|
||||
if (see_monst(th))
|
||||
addch(th->t_disguise);
|
||||
else if (on(player, SEEMONST))
|
||||
{
|
||||
standout();
|
||||
addch(th->t_type);
|
||||
standend();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* do_chase:
|
||||
* Make one thing chase another.
|
||||
*/
|
||||
int
|
||||
do_chase(struct rogue_state *rs,THING *th)
|
||||
{
|
||||
register coord *cp;
|
||||
register struct room *rer, *ree; /* room of chaser, room of chasee */
|
||||
register int mindist = 32767, curdist;
|
||||
register bool stoprun = FALSE; /* TRUE means we are there */
|
||||
register bool door;
|
||||
register THING *obj;
|
||||
static coord DEST; /* Temporary destination for chaser */
|
||||
|
||||
rer = th->t_room; /* Find room of chaser */
|
||||
if (on(*th, ISGREED) && rer->r_goldval == 0)
|
||||
th->t_dest = &hero; /* If gold has been taken, run after hero */
|
||||
if (th->t_dest == &hero) /* Find room of chasee */
|
||||
ree = proom;
|
||||
else
|
||||
ree = roomin(rs,th->t_dest);
|
||||
/*
|
||||
* We don't count doors as inside rooms for this routine
|
||||
*/
|
||||
door = (chat(th->t_pos.y, th->t_pos.x) == DOOR);
|
||||
/*
|
||||
* If the object of our desire is in a different room,
|
||||
* and we are not in a corridor, run to the door nearest to
|
||||
* our goal.
|
||||
*/
|
||||
over:
|
||||
if (rer != ree)
|
||||
{
|
||||
for (cp = rer->r_exit; cp < &rer->r_exit[rer->r_nexits]; cp++)
|
||||
{
|
||||
curdist = dist_cp(th->t_dest, cp);
|
||||
if (curdist < mindist)
|
||||
{
|
||||
DEST = *cp;
|
||||
mindist = curdist;
|
||||
}
|
||||
}
|
||||
if (door)
|
||||
{
|
||||
rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM];
|
||||
door = FALSE;
|
||||
goto over;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEST = *th->t_dest;
|
||||
/*
|
||||
* For dragons check and see if (a) the hero is on a straight
|
||||
* line from it, and (b) that it is within shooting distance,
|
||||
* but outside of striking range.
|
||||
*/
|
||||
if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x
|
||||
|| abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x))
|
||||
&& dist_cp(&th->t_pos, &hero) <= BOLT_LENGTH * BOLT_LENGTH
|
||||
&& !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0)
|
||||
{
|
||||
delta.y = sign(hero.y - th->t_pos.y);
|
||||
delta.x = sign(hero.x - th->t_pos.x);
|
||||
if (has_hit)
|
||||
endmsg(rs);
|
||||
fire_bolt(rs,&th->t_pos, &delta, "flame");
|
||||
running = FALSE;
|
||||
count = 0;
|
||||
quiet = 0;
|
||||
if (to_death && !on(*th, ISTARGET))
|
||||
{
|
||||
to_death = FALSE;
|
||||
kamikaze = FALSE;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This now contains what we want to run to this time
|
||||
* so we run to it. If we hit it we either want to fight it
|
||||
* or stop running
|
||||
*/
|
||||
if (!chase(th, &DEST))
|
||||
{
|
||||
if (ce(DEST, hero))
|
||||
{
|
||||
return( attack(rs,th) );
|
||||
}
|
||||
else if (ce(DEST, *th->t_dest))
|
||||
{
|
||||
for (obj = lvl_obj; obj != NULL; obj = next(obj))
|
||||
if (th->t_dest == &obj->o_pos)
|
||||
{
|
||||
detach(lvl_obj, obj);
|
||||
attach(th->t_pack, obj);
|
||||
chat(obj->o_pos.y, obj->o_pos.x) =
|
||||
(th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR;
|
||||
th->t_dest = find_dest(rs,th);
|
||||
break;
|
||||
}
|
||||
if (th->t_type != 'F')
|
||||
stoprun = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (th->t_type == 'F')
|
||||
return(0);
|
||||
}
|
||||
relocate(rs,th, &ch_ret);
|
||||
/*
|
||||
* And stop running if need be
|
||||
*/
|
||||
if (stoprun && ce(th->t_pos, *(th->t_dest)))
|
||||
th->t_flags &= ~ISRUN;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* set_oldch:
|
||||
* Set the oldch character for the monster
|
||||
*/
|
||||
void
|
||||
set_oldch(THING *tp, coord *cp)
|
||||
{
|
||||
char sch;
|
||||
|
||||
if (ce(tp->t_pos, *cp))
|
||||
return;
|
||||
|
||||
sch = tp->t_oldch;
|
||||
tp->t_oldch = CCHAR( mvinch(cp->y,cp->x) );
|
||||
if (!on(player, ISBLIND))
|
||||
{
|
||||
if ((sch == FLOOR || tp->t_oldch == FLOOR) &&
|
||||
(tp->t_room->r_flags & ISDARK))
|
||||
tp->t_oldch = ' ';
|
||||
else if (dist_cp(cp, &hero) <= LAMPDIST && see_floor)
|
||||
tp->t_oldch = chat(cp->y, cp->x);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* see_monst:
|
||||
* Return TRUE if the hero can see the monster
|
||||
*/
|
||||
bool
|
||||
see_monst(THING *mp)
|
||||
{
|
||||
int y, x;
|
||||
|
||||
if (on(player, ISBLIND))
|
||||
return FALSE;
|
||||
if (on(*mp, ISINVIS) && !on(player, CANSEE))
|
||||
return FALSE;
|
||||
y = mp->t_pos.y;
|
||||
x = mp->t_pos.x;
|
||||
if (dist(y, x, hero.y, hero.x) < LAMPDIST)
|
||||
{
|
||||
if (y != hero.y && x != hero.x &&
|
||||
!step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x)))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
if (mp->t_room != proom)
|
||||
return FALSE;
|
||||
return ((bool)!(mp->t_room->r_flags & ISDARK));
|
||||
}
|
||||
|
||||
/*
|
||||
* runto:
|
||||
* Set a monster running after the hero.
|
||||
*/
|
||||
void
|
||||
runto(struct rogue_state *rs,coord *runner)
|
||||
{
|
||||
register THING *tp;
|
||||
|
||||
/*
|
||||
* If we couldn't find him, something is funny
|
||||
*/
|
||||
#ifdef MASTER
|
||||
if ((tp = moat(runner->y, runner->x)) == NULL)
|
||||
msg(rs,"couldn't find monster in runto at (%d,%d)", runner->y, runner->x);
|
||||
#else
|
||||
tp = moat(runner->y, runner->x);
|
||||
#endif
|
||||
/*
|
||||
* Start the beastie running
|
||||
*/
|
||||
tp->t_flags |= ISRUN;
|
||||
tp->t_flags &= ~ISHELD;
|
||||
tp->t_dest = find_dest(rs,tp);
|
||||
}
|
||||
|
||||
/*
|
||||
* chase:
|
||||
* Find the spot for the chaser(er) to move closer to the
|
||||
* chasee(ee). Returns TRUE if we want to keep on chasing later
|
||||
* FALSE if we reach the goal.
|
||||
*/
|
||||
bool
|
||||
chase(THING *tp, coord *ee)
|
||||
{
|
||||
register THING *obj;
|
||||
register int x, y;
|
||||
register int curdist, thisdist;
|
||||
register coord *er = &tp->t_pos;
|
||||
register char ch;
|
||||
register int plcnt = 1;
|
||||
static coord tryp;
|
||||
|
||||
/*
|
||||
* If the thing is confused, let it move randomly. Invisible
|
||||
* Stalkers are slightly confused all of the time, and bats are
|
||||
* quite confused all the time
|
||||
*/
|
||||
if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'P' && rnd(5) == 0)
|
||||
|| (tp->t_type == 'B' && rnd(2) == 0))
|
||||
{
|
||||
/*
|
||||
* get a valid random move
|
||||
*/
|
||||
ch_ret = *rndmove(tp);
|
||||
curdist = dist_cp(&ch_ret, ee);
|
||||
/*
|
||||
* Small chance that it will become un-confused
|
||||
*/
|
||||
if (rnd(20) == 0)
|
||||
tp->t_flags &= ~ISHUH;
|
||||
}
|
||||
/*
|
||||
* Otherwise, find the empty spot next to the chaser that is
|
||||
* closest to the chasee.
|
||||
*/
|
||||
else
|
||||
{
|
||||
register int ey, ex;
|
||||
/*
|
||||
* This will eventually hold where we move to get closer
|
||||
* If we can't find an empty spot, we stay where we are.
|
||||
*/
|
||||
curdist = dist_cp(er, ee);
|
||||
ch_ret = *er;
|
||||
|
||||
ey = er->y + 1;
|
||||
if (ey >= NUMLINES - 1)
|
||||
ey = NUMLINES - 2;
|
||||
ex = er->x + 1;
|
||||
if (ex >= NUMCOLS)
|
||||
ex = NUMCOLS - 1;
|
||||
|
||||
for (x = er->x - 1; x <= ex; x++)
|
||||
{
|
||||
if (x < 0)
|
||||
continue;
|
||||
tryp.x = x;
|
||||
for (y = er->y - 1; y <= ey; y++)
|
||||
{
|
||||
tryp.y = y;
|
||||
if (!diag_ok(er, &tryp))
|
||||
continue;
|
||||
ch = winat(y, x);
|
||||
if (step_ok(ch))
|
||||
{
|
||||
/*
|
||||
* If it is a scroll, it might be a scare monster scroll
|
||||
* so we need to look it up to see what type it is.
|
||||
*/
|
||||
if (ch == SCROLL)
|
||||
{
|
||||
for (obj = lvl_obj; obj != NULL; obj = next(obj))
|
||||
{
|
||||
if (y == obj->o_pos.y && x == obj->o_pos.x)
|
||||
break;
|
||||
}
|
||||
if (obj != NULL && obj->o_which == S_SCARE)
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* It can also be a Xeroc, which we shouldn't step on
|
||||
*/
|
||||
if ((obj = moat(y, x)) != NULL && obj->t_type == 'X')
|
||||
continue;
|
||||
/*
|
||||
* If we didn't find any scrolls at this place or it
|
||||
* wasn't a scare scroll, then this place counts
|
||||
*/
|
||||
thisdist = dist(y, x, ee->y, ee->x);
|
||||
if (thisdist < curdist)
|
||||
{
|
||||
plcnt = 1;
|
||||
ch_ret = tryp;
|
||||
curdist = thisdist;
|
||||
}
|
||||
else if (thisdist == curdist && rnd(++plcnt) == 0)
|
||||
{
|
||||
ch_ret = tryp;
|
||||
curdist = thisdist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (bool)(curdist != 0 && !ce(ch_ret, hero));
|
||||
}
|
||||
|
||||
/*
|
||||
* roomin:
|
||||
* Find what room some coordinates are in. NULL means they aren't
|
||||
* in any room.
|
||||
*/
|
||||
struct room *
|
||||
roomin(struct rogue_state *rs,coord *cp)
|
||||
{
|
||||
register struct room *rp;
|
||||
register char *fp;
|
||||
|
||||
|
||||
fp = &flat(cp->y, cp->x);
|
||||
if (*fp & F_PASS)
|
||||
return &passages[*fp & F_PNUM];
|
||||
|
||||
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
|
||||
if (cp->x <= rp->r_pos.x + rp->r_max.x && rp->r_pos.x <= cp->x
|
||||
&& cp->y <= rp->r_pos.y + rp->r_max.y && rp->r_pos.y <= cp->y)
|
||||
return rp;
|
||||
|
||||
msg(rs,"in some bizarre place (%d, %d)", unc(*cp));
|
||||
#ifdef MASTER
|
||||
abort();
|
||||
return NULL;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* diag_ok:
|
||||
* Check to see if the move is legal if it is diagonal
|
||||
*/
|
||||
bool
|
||||
diag_ok(coord *sp, coord *ep)
|
||||
{
|
||||
if (ep->x < 0 || ep->x >= NUMCOLS || ep->y <= 0 || ep->y >= NUMLINES - 1)
|
||||
return FALSE;
|
||||
if (ep->x == sp->x || ep->y == sp->y)
|
||||
return TRUE;
|
||||
return (bool)(step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x)));
|
||||
}
|
||||
|
||||
/*
|
||||
* cansee:
|
||||
* Returns true if the hero can see a certain coordinate.
|
||||
*/
|
||||
bool
|
||||
cansee(struct rogue_state *rs,int y, int x)
|
||||
{
|
||||
register struct room *rer;
|
||||
static coord tp;
|
||||
|
||||
if (on(player, ISBLIND))
|
||||
return FALSE;
|
||||
if (dist(y, x, hero.y, hero.x) < LAMPDIST)
|
||||
{
|
||||
if (flat(y, x) & F_PASS)
|
||||
if (y != hero.y && x != hero.x &&
|
||||
!step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x)))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
* We can only see if the hero in the same room as
|
||||
* the coordinate and the room is lit or if it is close.
|
||||
*/
|
||||
tp.y = y;
|
||||
tp.x = x;
|
||||
return (bool)((rer = roomin(rs,&tp)) == proom && !(rer->r_flags & ISDARK));
|
||||
}
|
||||
|
||||
/*
|
||||
* find_dest:
|
||||
* find the proper destination for the monster
|
||||
*/
|
||||
coord *
|
||||
find_dest(struct rogue_state *rs,THING *tp)
|
||||
{
|
||||
register THING *obj;
|
||||
register int prob;
|
||||
|
||||
if ((prob = monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == proom
|
||||
|| see_monst(tp))
|
||||
return &hero;
|
||||
for (obj = lvl_obj; obj != NULL; obj = next(obj))
|
||||
{
|
||||
if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
|
||||
continue;
|
||||
if (roomin(rs,&obj->o_pos) == tp->t_room && rnd(100) < prob)
|
||||
{
|
||||
for (tp = mlist; tp != NULL; tp = next(tp))
|
||||
if (tp->t_dest == &obj->o_pos)
|
||||
break;
|
||||
if (tp == NULL)
|
||||
return &obj->o_pos;
|
||||
}
|
||||
}
|
||||
return &hero;
|
||||
}
|
||||
|
||||
/*
|
||||
* dist:
|
||||
* Calculate the "distance" between to points. Actually,
|
||||
* this calculates d^2, not d, but that's good enough for
|
||||
* our purposes, since it's only used comparitively.
|
||||
*/
|
||||
int
|
||||
dist(int y1, int x1, int y2, int x2)
|
||||
{
|
||||
return ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
||||
}
|
||||
|
||||
/*
|
||||
* dist_cp:
|
||||
* Call dist() with appropriate arguments for coord pointers
|
||||
*/
|
||||
int
|
||||
dist_cp(coord *c1, coord *c2)
|
||||
{
|
||||
return dist(c1->y, c1->x, c2->y, c2->x);
|
||||
}
|
||||
844
src/cc/rogue/command.c
Normal file
844
src/cc/rogue/command.c
Normal file
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
* Read and execute the user commands
|
||||
*
|
||||
* @(#)command.c 4.73 (Berkeley) 08/06/83
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <curses.h>
|
||||
#include "rogue.h"
|
||||
|
||||
/*
|
||||
* command:
|
||||
* Process the user commands
|
||||
*/
|
||||
void
|
||||
command(struct rogue_state *rs)
|
||||
{
|
||||
register char ch;
|
||||
register int ntimes = 1; /* Number of player moves */
|
||||
char *fp;
|
||||
THING *mp;
|
||||
static char countch, direction, newcount = FALSE;
|
||||
if (on(player, ISHASTE))
|
||||
ntimes++;
|
||||
/*
|
||||
* Let the daemons start up
|
||||
*/
|
||||
do_daemons(rs,BEFORE);
|
||||
do_fuses(rs,BEFORE);
|
||||
while (ntimes--)
|
||||
{
|
||||
if ( rs->replaydone != 0 )
|
||||
return;
|
||||
again = FALSE;
|
||||
if (has_hit)
|
||||
{
|
||||
endmsg(rs);
|
||||
has_hit = FALSE;
|
||||
}
|
||||
/*
|
||||
* these are illegal things for the player to be, so if any are
|
||||
* set, someone's been poking in memeory
|
||||
*/
|
||||
if (on(player, ISSLOW|ISGREED|ISINVIS|ISREGEN|ISTARGET))
|
||||
exit(1);
|
||||
|
||||
look(rs,TRUE);
|
||||
if (!running)
|
||||
door_stop = FALSE;
|
||||
status(rs);
|
||||
lastscore = purse;
|
||||
move(hero.y, hero.x);
|
||||
if ( rs->sleeptime != 0 )
|
||||
{
|
||||
if (!((running || count) && jump))
|
||||
refresh(); /* Draw screen */
|
||||
}
|
||||
take = 0;
|
||||
after = TRUE;
|
||||
/*
|
||||
* Read command or continue run
|
||||
*/
|
||||
#ifdef MASTER
|
||||
if (wizard)
|
||||
noscore = TRUE;
|
||||
#endif
|
||||
if (!no_command)
|
||||
{
|
||||
if (running || to_death)
|
||||
ch = runch;
|
||||
else if (count)
|
||||
ch = countch;
|
||||
else
|
||||
{
|
||||
ch = readchar(rs);
|
||||
move_on = FALSE;
|
||||
if (mpos != 0) /* Erase message if its there */
|
||||
msg(rs,"");
|
||||
}
|
||||
}
|
||||
else
|
||||
ch = '.';
|
||||
if (no_command)
|
||||
{
|
||||
if (--no_command == 0)
|
||||
{
|
||||
player.t_flags |= ISRUN;
|
||||
msg(rs,"you can move again");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* check for prefixes
|
||||
*/
|
||||
newcount = FALSE;
|
||||
if (isdigit(ch))
|
||||
{
|
||||
count = 0;
|
||||
newcount = TRUE;
|
||||
while (isdigit(ch))
|
||||
{
|
||||
count = count * 10 + (ch - '0');
|
||||
if (count > 255)
|
||||
count = 255;
|
||||
ch = readchar(rs);
|
||||
}
|
||||
countch = ch;
|
||||
/*
|
||||
* turn off count for commands which don't make sense
|
||||
* to repeat
|
||||
*/
|
||||
if ( rs->guiflag == 0 && rs->replaydone != 0 )
|
||||
ch = 'Q';
|
||||
switch (ch)
|
||||
{
|
||||
case CTRL('B'): case CTRL('H'): case CTRL('J'):
|
||||
case CTRL('K'): case CTRL('L'): case CTRL('N'):
|
||||
case CTRL('U'): case CTRL('Y'):
|
||||
case '.': case 'a': case 'b': case 'h': case 'j':
|
||||
case 'k': case 'l': case 'm': case 'n': case 'q':
|
||||
case 'r': case 's': case 't': case 'u': case 'y':
|
||||
case 'z': case 'B': case 'C': case 'H': case 'I':
|
||||
case 'J': case 'K': case 'L': case 'N': case 'U':
|
||||
case 'Y':
|
||||
#ifdef MASTER
|
||||
case CTRL('D'): case CTRL('A'):
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* execute a command
|
||||
*/
|
||||
if (count && !running)
|
||||
count--;
|
||||
if (ch != 'a' && ch != ESCAPE && !(running || count || to_death))
|
||||
{
|
||||
l_last_comm = last_comm;
|
||||
l_last_dir = last_dir;
|
||||
l_last_pick = last_pick;
|
||||
last_comm = ch;
|
||||
last_dir = '\0';
|
||||
last_pick = NULL;
|
||||
}
|
||||
over:
|
||||
switch (ch)
|
||||
{
|
||||
case ',': {
|
||||
THING *obj = NULL;
|
||||
int found = 0;
|
||||
for (obj = lvl_obj; obj != NULL; obj = next(obj))
|
||||
{
|
||||
if (obj->o_pos.y == hero.y && obj->o_pos.x == hero.x)
|
||||
{
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (levit_check(rs))
|
||||
;
|
||||
else
|
||||
pick_up(rs,(char)obj->o_type);
|
||||
}
|
||||
else {
|
||||
if (!terse)
|
||||
addmsg(rs,"there is ");
|
||||
addmsg(rs,"nothing here");
|
||||
if (!terse)
|
||||
addmsg(rs," to pick up");
|
||||
endmsg(rs);
|
||||
}
|
||||
}
|
||||
when '!': shell(rs);
|
||||
when 'h': do_move(rs,0, -1);
|
||||
when 'j': do_move(rs,1, 0);
|
||||
when 'k': do_move(rs,-1, 0);
|
||||
when 'l': do_move(rs,0, 1);
|
||||
when 'y': do_move(rs,-1, -1);
|
||||
when 'u': do_move(rs,-1, 1);
|
||||
when 'b': do_move(rs,1, -1);
|
||||
when 'n': do_move(rs,1, 1);
|
||||
when 'H': do_run('h');
|
||||
when 'J': do_run('j');
|
||||
when 'K': do_run('k');
|
||||
when 'L': do_run('l');
|
||||
when 'Y': do_run('y');
|
||||
when 'U': do_run('u');
|
||||
when 'B': do_run('b');
|
||||
when 'N': do_run('n');
|
||||
when CTRL('H'): case CTRL('J'): case CTRL('K'): case CTRL('L'):
|
||||
case CTRL('Y'): case CTRL('U'): case CTRL('B'): case CTRL('N'):
|
||||
{
|
||||
if (!on(player, ISBLIND))
|
||||
{
|
||||
door_stop = TRUE;
|
||||
firstmove = TRUE;
|
||||
}
|
||||
if (count && !newcount)
|
||||
ch = direction;
|
||||
else
|
||||
{
|
||||
ch += ('A' - CTRL('A'));
|
||||
direction = ch;
|
||||
}
|
||||
goto over;
|
||||
}
|
||||
when 'F':
|
||||
kamikaze = TRUE;
|
||||
/* FALLTHROUGH */
|
||||
case 'f':
|
||||
if (!get_dir(rs))
|
||||
{
|
||||
after = FALSE;
|
||||
break;
|
||||
}
|
||||
delta.y += hero.y;
|
||||
delta.x += hero.x;
|
||||
if ( ((mp = moat(delta.y, delta.x)) == NULL)
|
||||
|| ((!see_monst(mp)) && !on(player, SEEMONST)))
|
||||
{
|
||||
if (!terse)
|
||||
addmsg(rs,"I see ");
|
||||
msg(rs,"no monster there");
|
||||
after = FALSE;
|
||||
}
|
||||
else if (diag_ok(&hero, &delta))
|
||||
{
|
||||
to_death = TRUE;
|
||||
max_hit = 0;
|
||||
mp->t_flags |= ISTARGET;
|
||||
runch = ch = dir_ch;
|
||||
goto over;
|
||||
}
|
||||
when 't':
|
||||
if (!get_dir(rs))
|
||||
after = FALSE;
|
||||
else
|
||||
missile(rs,delta.y, delta.x);
|
||||
when 'a':
|
||||
if (last_comm == '\0')
|
||||
{
|
||||
msg(rs,"you haven't typed a command yet");
|
||||
after = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = last_comm;
|
||||
again = TRUE;
|
||||
goto over;
|
||||
}
|
||||
case 'q': quaff(rs);
|
||||
break;
|
||||
when 'Q':
|
||||
after = FALSE;
|
||||
q_comm = TRUE;
|
||||
if ( _quit() > 0 )
|
||||
{
|
||||
if ( rs->guiflag != 0 )
|
||||
{
|
||||
if (rs->needflush == 0 )
|
||||
rs->needflush = (uint32_t)time(NULL);
|
||||
rogue_bailout(rs);
|
||||
} else rs->replaydone = (uint32_t)time(NULL);
|
||||
}
|
||||
q_comm = FALSE;
|
||||
return;
|
||||
when 'i': after = FALSE; inventory(rs,pack, 0);
|
||||
when 'I': after = FALSE; picky_inven(rs);
|
||||
when 'd': drop(rs);
|
||||
when 'r': read_scroll(rs);
|
||||
when 'e': eat(rs);
|
||||
when 'w': wield(rs);
|
||||
when 'W': wear(rs);
|
||||
when 'T': take_off(rs);
|
||||
when 'P': ring_on(rs);
|
||||
when 'R': ring_off(rs);
|
||||
when 'o': option(rs); after = FALSE;
|
||||
when 'c': call(rs); after = FALSE;
|
||||
|
||||
when '>': after = FALSE; d_level(rs);
|
||||
if ( rs->guiflag != 0 && rs->needflush == 0 )
|
||||
rs->needflush = (uint32_t)time(NULL);
|
||||
|
||||
when '<': after = FALSE; u_level(rs);
|
||||
if ( rs->guiflag != 0 && rs->needflush == 0 )
|
||||
rs->needflush = (uint32_t)time(NULL);
|
||||
|
||||
when '?': after = FALSE; help(rs);
|
||||
when '/': after = FALSE; identify(rs);
|
||||
when 's': search(rs);
|
||||
when 'z':
|
||||
if (get_dir(rs))
|
||||
do_zap(rs);
|
||||
else
|
||||
after = FALSE;
|
||||
when 'D': after = FALSE; discovered(rs);
|
||||
when CTRL('P'): after = FALSE; msg(rs,huh);
|
||||
when CTRL('R'):
|
||||
after = FALSE;
|
||||
clearok(curscr,TRUE);
|
||||
wrefresh(curscr);
|
||||
when 'v':
|
||||
after = FALSE;
|
||||
msg(rs,"version %s. (mctesq was here)", release);
|
||||
when 'S':
|
||||
after = FALSE;
|
||||
#ifdef STANDALONE
|
||||
save_game(rs);
|
||||
#else
|
||||
msg(rs,"Saving is disabled, use bailout rpc");
|
||||
#endif
|
||||
when '.': ; /* Rest command */
|
||||
when ' ': after = FALSE; /* "Legal" illegal command */
|
||||
when '^':
|
||||
after = FALSE;
|
||||
if (get_dir(rs)) {
|
||||
delta.y += hero.y;
|
||||
delta.x += hero.x;
|
||||
fp = &flat(delta.y, delta.x);
|
||||
if (!terse)
|
||||
addmsg(rs,"You have found ");
|
||||
if (chat(delta.y, delta.x) != TRAP)
|
||||
msg(rs,"no trap there");
|
||||
else if (on(player, ISHALU))
|
||||
msg(rs,(char *)tr_name[rnd(NTRAPS)]);
|
||||
else {
|
||||
msg(rs,(char *)tr_name[*fp & F_TMASK]);
|
||||
*fp |= F_SEEN;
|
||||
}
|
||||
}
|
||||
#ifdef MASTER
|
||||
when '+':
|
||||
after = FALSE;
|
||||
if (wizard)
|
||||
{
|
||||
wizard = FALSE;
|
||||
turn_see(rs,TRUE);
|
||||
msg(rs,"not wizard any more");
|
||||
}
|
||||
else
|
||||
{
|
||||
wizard = passwd();
|
||||
if (wizard)
|
||||
{
|
||||
noscore = TRUE;
|
||||
turn_see(rs,FALSE);
|
||||
msg(rs,"you are suddenly as smart as Ken Arnold in dungeon #%d", dnum);
|
||||
}
|
||||
else
|
||||
msg(rs,"sorry");
|
||||
}
|
||||
#endif
|
||||
when ESCAPE: /* Escape */
|
||||
door_stop = FALSE;
|
||||
count = 0;
|
||||
after = FALSE;
|
||||
again = FALSE;
|
||||
when 'm':
|
||||
move_on = TRUE;
|
||||
if (!get_dir(rs))
|
||||
after = FALSE;
|
||||
else
|
||||
{
|
||||
ch = dir_ch;
|
||||
countch = dir_ch;
|
||||
goto over;
|
||||
}
|
||||
when ')': current(rs,cur_weapon, "wielding", NULL);
|
||||
when ']': current(rs,cur_armor, "wearing", NULL);
|
||||
when '=':
|
||||
current(rs,cur_ring[LEFT], "wearing",
|
||||
terse ? (char *)"(L)" : (char *)"on left hand");
|
||||
current(rs,cur_ring[RIGHT], "wearing",
|
||||
terse ? (char *)"(R)" : (char *)"on right hand");
|
||||
when '@':
|
||||
stat_msg = TRUE;
|
||||
status(rs);
|
||||
stat_msg = FALSE;
|
||||
after = FALSE;
|
||||
otherwise:
|
||||
after = FALSE;
|
||||
#ifdef MASTER
|
||||
if (wizard) switch (ch)
|
||||
{
|
||||
case '|': msg(rs,"@ %d,%d", hero.y, hero.x);
|
||||
when 'C': create_obj();
|
||||
when '$': msg(rs,"inpack = %d", inpack);
|
||||
when CTRL('G'): inventory(rs,lvl_obj, 0);
|
||||
when CTRL('W'): whatis(rs,FALSE, 0);
|
||||
when CTRL('D'): level++; new_level();
|
||||
when CTRL('A'): level--; new_level();
|
||||
when CTRL('F'): show_map();
|
||||
when CTRL('T'): teleport();
|
||||
when CTRL('E'): msg(rs,"food left: %d", food_left);
|
||||
when CTRL('C'): add_pass();
|
||||
when CTRL('X'): turn_see(rs,on(player, SEEMONST));
|
||||
when CTRL('~'):
|
||||
{
|
||||
THING *item;
|
||||
|
||||
if ((item = get_item(rs,"charge", STICK)) != NULL)
|
||||
item->o_charges = 10000;
|
||||
}
|
||||
when CTRL('I'):
|
||||
{
|
||||
int i;
|
||||
THING *obj;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
raise_level(rs);
|
||||
/*
|
||||
* Give him a sword (+1,+1)
|
||||
*/
|
||||
obj = new_item();
|
||||
init_weapon(obj, TWOSWORD);
|
||||
obj->o_hplus = 1;
|
||||
obj->o_dplus = 1;
|
||||
add_pack(rs,obj, TRUE);
|
||||
cur_weapon = obj;
|
||||
/*
|
||||
* And his suit of armor
|
||||
*/
|
||||
obj = new_item();
|
||||
obj->o_type = ARMOR;
|
||||
obj->o_which = PLATE_MAIL;
|
||||
obj->o_arm = -5;
|
||||
obj->o_flags |= ISKNOW;
|
||||
obj->o_count = 1;
|
||||
obj->o_group = 0;
|
||||
cur_armor = obj;
|
||||
add_pack(rs,obj, TRUE);
|
||||
}
|
||||
when '*' :
|
||||
pr_list();
|
||||
otherwise:
|
||||
illcom(rs,ch);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
illcom(rs,ch);
|
||||
}
|
||||
/*
|
||||
* turn off flags if no longer needed
|
||||
*/
|
||||
if (!running)
|
||||
door_stop = FALSE;
|
||||
}
|
||||
/*
|
||||
* If he ran into something to take, let him pick it up.
|
||||
*/
|
||||
if (take != 0)
|
||||
pick_up(rs,take);
|
||||
if (!running)
|
||||
door_stop = FALSE;
|
||||
if (!after)
|
||||
ntimes++;
|
||||
}
|
||||
do_daemons(rs,AFTER);
|
||||
do_fuses(rs,AFTER);
|
||||
if (ISRING(LEFT, R_SEARCH))
|
||||
search(rs);
|
||||
else if (ISRING(LEFT, R_TELEPORT) && rnd(50) == 0)
|
||||
teleport(rs);
|
||||
if (ISRING(RIGHT, R_SEARCH))
|
||||
search(rs);
|
||||
else if (ISRING(RIGHT, R_TELEPORT) && rnd(50) == 0)
|
||||
teleport(rs);
|
||||
}
|
||||
|
||||
/*
|
||||
* illcom:
|
||||
* What to do with an illegal command
|
||||
*/
|
||||
void
|
||||
illcom(struct rogue_state *rs,int ch)
|
||||
{
|
||||
save_msg = FALSE;
|
||||
count = 0;
|
||||
msg(rs,"illegal command '%s'", unctrl(ch));
|
||||
save_msg = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* search:
|
||||
* player gropes about him to find hidden things.
|
||||
*/
|
||||
void
|
||||
search(struct rogue_state *rs)
|
||||
{
|
||||
register int y, x;
|
||||
register char *fp;
|
||||
register int ey, ex;
|
||||
int probinc;
|
||||
bool found;
|
||||
|
||||
ey = hero.y + 1;
|
||||
ex = hero.x + 1;
|
||||
probinc = (on(player, ISHALU) ? 3 : 0);
|
||||
probinc += (on(player, ISBLIND) ? 2 : 0);
|
||||
found = FALSE;
|
||||
for (y = hero.y - 1; y <= ey; y++)
|
||||
for (x = hero.x - 1; x <= ex; x++)
|
||||
{
|
||||
if (y == hero.y && x == hero.x)
|
||||
continue;
|
||||
fp = &flat(y, x);
|
||||
if (!(*fp & F_REAL))
|
||||
switch (chat(y, x))
|
||||
{
|
||||
case '|':
|
||||
case '-':
|
||||
if (rnd(5 + probinc) != 0)
|
||||
break;
|
||||
chat(y, x) = DOOR;
|
||||
msg(rs,"a secret door");
|
||||
foundone:
|
||||
found = TRUE;
|
||||
*fp |= F_REAL;
|
||||
count = FALSE;
|
||||
running = FALSE;
|
||||
break;
|
||||
case FLOOR:
|
||||
if (rnd(2 + probinc) != 0)
|
||||
break;
|
||||
chat(y, x) = TRAP;
|
||||
if (!terse)
|
||||
addmsg(rs,"you found ");
|
||||
if (on(player, ISHALU))
|
||||
msg(rs,(char *)tr_name[rnd(NTRAPS)]);
|
||||
else {
|
||||
msg(rs,(char *)tr_name[*fp & F_TMASK]);
|
||||
*fp |= F_SEEN;
|
||||
}
|
||||
goto foundone;
|
||||
break;
|
||||
case ' ':
|
||||
if (rnd(3 + probinc) != 0)
|
||||
break;
|
||||
chat(y, x) = PASSAGE;
|
||||
goto foundone;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
look(rs,FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* help:
|
||||
* Give single character help, or the whole mess if he wants it
|
||||
*/
|
||||
void
|
||||
help(struct rogue_state *rs)
|
||||
{
|
||||
register const struct h_list *strp;
|
||||
register char helpch;
|
||||
register int numprint, cnt;
|
||||
msg(rs,"character you want help for (* for all): ");
|
||||
helpch = readchar(rs);
|
||||
mpos = 0;
|
||||
/*
|
||||
* If its not a *, print the right help string
|
||||
* or an error if he typed a funny character.
|
||||
*/
|
||||
if (helpch != '*')
|
||||
{
|
||||
move(0, 0);
|
||||
for (strp = helpstr; strp->h_desc != NULL; strp++)
|
||||
if (strp->h_ch == helpch)
|
||||
{
|
||||
lower_msg = TRUE;
|
||||
msg(rs,"%s%s", unctrl(strp->h_ch), strp->h_desc);
|
||||
lower_msg = FALSE;
|
||||
return;
|
||||
}
|
||||
msg(rs,"unknown character '%s'", unctrl(helpch));
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Here we print help for everything.
|
||||
* Then wait before we return to command mode
|
||||
*/
|
||||
numprint = 0;
|
||||
for (strp = helpstr; strp->h_desc != NULL; strp++)
|
||||
if (strp->h_print)
|
||||
numprint++;
|
||||
if (numprint & 01) /* round odd numbers up */
|
||||
numprint++;
|
||||
numprint /= 2;
|
||||
if (numprint > LINES - 1)
|
||||
numprint = LINES - 1;
|
||||
|
||||
wclear(hw);
|
||||
cnt = 0;
|
||||
for (strp = helpstr; strp->h_desc != NULL; strp++)
|
||||
if (strp->h_print)
|
||||
{
|
||||
wmove(hw, cnt % numprint, cnt >= numprint ? COLS / 2 : 0);
|
||||
if (strp->h_ch)
|
||||
waddstr(hw, unctrl(strp->h_ch));
|
||||
waddstr(hw, strp->h_desc);
|
||||
if (++cnt >= numprint * 2)
|
||||
break;
|
||||
}
|
||||
wmove(hw, LINES - 1, 0);
|
||||
waddstr(hw, "--Press space to continue--");
|
||||
wrefresh(hw);
|
||||
wait_for(rs,' ');
|
||||
clearok(stdscr, TRUE);
|
||||
/*
|
||||
refresh();
|
||||
*/
|
||||
msg(rs,"");
|
||||
touchwin(stdscr);
|
||||
wrefresh(stdscr);
|
||||
}
|
||||
|
||||
/*
|
||||
* identify:
|
||||
* Tell the player what a certain thing is.
|
||||
*/
|
||||
void
|
||||
identify(struct rogue_state *rs)
|
||||
{
|
||||
register int ch;
|
||||
register const struct h_list *hp;
|
||||
register char *str;
|
||||
static const struct h_list ident_list[] = {
|
||||
{'|', "wall of a room", FALSE},
|
||||
{'-', "wall of a room", FALSE},
|
||||
{GOLD, "gold", FALSE},
|
||||
{STAIRS, "a staircase", FALSE},
|
||||
{DOOR, "door", FALSE},
|
||||
{FLOOR, "room floor", FALSE},
|
||||
{PLAYER, "you", FALSE},
|
||||
{PASSAGE, "passage", FALSE},
|
||||
{TRAP, "trap", FALSE},
|
||||
{POTION, "potion", FALSE},
|
||||
{SCROLL, "scroll", FALSE},
|
||||
{FOOD, "food", FALSE},
|
||||
{WEAPON, "weapon", FALSE},
|
||||
{' ', "solid rock", FALSE},
|
||||
{ARMOR, "armor", FALSE},
|
||||
{AMULET, "the Amulet of Yendor", FALSE},
|
||||
{RING, "ring", FALSE},
|
||||
{STICK, "wand or staff", FALSE},
|
||||
{'\0'}
|
||||
};
|
||||
|
||||
msg(rs,"what do you want identified? ");
|
||||
ch = readchar(rs);
|
||||
mpos = 0;
|
||||
if (ch == ESCAPE)
|
||||
{
|
||||
msg(rs,"");
|
||||
return;
|
||||
}
|
||||
if (isupper(ch))
|
||||
str = monsters[ch-'A'].m_name;
|
||||
else
|
||||
{
|
||||
str = "unknown character";
|
||||
for (hp = ident_list; hp->h_ch != '\0'; hp++)
|
||||
if (hp->h_ch == ch)
|
||||
{
|
||||
str = hp->h_desc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg(rs,"'%s': %s", unctrl(ch), str);
|
||||
}
|
||||
|
||||
/*
|
||||
* d_level:
|
||||
* He wants to go down a level
|
||||
*/
|
||||
void
|
||||
d_level(struct rogue_state *rs)
|
||||
{
|
||||
if (levit_check(rs))
|
||||
return;
|
||||
if (chat(hero.y, hero.x) != STAIRS)
|
||||
msg(rs,"I see no way down");
|
||||
else
|
||||
{
|
||||
level++;
|
||||
seenstairs = FALSE;
|
||||
new_level(rs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* u_level:
|
||||
* He wants to go up a level
|
||||
*/
|
||||
void
|
||||
u_level(struct rogue_state *rs)
|
||||
{
|
||||
if (levit_check(rs))
|
||||
return;
|
||||
if (chat(hero.y, hero.x) == STAIRS)
|
||||
if (amulet)
|
||||
{
|
||||
level--;
|
||||
if (level == 0)
|
||||
total_winner(rs);
|
||||
new_level(rs);
|
||||
msg(rs,"you feel a wrenching sensation in your gut");
|
||||
}
|
||||
else
|
||||
msg(rs,"your way is magically blocked");
|
||||
else
|
||||
msg(rs,"I see no way up");
|
||||
}
|
||||
|
||||
/*
|
||||
* levit_check:
|
||||
* Check to see if she's levitating, and if she is, print an
|
||||
* appropriate message.
|
||||
*/
|
||||
bool
|
||||
levit_check(struct rogue_state *rs)
|
||||
{
|
||||
if (!on(player, ISLEVIT))
|
||||
return FALSE;
|
||||
msg(rs,"You can't. You're floating off the ground!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* call:
|
||||
* Allow a user to call a potion, scroll, or ring something
|
||||
*/
|
||||
void
|
||||
call(struct rogue_state *rs)
|
||||
{
|
||||
register THING *obj;
|
||||
register const struct obj_info *op = NULL;
|
||||
register char **guess; const char *elsewise = NULL;
|
||||
register const bool *know;
|
||||
|
||||
obj = get_item(rs,"call", CALLABLE);
|
||||
/*
|
||||
* Make certain that it is somethings that we want to wear
|
||||
*/
|
||||
if (obj == NULL)
|
||||
return;
|
||||
switch (obj->o_type)
|
||||
{
|
||||
case RING:
|
||||
op = &ring_info[obj->o_which];
|
||||
elsewise = r_stones[obj->o_which];
|
||||
goto norm;
|
||||
when POTION:
|
||||
op = &pot_info[obj->o_which];
|
||||
elsewise = p_colors[obj->o_which];
|
||||
goto norm;
|
||||
when SCROLL:
|
||||
op = &scr_info[obj->o_which];
|
||||
elsewise = s_names[obj->o_which];
|
||||
goto norm;
|
||||
when STICK:
|
||||
op = &ws_info[obj->o_which];
|
||||
elsewise = ws_made[obj->o_which];
|
||||
norm:
|
||||
know = &op->oi_know;
|
||||
guess = (char **)&op->oi_guess;
|
||||
if (*guess != NULL)
|
||||
elsewise = *guess;
|
||||
when FOOD:
|
||||
msg(rs,"you can't call that anything");
|
||||
return;
|
||||
otherwise:
|
||||
guess = &obj->o_label;
|
||||
know = NULL;
|
||||
elsewise = obj->o_label;
|
||||
}
|
||||
if (know != NULL && *know)
|
||||
{
|
||||
msg(rs,"that has already been identified");
|
||||
return;
|
||||
}
|
||||
if (elsewise != NULL && elsewise == *guess)
|
||||
{
|
||||
if (!terse)
|
||||
addmsg(rs,"Was ");
|
||||
msg(rs,"called \"%s\"", elsewise);
|
||||
}
|
||||
if (terse)
|
||||
msg(rs,"call it: ");
|
||||
else
|
||||
msg(rs,"what do you want to call it? ");
|
||||
|
||||
if (elsewise == NULL)
|
||||
strcpy(prbuf, "");
|
||||
else
|
||||
strcpy(prbuf, elsewise);
|
||||
if (get_str(rs,prbuf, stdscr) == NORM)
|
||||
{
|
||||
if (*guess != NULL)
|
||||
free(*guess);
|
||||
*guess = (char *)malloc((unsigned int) strlen(prbuf) + 1);
|
||||
strcpy(*guess, prbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* current:
|
||||
* Print the current weapon/armor
|
||||
*/
|
||||
void
|
||||
current(struct rogue_state *rs,THING *cur, char *how, char *where)
|
||||
{
|
||||
after = FALSE;
|
||||
if (cur != NULL)
|
||||
{
|
||||
if (!terse)
|
||||
addmsg(rs,"you are %s (", how);
|
||||
inv_describe = FALSE;
|
||||
addmsg(rs,"%c) %s", cur->o_packch, inv_name(cur, TRUE));
|
||||
inv_describe = TRUE;
|
||||
if (where)
|
||||
addmsg(rs," %s", where);
|
||||
endmsg(rs);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!terse)
|
||||
addmsg(rs,"you are ");
|
||||
addmsg(rs,"%s nothing", how);
|
||||
if (where)
|
||||
addmsg(rs," %s", where);
|
||||
endmsg(rs);
|
||||
}
|
||||
}
|
||||
1500
src/cc/rogue/config.guess
vendored
Executable file
1500
src/cc/rogue/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
269
src/cc/rogue/config.h.in
Normal file
269
src/cc/rogue/config.h.in
Normal file
@@ -0,0 +1,269 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if scorefile is top scores, not top players */
|
||||
#undef ALLSCORES
|
||||
|
||||
/* Define if checktime feature should be enabled */
|
||||
#undef CHECKTIME
|
||||
|
||||
/* Define to group owner of setgid executable */
|
||||
#undef GROUPOWNER
|
||||
|
||||
/* Define to 1 if you have the `alarm' function. */
|
||||
#undef HAVE_ALARM
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if libcurses is requested */
|
||||
#undef HAVE_CURSES_H
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
#undef HAVE_DOPRNT
|
||||
|
||||
/* Define to 1 if you have the `erasechar' function. */
|
||||
#undef HAVE_ERASECHAR
|
||||
|
||||
/* Define if ncurses has ESCDELAY variable */
|
||||
#undef HAVE_ESCDELAY
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `getgid' function. */
|
||||
#undef HAVE_GETGID
|
||||
|
||||
/* Define to 1 if you have the `getloadavg' function. */
|
||||
#undef HAVE_GETLOADAVG
|
||||
|
||||
/* Define to 1 if you have the `getpass' function. */
|
||||
#undef HAVE_GETPASS
|
||||
|
||||
/* Define to 1 if you have the `getpwuid' function. */
|
||||
#undef HAVE_GETPWUID
|
||||
|
||||
/* Define to 1 if you have the `getuid' function. */
|
||||
#undef HAVE_GETUID
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `killchar' function. */
|
||||
#undef HAVE_KILLCHAR
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if you have the `loadav' function. */
|
||||
#undef HAVE_LOADAV
|
||||
|
||||
/* Define to 1 if `lstat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
#undef HAVE_LSTAT_EMPTY_STRING_BUG
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if libncurses is requested */
|
||||
#undef HAVE_NCURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ncurses/term.h> header file. */
|
||||
#undef HAVE_NCURSES_TERM_H
|
||||
|
||||
/* Define to 1 if you have the `nlist' function. */
|
||||
#undef HAVE_NLIST
|
||||
|
||||
/* Define to 1 if you have the <nlist.h> header file. */
|
||||
#undef HAVE_NLIST_H
|
||||
|
||||
/* Define to 1 if you have the <process.h> header file. */
|
||||
#undef HAVE_PROCESS_H
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#undef HAVE_PWD_H
|
||||
|
||||
/* Define to 1 if you have the `setenv' function. */
|
||||
#undef HAVE_SETENV
|
||||
|
||||
/* Define to 1 if you have the `setgid' function. */
|
||||
#undef HAVE_SETGID
|
||||
|
||||
/* Define to 1 if you have the `setregid' function. */
|
||||
#undef HAVE_SETREGID
|
||||
|
||||
/* Define to 1 if you have the `setresgid' function. */
|
||||
#undef HAVE_SETRESGID
|
||||
|
||||
/* Define to 1 if you have the `setresuid' function. */
|
||||
#undef HAVE_SETRESUID
|
||||
|
||||
/* Define to 1 if you have the `setreuid' function. */
|
||||
#undef HAVE_SETREUID
|
||||
|
||||
/* Define to 1 if you have the `setuid' function. */
|
||||
#undef HAVE_SETUID
|
||||
|
||||
/* Define to 1 if you have the `spawnl' function. */
|
||||
#undef HAVE_SPAWNL
|
||||
|
||||
/* Define to 1 if `stat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
#undef HAVE_STAT_EMPTY_STRING_BUG
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#undef HAVE_SYS_UTSNAME_H
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#undef HAVE_TERMIOS_H
|
||||
|
||||
/* Define to 1 if you have the <term.h> header file. */
|
||||
#undef HAVE_TERM_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <utmp.h> header file. */
|
||||
#undef HAVE_UTMP_H
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if you have the `vprintf' function. */
|
||||
#undef HAVE_VPRINTF
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#undef HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Define to 1 if you have the `_spawnl' function. */
|
||||
#undef HAVE__SPAWNL
|
||||
|
||||
/* define if we should use program's load average function instead of system
|
||||
*/
|
||||
#undef LOADAV
|
||||
|
||||
/* Define to file to use for scoreboard lockfile */
|
||||
#undef LOCKFILE
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
|
||||
/* Define to include wizard mode */
|
||||
#undef MASTER
|
||||
|
||||
/* Define if maxusers feature should be enabled */
|
||||
#undef MAXLOAD
|
||||
|
||||
/* Define if maxusers feature should be enabled */
|
||||
#undef MAXUSERS
|
||||
|
||||
/* kernel file to pass to nlist() when reading load average (unlikely to work)
|
||||
*/
|
||||
#undef NAMELIST
|
||||
|
||||
/* word for the number of scores to store in scoreboard */
|
||||
#undef NUMNAME
|
||||
|
||||
/* number of scores to store in scoreboard */
|
||||
#undef NUMSCORES
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define crypt(3) wizard mode password */
|
||||
#undef PASSWD
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to file to use for scoreboard */
|
||||
#undef SCOREFILE
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
/* define if we should use program's user counting function instead of
|
||||
system's */
|
||||
#undef UCOUNT
|
||||
|
||||
/* utmp like file to pass to ucount() when counting online users (unlikely to
|
||||
work) */
|
||||
#undef UTMP
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
#undef vfork
|
||||
1608
src/cc/rogue/config.sub
vendored
Executable file
1608
src/cc/rogue/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
7511
src/cc/rogue/configure
vendored
Executable file
7511
src/cc/rogue/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
246
src/cc/rogue/configure.ac
Normal file
246
src/cc/rogue/configure.ac
Normal file
@@ -0,0 +1,246 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.56)
|
||||
AC_INIT([Rogue],[5.4.4], [yendor@rogueforge.net])
|
||||
AC_CONFIG_SRCDIR([armor.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
AC_CONFIG_FILES([Makefile rogue.6 rogue.cat rogue.doc rogue.html rogue.me])
|
||||
AC_CANONICAL_SYSTEM([])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
|
||||
# Checks for libraries.
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([arpa/inet.h sys/utsname.h pwd.h fcntl.h limits.h nlist.h stdlib.h string.h sys/ioctl.h termios.h unistd.h utmp.h term.h ncurses/term.h process.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
AC_C_CONST
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_STRUCT_TM
|
||||
MP_WITH_CURSES
|
||||
# Checks for library functions.
|
||||
AC_FUNC_FORK
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_LSTAT
|
||||
AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_STAT
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS([erasechar killchar alarm getpass memset setenv strchr nlist _spawnl spawnl getpwuid loadav getloadavg strerror setresgid setregid setgid setresuid setreuid setuid getuid getgid])
|
||||
|
||||
AC_CHECK_PROG([NROFF], [nroff], [nroff],)
|
||||
AC_CHECK_PROG([GROFF], [groff], [groff],)
|
||||
AC_CHECK_PROG([COLCRT], [colcrt], [colcrt],)
|
||||
AC_CHECK_PROG([TBL], [tbl], [tbl],)
|
||||
AC_CHECK_PROG([SED], [sed], [sed],)
|
||||
|
||||
AC_ARG_WITH(program-name, AC_HELP_STRING([--with-program-name=NAME],[alternate executable name]),[progname="$withval" ], [progname="rogue"] )
|
||||
PROGRAM=$progname
|
||||
AC_SUBST(PROGRAM)
|
||||
|
||||
AC_ARG_ENABLE(setgid, AC_HELP_STRING([--enable-setgid=NAME],[install executable as setgid with group ownership of NAME @<:@default=no@:>@])],[],[])
|
||||
AC_MSG_CHECKING([if using setgid execute bit])
|
||||
if test "x$enable_setgid" = "xno" ; then
|
||||
GROUPOWNER=
|
||||
elif test "x$enable_setgid" = "xyes" ; then
|
||||
GROUPOWNER=games
|
||||
elif test "x$enable_setgid" = "x" ; then
|
||||
GROUPOWNER=
|
||||
else
|
||||
GROUPOWNER=$enable_setgid
|
||||
fi
|
||||
|
||||
if test "x$GROUPOWNER" != "x" ; then
|
||||
AC_DEFINE_UNQUOTED([GROUPOWNER],[$GROUPOWNER], [Define to group owner of setgid executable])
|
||||
AC_MSG_RESULT([$GROUPOWNER])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_SUBST(GROUPOWNER)
|
||||
|
||||
AC_ARG_ENABLE([scorefile],[AC_HELP_STRING([--enable-scorefile=SCOREFILE], [enable scoreboard with given filename])],[],[])
|
||||
AC_MSG_CHECKING([for scoreboard file])
|
||||
if test "x$enable_scorefile" = "xno" ; then
|
||||
SCOREFILE=
|
||||
elif test "x$enable_scorefile" = "xyes" ; then
|
||||
SCOREFILE=$progname.scr
|
||||
elif test "x$enable_scorefile" = "x" ; then
|
||||
SCOREFILE=$progname.scr
|
||||
else
|
||||
SCOREFILE=$enable_scorefile
|
||||
fi
|
||||
|
||||
if test "x$SCOREFILE" != "x" ; then
|
||||
AC_DEFINE_UNQUOTED([SCOREFILE], ["$SCOREFILE"], [Define to file to use for scoreboard])
|
||||
AC_MSG_RESULT([$SCOREFILE])
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
|
||||
AC_SUBST(SCOREFILE)
|
||||
|
||||
AC_ARG_ENABLE([lockfile],[AC_HELP_STRING([--enable-lockfile=LOCKFILE], [enable scoreboard lockfile with given filename])],[],[])
|
||||
AC_MSG_CHECKING([for scoreboard lockfile file])
|
||||
if test "x$enable_lockfile" = "xno" ; then
|
||||
LOCKFILE=
|
||||
elif test "x$enable_lockfile" = "xyes" ; then
|
||||
LOCKFILE=$progname.lck
|
||||
elif test "x$enable_lockfile" = "x" ; then
|
||||
LOCKFILE=$progname.lck
|
||||
else
|
||||
LOCKFILE=$enable_lockfile
|
||||
fi
|
||||
|
||||
if test "x$LOCKFILE" != "x" ; then
|
||||
AC_DEFINE_UNQUOTED([LOCKFILE], ["$LOCKFILE"], [Define to file to use for scoreboard lockfile])
|
||||
AC_MSG_RESULT([$LOCKFILE])
|
||||
else
|
||||
AC_MSG_RESULT([disabled])
|
||||
fi
|
||||
|
||||
AC_SUBST(LOCKFILE)
|
||||
|
||||
AC_ARG_ENABLE([wizardmode],[AC_HELP_STRING([--enable-wizardmode], [enable availability of wizard mode @<:@default=no@:>@])],[],[])
|
||||
AC_MSG_CHECKING([if wizard mode is enabled])
|
||||
if test "x$enable_wizardmode" = "xno" ; then
|
||||
AC_MSG_RESULT([no])
|
||||
elif test "x$enable_wizardmode" = "x" ; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_DEFINE([MASTER], [], [Define to include wizard mode])
|
||||
if test "x$enable_wizardmode" != "xyes" ; then
|
||||
AC_DEFINE_UNQUOTED([PASSWD],[$enable_wizardmode], [Define crypt(3) wizard mode password])
|
||||
fi
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([allscores],[AC_HELP_STRING([--enable-allscores], [enable scoreboard to show top scores, not just top players @<:@default=yes@:>@])],[],[enable_allscores=yes])
|
||||
AC_MSG_CHECKING([if allscores is enabled])
|
||||
if test "x$enable_allscores" = "xyes" ; then
|
||||
AC_DEFINE([ALLSCORES], [1], [Define if scorefile is top scores, not top players])
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([checktime],[AC_HELP_STRING([--enable-checktime], [enable checktime @<:@default=no@:>@])],[],[])
|
||||
AC_MSG_CHECKING([if checktime is enabled])
|
||||
if test "x$enable_checktime" = "xyes" ; then
|
||||
AC_DEFINE([CHECKTIME], [1], [Define if checktime feature should be enabled])
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([maxload],[AC_HELP_STRING([--enable-maxload], [enable maxload @<:@default=no@:>@])],[],[])
|
||||
AC_MSG_CHECKING([runtime execution limit (maximum system load average)])
|
||||
if test "x$enable_maxload" = "xyes" ; then
|
||||
AC_DEFINE([MAXLOAD], [100], [Define if maxload feature should be enabled])
|
||||
AC_MSG_RESULT([100])
|
||||
elif test "x$enable_maxload" = "x" ; then
|
||||
AC_MSG_RESULT([unlimited])
|
||||
elif test "x$enable_maxload" = "xno" ; then
|
||||
AC_MSG_RESULT([unlimited])
|
||||
else
|
||||
AC_DEFINE_UNQUOTED([MAXLOAD], [$enable_maxload], [Define if maxload feature should be enabled])
|
||||
AC_MSG_RESULT([$enable_maxload])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([maxusers],[AC_HELP_STRING([--enable-maxusers], [enable maxuser @<:@default=no@:>@])],[],[])
|
||||
AC_MSG_CHECKING([runtime execution limit (maximum online system users)])
|
||||
if test "x$enable_maxusers" = "xyes" ; then
|
||||
AC_DEFINE([MAXUSERS], [100], [Define if maxusers feature should be enabled])
|
||||
AC_MSG_RESULT([100])
|
||||
elif test "x$enable_maxusers" = "x" ; then
|
||||
AC_MSG_RESULT([unlimited])
|
||||
elif test "x$enable_maxload" = "xno" ; then
|
||||
AC_MSG_RESULT([unlimited])
|
||||
else
|
||||
AC_DEFINE_UNQUOTED([MAXLOAD], [$enable_maxusers], [Define if maxusers feature should be enabled])
|
||||
AC_MSG_RESULT([$enable_maxusers])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([numscores],[AC_HELP_STRING([--enable-numscores], [number of scores to store in scoreboard @<:@default=10@:>@])],[],[])
|
||||
AC_MSG_CHECKING([what the number of scores to store in scoreboard is])
|
||||
if test "x$numscores" = "xyes" ; then
|
||||
AC_DEFINE([NUMSCORES], [10], [number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([10])
|
||||
elif test "x$enable_numscores" = "x" ; then
|
||||
AC_DEFINE([NUMSCORES], [10], [number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([10])
|
||||
elif test "x$enable_numscores" = "xno" ; then
|
||||
AC_DEFINE([NUMSCORES], [10], [number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([10])
|
||||
else
|
||||
AC_DEFINE_UNQUOTED([NUMSCORES], [$enable_numscores], [number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([$enable_numscores])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([numname],[AC_HELP_STRING([--enable-numname], [word for number of scores to store in scoreboard @<:@default=Ten@:>@])],[],[])
|
||||
AC_MSG_CHECKING([word for the number of scores to store in scoreboard is])
|
||||
if test "x$enable_numname" = "xyes" ; then
|
||||
AC_DEFINE([NUMNAME], ["Ten"], [word for the number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([Ten])
|
||||
elif test "x$enable_numname" = "x" ; then
|
||||
AC_DEFINE([NUMNAME], ["Ten"], [word for the number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([Ten])
|
||||
elif test "x$enable_numname" = "xno" ; then
|
||||
AC_DEFINE([NUMNAME], ["Ten"], [word for the number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([Ten])
|
||||
else
|
||||
AC_DEFINE_UNQUOTED([NUMNAME], ["$enable_numname"], [word for the number of scores to store in scoreboard])
|
||||
AC_MSG_RESULT([$enable_numname])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([loadav],[AC_HELP_STRING([--enable-loadav=NAMELIST], [use program's load average function (unlikely to work) @<:@default=no@:>@])],[],[])
|
||||
AC_MSG_CHECKING([whether to use program's built in load average function])
|
||||
if test "x$enable_loadav" = "xyes" ; then
|
||||
AC_DEFINE([LOADAV], [], [define if we should use program's load average function instead of system])
|
||||
AC_DEFINE([NAMELIST], [/vmunix], [kernel file to pass to nlist() when reading load average (unlikely to work)])
|
||||
AC_MSG_RESULT([/vmunix])
|
||||
elif test "x$enable_loadav" = "x" ; then
|
||||
AC_MSG_RESULT([no])
|
||||
elif test "x$enable_loadav" = "xno" ; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_DEFINE([LOADAV], [], [define if we should use program's load average function instead of system])
|
||||
AC_DEFINE_UNQUOTED([NAMELIST], [$enable_loadav], [kernel file to pass to nlist() when reading load average (unlikely to work)])
|
||||
AC_MSG_RESULT([$enable_loadav])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([ucount],[AC_HELP_STRING([--enable-ucount=UTMPFILE], [use program's own function to count users (unlikely to work) @<:@default=no@:>@])],[],[])
|
||||
AC_MSG_CHECKING([whether to use program's built in user counting function])
|
||||
if test "x$enable_ucount" = "xyes" ; then
|
||||
AC_DEFINE([UCOUNT], [], [define if we should use program's user counting function instead of system's])
|
||||
AC_DEFINE([UTMP], [/etc/utmp], [utmp like file to pass to ucount() when counting online users (unlikely to work)])
|
||||
AC_MSG_RESULT([/etc/utmp])
|
||||
elif test "x$enable_ucount" = "x" ; then
|
||||
AC_MSG_RESULT([no])
|
||||
elif test "x$enable_count" = "xno" ; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_DEFINE([UCOUNT], [], [define if we should use program's user counting function instead of system's])
|
||||
AC_DEFINE_UNQUOTED([UTMP], [$enable_ucount], [utmp like file to pass to ucount() when counting online users (unlikely to work)])
|
||||
AC_MSG_RESULT([$enable_ucount])
|
||||
fi
|
||||
|
||||
TARGET=$target
|
||||
AC_SUBST(TARGET)
|
||||
|
||||
AC_MSG_CHECKING([whether to docdir is defined])
|
||||
if test "x$docdir" = "x" ; then
|
||||
AC_MSG_RESULT([docdir undefined])
|
||||
docdir=\${datadir}/doc/\${PACKAGE_TARNAME}
|
||||
AC_SUBST(docdir)
|
||||
else
|
||||
AC_MSG_RESULT([docdir defined])
|
||||
fi
|
||||
|
||||
AC_OUTPUT
|
||||
432
src/cc/rogue/cursesd.c
Normal file
432
src/cc/rogue/cursesd.c
Normal file
@@ -0,0 +1,432 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "cursesd.h"
|
||||
|
||||
static int32_t endwinflag;
|
||||
WINDOW *stdscr,*curscr;
|
||||
int32_t ESCDELAY;
|
||||
|
||||
WINDOW *newwin(int32_t nlines,int32_t ncols,int32_t begin_y,int32_t begin_x)
|
||||
{
|
||||
WINDOW *scr = 0;
|
||||
if ( nlines == LINES && ncols == COLS && begin_y == 0 && begin_x == 0 )
|
||||
scr = (WINDOW *)calloc(1,sizeof(*stdscr));
|
||||
curscr = scr;
|
||||
return(scr);
|
||||
}
|
||||
|
||||
WINDOW *initscr()
|
||||
{
|
||||
if ( stdscr == 0 )
|
||||
stdscr = newwin(LINES,COLS,0,0);
|
||||
return(stdscr);
|
||||
}
|
||||
|
||||
int32_t delwin(WINDOW *win)
|
||||
{
|
||||
free(win);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t wmove(WINDOW *win, int32_t y, int32_t x)
|
||||
{
|
||||
win->y = y;
|
||||
win->x = x;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t move(int32_t y, int32_t x)
|
||||
{
|
||||
return(wmove(stdscr,y,x));
|
||||
}
|
||||
|
||||
int32_t werase(WINDOW *win)
|
||||
{
|
||||
memset(win->screen,' ',sizeof(win->screen));
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t wclear(WINDOW *win)
|
||||
{
|
||||
werase(win);
|
||||
clearok(win,TRUE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t wclrtoeol(WINDOW *win)
|
||||
{
|
||||
if ( win->x < COLS-1 )
|
||||
memset(&win->screen[win->y][win->x],' ',COLS - win->x);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t wclrtobot(WINDOW *win)
|
||||
{
|
||||
wclrtoeol(win);
|
||||
if ( win->y < LINES-1 )
|
||||
memset(&win->screen[win->y+1][0],' ',COLS);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t erase(void)
|
||||
{
|
||||
return(werase(stdscr));
|
||||
}
|
||||
|
||||
int32_t clear(void)
|
||||
{
|
||||
return(wclear(stdscr));
|
||||
}
|
||||
|
||||
int32_t clrtobot(void)
|
||||
{
|
||||
return(wclrtobot(stdscr));
|
||||
}
|
||||
|
||||
int32_t clrtoeol(void)
|
||||
{
|
||||
return(wclrtoeol(stdscr));
|
||||
}
|
||||
|
||||
int32_t waddch(WINDOW *win, chtype ch)
|
||||
{
|
||||
int32_t i;
|
||||
if ( ch == '\t' )
|
||||
{
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if ( win->x >= COLS-1 )
|
||||
break;
|
||||
win->x++;
|
||||
if ( (win->x & 7) == 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( ch == '\n' )
|
||||
{
|
||||
wclrtoeol(win);
|
||||
win->x = 0;
|
||||
win->y++;
|
||||
if ( win->y >= LINES )
|
||||
win->y = 0;
|
||||
}
|
||||
else if ( ch == '\b' )
|
||||
{
|
||||
if ( win->x > 0 )
|
||||
win->x--;
|
||||
}
|
||||
else
|
||||
{
|
||||
win->screen[win->y][win->x++] = ch;
|
||||
if ( win->x >= COLS )
|
||||
{
|
||||
win->x = 0;
|
||||
win->y++;
|
||||
if ( win->y >= LINES )
|
||||
win->y = 0;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t mvwaddch(WINDOW *win, int32_t y, int32_t x, chtype ch)
|
||||
{
|
||||
win->y = y;
|
||||
win->x = x;
|
||||
return(waddch(win,ch));
|
||||
}
|
||||
|
||||
int32_t addch(chtype ch)
|
||||
{
|
||||
return(waddch(stdscr,ch));
|
||||
}
|
||||
|
||||
int32_t mvaddch(int32_t y, int32_t x, chtype ch)
|
||||
{
|
||||
return(mvwaddch(stdscr,y,x,ch));
|
||||
}
|
||||
|
||||
int32_t waddstr(WINDOW *win, const char *str)
|
||||
{
|
||||
int32_t i;
|
||||
//fprintf(stderr,"%s\n",str);
|
||||
for (i=0; str[i]!=0; i++)
|
||||
waddch(win,str[i]);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t waddnstr(WINDOW *win, const char *str, int32_t n)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; str[i]!=0 && i<n; i++)
|
||||
waddch(win,str[i]);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t mvwaddstr(WINDOW *win, int32_t y, int32_t x, const char *str)
|
||||
{
|
||||
win->y = y;
|
||||
win->x = x;
|
||||
return(waddstr(win,str));
|
||||
}
|
||||
|
||||
int32_t mvwaddnstr(WINDOW *win, int32_t y, int32_t x, const char *str, int32_t n)
|
||||
{
|
||||
win->y = y;
|
||||
win->x = x;
|
||||
return(waddnstr(win,str,n));
|
||||
}
|
||||
|
||||
int32_t addstr(const char *str)
|
||||
{
|
||||
return(waddstr(stdscr,str));
|
||||
}
|
||||
|
||||
int32_t addnstr(const char *str, int32_t n)
|
||||
{
|
||||
return(waddnstr(stdscr,str,n));
|
||||
}
|
||||
|
||||
int32_t mvaddstr(int32_t y, int32_t x, const char *str)
|
||||
{
|
||||
stdscr->y = y;
|
||||
stdscr->x = x;
|
||||
return(waddstr(stdscr,str));
|
||||
}
|
||||
|
||||
int32_t mvaddnstr(int32_t y, int32_t x, const char *str, int32_t n)
|
||||
{
|
||||
stdscr->y = y;
|
||||
stdscr->x = x;
|
||||
return(waddnstr(stdscr,str,n));
|
||||
}
|
||||
|
||||
int32_t printw(char *fmt,...)
|
||||
{
|
||||
char str[512]; int32_t ret; va_list myargs; // Declare a va_list type variable
|
||||
va_start(myargs,fmt); // Initialise the va_list variable with the ... after fmt
|
||||
ret = vsprintf(str,fmt,myargs); // Forward the '...' to vsprintf
|
||||
va_end(myargs); // Clean up the va_list
|
||||
return(addstr(str));
|
||||
}
|
||||
|
||||
int32_t wprintw(WINDOW *win,char *fmt,...)
|
||||
{
|
||||
char str[512]; int32_t ret; va_list myargs; // Declare a va_list type variable
|
||||
va_start(myargs,fmt); // Initialise the va_list variable with the ... after fmt
|
||||
ret = vsprintf(str,fmt,myargs); // Forward the '...' to vsprintf
|
||||
va_end(myargs); // Clean up the va_list
|
||||
return(waddstr(win,str));
|
||||
}
|
||||
|
||||
int32_t mvprintw(int32_t y,int32_t x,char *fmt,...)
|
||||
{
|
||||
char str[512]; int32_t ret; va_list myargs; // Declare a va_list type variable
|
||||
va_start(myargs,fmt); // Initialise the va_list variable with the ... after fmt
|
||||
ret = vsprintf(str,fmt,myargs); // Forward the '...' to vsprintf
|
||||
va_end(myargs); // Clean up the va_list
|
||||
stdscr->y = y;
|
||||
stdscr->x = x;
|
||||
return(addstr(str));
|
||||
}
|
||||
|
||||
int32_t mvwprintw(WINDOW *win,int32_t y,int32_t x,char *fmt,...)
|
||||
{
|
||||
char str[512]; int32_t ret; va_list myargs; // Declare a va_list type variable
|
||||
va_start(myargs,fmt); // Initialise the va_list variable with the ... after fmt
|
||||
ret = vsprintf(str,fmt,myargs); // Forward the '...' to vsprintf
|
||||
va_end(myargs); // Clean up the va_list
|
||||
win->y = y;
|
||||
win->x = x;
|
||||
return(waddstr(win,str));
|
||||
}
|
||||
|
||||
chtype winch(WINDOW *win)
|
||||
{
|
||||
return(win->screen[win->y][win->x]);
|
||||
}
|
||||
|
||||
chtype inch(void)
|
||||
{
|
||||
return(winch(stdscr));
|
||||
}
|
||||
|
||||
chtype mvwinch(WINDOW *win, int32_t y, int32_t x)
|
||||
{
|
||||
win->y = y;
|
||||
win->x = x;
|
||||
return(win->screen[win->y][win->x]);
|
||||
}
|
||||
|
||||
chtype mvinch(int32_t y, int32_t x)
|
||||
{
|
||||
return(mvwinch(stdscr,y,x));
|
||||
}
|
||||
|
||||
int32_t mvcur(int32_t oldrow, int32_t oldcol, int32_t newrow, int32_t newcol)
|
||||
{
|
||||
stdscr->y = newrow;
|
||||
stdscr->x = newcol;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t endwin(void)
|
||||
{
|
||||
if ( stdscr != 0 )
|
||||
free(stdscr), stdscr = 0;
|
||||
endwinflag = 1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t isendwin(void)
|
||||
{
|
||||
return(endwinflag);
|
||||
}
|
||||
|
||||
int32_t refresh(void)
|
||||
{
|
||||
endwinflag = 0;
|
||||
return(wrefresh(stdscr));
|
||||
}
|
||||
|
||||
int32_t redrawwin(WINDOW *win)
|
||||
{
|
||||
return(wrefresh(win));
|
||||
}
|
||||
|
||||
int32_t wredrawln(WINDOW *win, int32_t beg_line, int32_t num_lines)
|
||||
{
|
||||
return(wrefresh(win));
|
||||
}
|
||||
|
||||
// functions with no data side effect
|
||||
#ifdef they_are_macros
|
||||
int32_t wrefresh(WINDOW *win)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t wnoutrefresh(WINDOW *win)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t doupdate(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t touchwin(WINDOW *win)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t standout(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t standend(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t raw(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t keypad(WINDOW *win, bool bf)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t noecho(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t flushinp(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t clearok(WINDOW *win, bool bf)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t idlok(WINDOW *win, bool bf)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t leaveok(WINDOW *win, bool bf)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t mvwin(WINDOW *win, int32_t y, int32_t x) // stub
|
||||
{
|
||||
fprintf(stderr,"unexpected call to mvwin\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
WINDOW *subwin(WINDOW *orig, int32_t nlines, int32_t ncols, int32_t begin_y, int32_t begin_x)
|
||||
{
|
||||
fprintf(stderr,"unexpected and unsupported call to subwin\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
char erasechar(void)
|
||||
{
|
||||
fprintf(stderr,"unexpected and unsupported call to erasechar\n");
|
||||
return(8);
|
||||
}
|
||||
|
||||
char killchar(void)
|
||||
{
|
||||
fprintf(stderr,"unexpected and unsupported call to erasechar\n");
|
||||
return(3);
|
||||
}
|
||||
|
||||
int32_t wgetnstr(WINDOW *win, char *str, int32_t n) // stub
|
||||
{
|
||||
fprintf(stderr,"unexpected and unsupported call to mvgetnstr\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifndef __MINGW32__
|
||||
int32_t getch(void)
|
||||
{
|
||||
fprintf(stderr,"unexpected and unsupported call to getch\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t md_readchar(void)
|
||||
{
|
||||
fprintf(stderr,"unexpected and unsupported call to md_readchar\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
char *unctrl(char c)
|
||||
{
|
||||
static char ctrlstr[5];
|
||||
sprintf(ctrlstr,"^%%%02x",c);
|
||||
return(ctrlstr);
|
||||
}
|
||||
198
src/cc/rogue/cursesd.h
Normal file
198
src/cc/rogue/cursesd.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef H_CURSESD_H
|
||||
#define H_CURSESD_H
|
||||
|
||||
#define KEY_OFFSET 0x100
|
||||
#define KEY_DOWN (KEY_OFFSET + 0x02) /* Down arrow key */
|
||||
#define KEY_UP (KEY_OFFSET + 0x03) /* Up arrow key */
|
||||
#define KEY_LEFT (KEY_OFFSET + 0x04) /* Left arrow key */
|
||||
#define KEY_RIGHT (KEY_OFFSET + 0x05) /* Right arrow key */
|
||||
|
||||
|
||||
#define COLOR_BLACK 0
|
||||
|
||||
#ifdef PDC_RGB /* RGB */
|
||||
# define COLOR_RED 1
|
||||
# define COLOR_GREEN 2
|
||||
# define COLOR_BLUE 4
|
||||
#else /* BGR */
|
||||
# define COLOR_BLUE 1
|
||||
# define COLOR_GREEN 2
|
||||
# define COLOR_RED 4
|
||||
#endif
|
||||
|
||||
#define COLOR_CYAN (COLOR_BLUE | COLOR_GREEN)
|
||||
#define COLOR_MAGENTA (COLOR_RED | COLOR_BLUE)
|
||||
#define COLOR_YELLOW (COLOR_RED | COLOR_GREEN)
|
||||
|
||||
#define COLOR_WHITE 7
|
||||
|
||||
#define LINES 24
|
||||
#define COLS 80
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h> /* we need va_list */
|
||||
#include <stddef.h> /* we want wchar_t */
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define ERR (-1)
|
||||
|
||||
struct cursesd_info
|
||||
{
|
||||
uint8_t screen[LINES][COLS];
|
||||
int32_t x,y;
|
||||
};
|
||||
typedef struct cursesd_info WINDOW;
|
||||
extern WINDOW *stdscr,*curscr;
|
||||
extern int32_t ESCDELAY;
|
||||
typedef char chtype;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
int32_t getch(void); // stub
|
||||
#endif
|
||||
|
||||
int32_t md_readchar(void); // stub
|
||||
|
||||
WINDOW *initscr(void);
|
||||
int32_t endwin(void);
|
||||
int32_t isendwin(void);
|
||||
//SCREEN *newterm(const char *type, FILE *outfd, FILE *infd);
|
||||
//SCREEN *set_term(SCREEN *new);
|
||||
//void delscreen(SCREEN* sp);
|
||||
|
||||
int32_t refresh(void);
|
||||
int32_t wrefresh(WINDOW *win);
|
||||
//int32_t wnoutrefresh(WINDOW *win);
|
||||
//int32_t doupdate(void);
|
||||
int32_t redrawwin(WINDOW *win);
|
||||
int32_t wredrawln(WINDOW *win, int32_t beg_line, int32_t num_lines);
|
||||
|
||||
int32_t erase(void);
|
||||
int32_t werase(WINDOW *win);
|
||||
int32_t clear(void);
|
||||
int32_t wclear(WINDOW *win);
|
||||
int32_t clrtobot(void);
|
||||
int32_t wclrtobot(WINDOW *win);
|
||||
int32_t clrtoeol(void);
|
||||
int32_t wclrtoeol(WINDOW *win);
|
||||
|
||||
int32_t standout(void);
|
||||
int32_t standend(void);
|
||||
int32_t raw(void);
|
||||
int32_t noecho(void);
|
||||
int32_t flushinp(void);
|
||||
int32_t keypad(WINDOW *win, bool bf);
|
||||
|
||||
int32_t clearok(WINDOW *win, bool bf);
|
||||
int32_t idlok(WINDOW *win, bool bf);
|
||||
int32_t leaveok(WINDOW *win, bool bf);
|
||||
|
||||
WINDOW *newwin(int32_t nlines,int32_t ncols,int32_t begin_y,int32_t begin_x); // only LINES,COLS,0,0
|
||||
int32_t delwin(WINDOW *win);
|
||||
int32_t touchwin(WINDOW *win); // stub
|
||||
WINDOW *subwin(WINDOW *orig, int32_t nlines, int32_t ncols, int32_t begin_y, int32_t begin_x); // stub
|
||||
int32_t mvwin(WINDOW *win, int32_t y, int32_t x); // stub
|
||||
int32_t mvcur(int32_t oldrow, int32_t oldcol, int32_t newrow, int32_t newcol);
|
||||
|
||||
char erasechar(void); // stub
|
||||
char killchar(void); // stub
|
||||
|
||||
int32_t move(int32_t y, int32_t x);
|
||||
int32_t wmove(WINDOW *win, int32_t y, int32_t x);
|
||||
|
||||
chtype inch(void);
|
||||
chtype winch(WINDOW *win);
|
||||
chtype mvinch(int32_t y, int32_t x);
|
||||
chtype mvwinch(WINDOW *win, int32_t y, int32_t x);
|
||||
|
||||
int32_t addch(chtype ch);
|
||||
int32_t waddch(WINDOW *win, chtype ch);
|
||||
int32_t mvaddch(int32_t y, int32_t x, chtype ch);
|
||||
int32_t mvwaddch(WINDOW *win, int32_t y, int32_t x, chtype ch);
|
||||
|
||||
int32_t addstr(const char *str);
|
||||
int32_t addnstr(const char *str, int32_t n);
|
||||
int32_t waddstr(WINDOW *win, const char *str);
|
||||
int32_t waddnstr(WINDOW *win, const char *str, int32_t n);
|
||||
int32_t mvaddstr(int32_t y, int32_t x, const char *str);
|
||||
int32_t mvaddnstr(int32_t y, int32_t x, const char *str, int32_t n);
|
||||
int32_t mvwaddstr(WINDOW *win, int32_t y, int32_t x, const char *str);
|
||||
int32_t mvwaddnstr(WINDOW *win, int32_t y, int32_t x, const char *str, int32_t n);
|
||||
|
||||
int32_t wgetnstr(WINDOW *win, char *str, int32_t n); // stub
|
||||
int32_t printw(char *fmt,...);
|
||||
int32_t wprintw(WINDOW *win,char *fmt,...);
|
||||
int32_t mvprintw(int32_t y,int32_t x,char *fmt,...);
|
||||
int32_t mvwprintw(WINDOW *win,int32_t y,int32_t x,char *fmt,...);
|
||||
|
||||
char *unctrl(char c);
|
||||
|
||||
#define A_CHARTEXT 0xff
|
||||
#define baudrate() 9600
|
||||
#define getmaxx(a) COLS
|
||||
#define getmaxy(a) LINES
|
||||
#define getyx(win,_argfory,_argforx) _argfory = win->y, _argforx = win->x
|
||||
|
||||
// functions with only visible effects
|
||||
#define wrefresh(win) 0
|
||||
#define wnoutrefresh(win) 0
|
||||
#define doupdate() 0
|
||||
#define touchwin(win) 0
|
||||
#define standout() 0
|
||||
#define standend() 0
|
||||
#define raw() 0
|
||||
#define keypad(win,bf) 0
|
||||
#define noecho() 0
|
||||
#define flushinp() 0
|
||||
#define clearok(win,bf) 0
|
||||
#define idlok(win,bf) 0
|
||||
#define leaveok(win,bf) 0
|
||||
#define halfdelay(x) 0
|
||||
#define nocbreak() 0
|
||||
#define cbreak() 0
|
||||
#define curs_set(x) 0
|
||||
|
||||
// for tetris
|
||||
#define init_pair(a,b,c) 0
|
||||
#define start_color() 0
|
||||
#define box(a,b,c) 0
|
||||
#define A_REVERSE 0
|
||||
#define COLOR_PAIR(a) 0
|
||||
#define timeout(x) 0
|
||||
// end for tetris
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
216
src/cc/rogue/daemon.c
Normal file
216
src/cc/rogue/daemon.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Contains functions for dealing with things that happen in the
|
||||
* future.
|
||||
*
|
||||
* @(#)daemon.c 4.7 (Berkeley) 02/05/99
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <curses.h>
|
||||
#include "rogue.h"
|
||||
|
||||
#define EMPTY 0
|
||||
#define DAEMON -1
|
||||
#define MAXDAEMONS 20
|
||||
|
||||
#define _X_ { EMPTY }
|
||||
|
||||
struct delayed_action d_list[MAXDAEMONS] = {
|
||||
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
|
||||
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
|
||||
};
|
||||
|
||||
/*
|
||||
* d_slot:
|
||||
* Find an empty slot in the daemon/fuse list
|
||||
*/
|
||||
struct delayed_action *
|
||||
d_slot()
|
||||
{
|
||||
register struct delayed_action *dev;
|
||||
|
||||
for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)
|
||||
if (dev->d_type == EMPTY)
|
||||
return dev;
|
||||
#ifdef MASTER
|
||||
debug("Ran out of fuse slots");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* find_slot:
|
||||
* Find a particular slot in the table
|
||||
*/
|
||||
struct delayed_action *
|
||||
find_slot(void (*func)(struct rogue_state *rs,int))
|
||||
{
|
||||
register struct delayed_action *dev;
|
||||
|
||||
for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)
|
||||
if (dev->d_type != EMPTY && func == dev->d_func)
|
||||
return dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* start_daemon:
|
||||
* Start a daemon, takes a function.
|
||||
*/
|
||||
void
|
||||
start_daemon(void (*func)(struct rogue_state *rs,int), int arg, int type)
|
||||
{
|
||||
register struct delayed_action *dev;
|
||||
|
||||
dev = d_slot();
|
||||
dev->d_type = type;
|
||||
dev->d_func = func;
|
||||
dev->d_arg = arg;
|
||||
dev->d_time = DAEMON;
|
||||
}
|
||||
|
||||
/*
|
||||
* kill_daemon:
|
||||
* Remove a daemon from the list
|
||||
*/
|
||||
void
|
||||
kill_daemon(void (*func)(struct rogue_state *rs,int))
|
||||
{
|
||||
register struct delayed_action *dev;
|
||||
|
||||
if ((dev = find_slot(func)) == NULL)
|
||||
return;
|
||||
/*
|
||||
* Take it out of the list
|
||||
*/
|
||||
dev->d_type = EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_daemons:
|
||||
* Run all the daemons that are active with the current flag,
|
||||
* passing the argument to the function.
|
||||
*/
|
||||
void
|
||||
do_daemons(struct rogue_state *rs,int flag)
|
||||
{
|
||||
register struct delayed_action *dev;
|
||||
|
||||
/*
|
||||
* Loop through the devil list
|
||||
*/
|
||||
for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)
|
||||
/*
|
||||
* Executing each one, giving it the proper arguments
|
||||
*/
|
||||
if (dev->d_type == flag && dev->d_time == DAEMON)
|
||||
(*dev->d_func)(rs,dev->d_arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* fuse:
|
||||
* Start a fuse to go off in a certain number of turns
|
||||
*/
|
||||
void
|
||||
fuse(void (*func)(struct rogue_state *rs,int), int arg, int time, int type)
|
||||
{
|
||||
register struct delayed_action *wire;
|
||||
|
||||
wire = d_slot();
|
||||
wire->d_type = type;
|
||||
wire->d_func = func;
|
||||
wire->d_arg = arg;
|
||||
wire->d_time = time;
|
||||
}
|
||||
|
||||
/*
|
||||
* lengthen:
|
||||
* Increase the time until a fuse goes off
|
||||
*/
|
||||
void
|
||||
lengthen(void (*func)(struct rogue_state *rs,int), int xtime)
|
||||
{
|
||||
register struct delayed_action *wire;
|
||||
|
||||
if ((wire = find_slot(func)) == NULL)
|
||||
return;
|
||||
wire->d_time += xtime;
|
||||
}
|
||||
|
||||
/*
|
||||
* extinguish:
|
||||
* Put out a fuse
|
||||
*/
|
||||
void
|
||||
extinguish(void (*func)(struct rogue_state *rs,int))
|
||||
{
|
||||
register struct delayed_action *wire;
|
||||
|
||||
if ((wire = find_slot(func)) == NULL)
|
||||
return;
|
||||
wire->d_type = EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_fuses:
|
||||
* Decrement counters and start needed fuses
|
||||
*/
|
||||
|
||||
/*char *actionfunc_str(char *str,void *ptr)
|
||||
{
|
||||
if ( ptr == (void *)runners )
|
||||
strcpy(str,"runners");
|
||||
else if ( ptr == (void *)doctor )
|
||||
strcpy(str,"doctor");
|
||||
else if ( ptr == (void *)stomach )
|
||||
strcpy(str,"stomach");
|
||||
else if ( ptr == (void *)nohaste )
|
||||
strcpy(str,"nohaste");
|
||||
else if ( ptr == (void *)unconfuse )
|
||||
strcpy(str,"unconfuse");
|
||||
else if ( ptr == (void *)swander )
|
||||
strcpy(str,"swander");
|
||||
else if ( ptr == (void *)come_down )
|
||||
strcpy(str,"come_down");
|
||||
else if ( ptr == (void *)unsee )
|
||||
strcpy(str,"unsee");
|
||||
else if ( ptr == (void *)sight )
|
||||
strcpy(str,"sight");
|
||||
else if ( ptr == (void *)land )
|
||||
strcpy(str,"land");
|
||||
else if ( ptr == (void *)rollwand )
|
||||
strcpy(str,"rollwand");
|
||||
else if ( ptr == (void *)visuals )
|
||||
strcpy(str,"visuals");
|
||||
else if ( ptr == (void *)turn_see )
|
||||
strcpy(str,"turn_see");
|
||||
else strcpy(str,"no match");
|
||||
return(str);
|
||||
}*/
|
||||
|
||||
void
|
||||
do_fuses(struct rogue_state *rs,int flag)
|
||||
{
|
||||
register struct delayed_action *wire; char str[64];
|
||||
|
||||
/*
|
||||
* Step though the list
|
||||
*/
|
||||
for (wire = d_list; wire <= &d_list[MAXDAEMONS-1]; wire++)
|
||||
/*
|
||||
* Decrementing counters and starting things we want. We also need
|
||||
* to remove the fuse from the list once it has gone off.
|
||||
*/
|
||||
if (flag == wire->d_type && wire->d_time > 0 && --wire->d_time == 0)
|
||||
{
|
||||
//if ( fp != 0 )
|
||||
// fprintf(fp,"t.%d %d %s, ",wire->d_type,wire->d_time,actionfunc_str(str,wire->d_func));
|
||||
wire->d_type = EMPTY;
|
||||
(*wire->d_func)(rs,wire->d_arg);
|
||||
}
|
||||
}
|
||||
361
src/cc/rogue/daemons.c
Normal file
361
src/cc/rogue/daemons.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* All the daemon and fuse functions are in here
|
||||
*
|
||||
* @(#)daemons.c 4.24 (Berkeley) 02/05/99
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <curses.h>
|
||||
#include "rogue.h"
|
||||
|
||||
/*
|
||||
* doctor:
|
||||
* A healing daemon that restors hit points after rest
|
||||
*/
|
||||
void
|
||||
doctor(struct rogue_state *rs,int arg)
|
||||
{
|
||||
register int lv, ohp;
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"doctor\n");
|
||||
|
||||
lv = pstats.s_lvl;
|
||||
ohp = pstats.s_hpt;
|
||||
quiet++;
|
||||
if (lv < 8)
|
||||
{
|
||||
if (quiet + (lv << 1) > 20)
|
||||
pstats.s_hpt++;
|
||||
}
|
||||
else
|
||||
if (quiet >= 3)
|
||||
pstats.s_hpt += rnd(lv - 7) + 1;
|
||||
if (ISRING(LEFT, R_REGEN))
|
||||
pstats.s_hpt++;
|
||||
if (ISRING(RIGHT, R_REGEN))
|
||||
pstats.s_hpt++;
|
||||
if (ohp != pstats.s_hpt)
|
||||
{
|
||||
if (pstats.s_hpt > max_hp)
|
||||
pstats.s_hpt = max_hp;
|
||||
quiet = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Swander:
|
||||
* Called when it is time to start rolling for wandering monsters
|
||||
*/
|
||||
void
|
||||
swander(struct rogue_state *rs,int arg)
|
||||
{
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"swander\n");
|
||||
start_daemon(rollwand, 0, BEFORE);
|
||||
}
|
||||
|
||||
/*
|
||||
* rollwand:
|
||||
* Called to roll to see if a wandering monster starts up
|
||||
*/
|
||||
int between = 0;
|
||||
void
|
||||
rollwand(struct rogue_state *rs,int arg)
|
||||
{
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"rollwand\n");
|
||||
if (++between >= 4)
|
||||
{
|
||||
if (roll(1, 6) == 4)
|
||||
{
|
||||
wanderer(rs);
|
||||
kill_daemon(rollwand);
|
||||
fuse(swander, 0, WANDERTIME, BEFORE);
|
||||
}
|
||||
between = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* unconfuse:
|
||||
* Release the poor player from his confusion
|
||||
*/
|
||||
void
|
||||
unconfuse(struct rogue_state *rs,int arg)
|
||||
{
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"unconfuse\n");
|
||||
player.t_flags &= ~ISHUH;
|
||||
msg(rs,"you feel less %s now", choose_str("trippy", "confused"));
|
||||
}
|
||||
|
||||
/*
|
||||
* unsee:
|
||||
* Turn off the ability to see invisible
|
||||
*/
|
||||
void
|
||||
unsee(struct rogue_state *rs,int arg)
|
||||
{
|
||||
register THING *th;
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"unsee\n");
|
||||
|
||||
for (th = mlist; th != NULL; th = next(th))
|
||||
if (on(*th, ISINVIS) && see_monst(th))
|
||||
mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
|
||||
player.t_flags &= ~CANSEE;
|
||||
}
|
||||
|
||||
/*
|
||||
* sight:
|
||||
* He gets his sight back
|
||||
*/
|
||||
void
|
||||
sight(struct rogue_state *rs,int arg)
|
||||
{
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"sight\n");
|
||||
if (on(player, ISBLIND))
|
||||
{
|
||||
extinguish(sight);
|
||||
player.t_flags &= ~ISBLIND;
|
||||
if (!(proom->r_flags & ISGONE))
|
||||
enter_room(rs,&hero);
|
||||
msg(rs,choose_str("far out! Everything is all cosmic again",
|
||||
"the veil of darkness lifts"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* nohaste:
|
||||
* End the hasting
|
||||
*/
|
||||
void
|
||||
nohaste(struct rogue_state *rs,int arg)
|
||||
{
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"nohaste\n");
|
||||
player.t_flags &= ~ISHASTE;
|
||||
msg(rs,"you feel yourself slowing down");
|
||||
}
|
||||
|
||||
/*
|
||||
* stomach:
|
||||
* Digest the hero's food
|
||||
*/
|
||||
void
|
||||
stomach(struct rogue_state *rs,int arg)
|
||||
{
|
||||
register int oldfood;
|
||||
int orig_hungry = hungry_state;
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"stomach\n");
|
||||
|
||||
if (food_left <= 0)
|
||||
{
|
||||
if (food_left-- < -STARVETIME)
|
||||
death(rs,'s');
|
||||
/*
|
||||
* the hero is fainting
|
||||
*/
|
||||
if (no_command || rnd(5) != 0)
|
||||
return;
|
||||
no_command += rnd(8) + 4;
|
||||
hungry_state = 3;
|
||||
if (!terse)
|
||||
addmsg(rs,choose_str("the munchies overpower your motor capabilities. ",
|
||||
"you feel too weak from lack of food. "));
|
||||
msg(rs,choose_str("You freak out", "You faint"));
|
||||
}
|
||||
else
|
||||
{
|
||||
oldfood = food_left;
|
||||
food_left -= ring_eat(LEFT) + ring_eat(RIGHT) + 1 - amulet;
|
||||
|
||||
if (food_left < MORETIME && oldfood >= MORETIME)
|
||||
{
|
||||
hungry_state = 2;
|
||||
msg(rs,choose_str("the munchies are interfering with your motor capabilites",
|
||||
"you are starting to feel weak"));
|
||||
}
|
||||
else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)
|
||||
{
|
||||
hungry_state = 1;
|
||||
if (terse)
|
||||
msg(rs,choose_str("getting the munchies", "getting hungry"));
|
||||
else
|
||||
msg(rs,choose_str("you are getting the munchies",
|
||||
"you are starting to get hungry"));
|
||||
}
|
||||
}
|
||||
if (hungry_state != orig_hungry) {
|
||||
player.t_flags &= ~ISRUN;
|
||||
running = FALSE;
|
||||
to_death = FALSE;
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* come_down:
|
||||
* Take the hero down off her acid trip.
|
||||
*/
|
||||
void
|
||||
come_down(struct rogue_state *rs,int arg)
|
||||
{
|
||||
register THING *tp;
|
||||
register bool seemonst;
|
||||
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"come_down\n");
|
||||
if (!on(player, ISHALU))
|
||||
return;
|
||||
|
||||
kill_daemon(visuals);
|
||||
player.t_flags &= ~ISHALU;
|
||||
|
||||
if (on(player, ISBLIND))
|
||||
return;
|
||||
|
||||
/*
|
||||
* undo the things
|
||||
*/
|
||||
for (tp = lvl_obj; tp != NULL; tp = next(tp))
|
||||
if (cansee(rs,tp->o_pos.y, tp->o_pos.x))
|
||||
mvaddch(tp->o_pos.y, tp->o_pos.x, tp->o_type);
|
||||
|
||||
/*
|
||||
* undo the monsters
|
||||
*/
|
||||
seemonst = on(player, SEEMONST);
|
||||
for (tp = mlist; tp != NULL; tp = next(tp))
|
||||
{
|
||||
move(tp->t_pos.y, tp->t_pos.x);
|
||||
if (cansee(rs,tp->t_pos.y, tp->t_pos.x))
|
||||
if (!on(*tp, ISINVIS) || on(player, CANSEE))
|
||||
addch(tp->t_disguise);
|
||||
else
|
||||
addch(chat(tp->t_pos.y, tp->t_pos.x));
|
||||
else if (seemonst)
|
||||
{
|
||||
standout();
|
||||
addch(tp->t_type);
|
||||
standend();
|
||||
}
|
||||
}
|
||||
msg(rs,"Everything looks SO boring now.");
|
||||
}
|
||||
|
||||
/*
|
||||
* visuals:
|
||||
* change the characters for the player
|
||||
*/
|
||||
void
|
||||
visuals(struct rogue_state *rs,int arg)
|
||||
{
|
||||
register THING *tp;
|
||||
register bool seemonst;
|
||||
|
||||
if (!after || (running && jump))
|
||||
return;
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"visuals\n");
|
||||
/*
|
||||
* change the things
|
||||
*/
|
||||
for (tp = lvl_obj; tp != NULL; tp = next(tp))
|
||||
if (cansee(rs,tp->o_pos.y, tp->o_pos.x))
|
||||
mvaddch(tp->o_pos.y, tp->o_pos.x, rnd_thing());
|
||||
|
||||
/*
|
||||
* change the stairs
|
||||
*/
|
||||
if (!seenstairs && cansee(rs,stairs.y, stairs.x))
|
||||
mvaddch(stairs.y, stairs.x, rnd_thing());
|
||||
|
||||
/*
|
||||
* change the monsters
|
||||
*/
|
||||
seemonst = on(player, SEEMONST);
|
||||
for (tp = mlist; tp != NULL; tp = next(tp))
|
||||
{
|
||||
move(tp->t_pos.y, tp->t_pos.x);
|
||||
if (see_monst(tp))
|
||||
{
|
||||
if (tp->t_type == 'X' && tp->t_disguise != 'X')
|
||||
addch(rnd_thing());
|
||||
else
|
||||
addch(rnd(26) + 'A');
|
||||
}
|
||||
else if (seemonst)
|
||||
{
|
||||
standout();
|
||||
addch(rnd(26) + 'A');
|
||||
standend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* land:
|
||||
* Land from a levitation potion
|
||||
*/
|
||||
void
|
||||
land(struct rogue_state *rs,int arg)
|
||||
{
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"land\n");
|
||||
player.t_flags &= ~ISLEVIT;
|
||||
msg(rs,choose_str("bummer! You've hit the ground",
|
||||
"you float gently to the ground"));
|
||||
}
|
||||
|
||||
/*
|
||||
* turn_see:
|
||||
* Put on or off seeing monsters on this level
|
||||
*/
|
||||
bool
|
||||
turn_see(struct rogue_state *rs,bool turn_off)
|
||||
{
|
||||
THING *mp;
|
||||
bool can_see, add_new;
|
||||
if ( rs->logfp != 0 )
|
||||
fprintf(rs->logfp,"turn_see\n");
|
||||
|
||||
add_new = FALSE;
|
||||
for (mp = mlist; mp != NULL; mp = next(mp))
|
||||
{
|
||||
move(mp->t_pos.y, mp->t_pos.x);
|
||||
can_see = see_monst(mp);
|
||||
if (turn_off)
|
||||
{
|
||||
if (!can_see)
|
||||
addch(mp->t_oldch);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!can_see)
|
||||
standout();
|
||||
if (!on(player, ISHALU))
|
||||
addch(mp->t_type);
|
||||
else
|
||||
addch(rnd(26) + 'A');
|
||||
if (!can_see)
|
||||
{
|
||||
standend();
|
||||
add_new ^= 1;//add_new++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (turn_off)
|
||||
player.t_flags &= ~SEEMONST;
|
||||
else
|
||||
player.t_flags |= SEEMONST;
|
||||
return add_new;
|
||||
}
|
||||
|
||||
516
src/cc/rogue/extern.c
Normal file
516
src/cc/rogue/extern.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* global variable initializaton
|
||||
*
|
||||
* @(#)extern.c 4.82 (Berkeley) 02/05/99
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <curses.h>
|
||||
#include "rogue.h"
|
||||
|
||||
|
||||
|
||||
bool after; /* True if we want after daemons */
|
||||
bool again; /* Repeating the last command */
|
||||
int noscore; /* Was a wizard sometime */
|
||||
bool seenstairs; /* Have seen the stairs (for lsd) */
|
||||
bool amulet = FALSE; /* He found the amulet */
|
||||
bool door_stop = FALSE; /* Stop running when we pass a door */
|
||||
bool fight_flush = FALSE; /* True if toilet input */
|
||||
bool firstmove = FALSE; /* First move after setting door_stop */
|
||||
bool got_ltc = FALSE; /* We have gotten the local tty chars */
|
||||
bool has_hit = FALSE; /* Has a "hit" message pending in msg */
|
||||
bool in_shell = FALSE; /* True if executing a shell */
|
||||
bool inv_describe = TRUE; /* Say which way items are being used */
|
||||
bool jump = FALSE; /* Show running as series of jumps */
|
||||
bool kamikaze = FALSE; /* to_death really to DEATH */
|
||||
bool lower_msg = FALSE; /* Messages should start w/lower case */
|
||||
bool move_on = FALSE; /* Next move shouldn't pick up items */
|
||||
bool msg_esc = FALSE; /* Check for ESC from msg's --More-- */
|
||||
bool passgo = FALSE; /* Follow passages */
|
||||
bool playing = TRUE; /* True until he quits */
|
||||
bool q_comm = FALSE; /* Are we executing a 'Q' command? */
|
||||
bool running = FALSE; /* True if player is running */
|
||||
bool save_msg = TRUE; /* Remember last msg */
|
||||
bool see_floor = TRUE; /* Show the lamp illuminated floor */
|
||||
bool stat_msg = FALSE; /* Should status() print as a msg() */
|
||||
bool terse = FALSE; /* True if we should be short */
|
||||
bool to_death = FALSE; /* Fighting is to the death! */
|
||||
bool tombstone = TRUE; /* Print out tombstone at end */
|
||||
#ifdef MASTER
|
||||
int wizard = FALSE; /* True if allows wizard commands */
|
||||
#endif
|
||||
bool pack_used[26] = { /* Is the character used in the pack? */
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
|
||||
char dir_ch; /* Direction from last get_dir() call */
|
||||
char runch; /* Direction player is running */
|
||||
char take; /* Thing she is taking */
|
||||
|
||||
int orig_dsusp; /* Original dsusp char */
|
||||
char file_name[MAXSTR]; /* Save file name */
|
||||
char huh[MAXSTR]; /* The last message printed */
|
||||
char prbuf[2*MAXSTR]; /* buffer for sprintfs */
|
||||
char whoami[MAXSTR]; /* Name of player */
|
||||
char fruit[MAXSTR] = /* Favorite fruit */
|
||||
{ 's', 'l', 'i', 'm', 'e', '-', 'm', 'o', 'l', 'd', '\0' };
|
||||
char home[MAXSTR] = { '\0' }; /* User's home directory */
|
||||
char l_last_comm = '\0'; /* Last last_comm */
|
||||
char l_last_dir = '\0'; /* Last last_dir */
|
||||
char last_comm = '\0'; /* Last command typed */
|
||||
char last_dir = '\0'; /* Last direction given */
|
||||
|
||||
int n_objs; /* # items listed in inventory() call */
|
||||
int ntraps; /* Number of traps on this level */
|
||||
int hungry_state = 0; /* How hungry is he */
|
||||
int inpack = 0; /* Number of things in pack */
|
||||
int inv_type = 0; /* Type of inventory to use */
|
||||
int level = 1; /* What level she is on */
|
||||
int max_hit; /* Max damage done to her in to_death */
|
||||
int max_level; /* Deepest player has gone */
|
||||
int mpos = 0; /* Where cursor is on top line */
|
||||
int no_food = 0; /* Number of levels without food */
|
||||
|
||||
int count = 0; /* Number of times to repeat command */
|
||||
int food_left; /* Amount of food in hero's stomach */
|
||||
int lastscore = -1; /* Score before this turn */
|
||||
int no_command = 0; /* Number of turns asleep */
|
||||
int no_move = 0; /* Number of turns held in place */
|
||||
int purse = 0; /* How much gold he has */
|
||||
int quiet = 0; /* Number of quiet turns */
|
||||
int vf_hit = 0; /* Number of time flytrap has hit */
|
||||
|
||||
|
||||
//int dnum; /* Dungeon number */
|
||||
uint64_t seed; /* Random number seed */
|
||||
|
||||
coord delta; /* Change indicated to get_dir() */
|
||||
coord oldpos; /* Position before last look() call */
|
||||
coord stairs; /* Location of staircase */
|
||||
|
||||
PLACE places[MAXLINES*MAXCOLS]; /* level map */
|
||||
|
||||
const char *p_colors[MAXPOTIONS]; /* Colors of the potions */
|
||||
const char *r_stones[MAXRINGS]; /* Stone settings of the rings */
|
||||
const char *ws_made[MAXSTICKS]; /* What sticks are made of */
|
||||
const char *ws_type[MAXSTICKS]; /* Is it a wand or a staff */
|
||||
|
||||
THING *cur_armor; /* What he is wearing */
|
||||
THING *cur_ring[2]; /* Which rings are being worn */
|
||||
THING *cur_weapon; /* Which weapon he is weilding */
|
||||
THING *l_last_pick = NULL; /* Last last_pick */
|
||||
THING *last_pick = NULL; /* Last object picked in get_item() */
|
||||
THING *lvl_obj = NULL; /* List of objects on this level */
|
||||
THING *mlist = NULL; /* List of monsters on the level */
|
||||
struct room *oldrp; /* Roomin(&oldpos) */
|
||||
THING player; /* His stats */
|
||||
WINDOW *hw = NULL; /* used as a scratch window */
|
||||
char *s_names[MAXSCROLLS]; /* Names of the scrolls */
|
||||
FILE *scoreboard = NULL; /* File descriptor for score file */
|
||||
|
||||
#define INIT_STATS { 16, 0, 1, 10, 12, "1x4", 12 }
|
||||
|
||||
struct stats max_stats = INIT_STATS; /* The maximum for the player */
|
||||
struct stats orig_max_stats = INIT_STATS;
|
||||
|
||||
struct monster monsters[26];
|
||||
struct room passages[MAXPASS],rooms[MAXROOMS]; /* One for each room -- A level */
|
||||
struct obj_info things[NUMTHINGS],ring_info[MAXRINGS],pot_info[MAXPOTIONS],arm_info[MAXARMORS],scr_info[MAXSCROLLS],weap_info[MAXWEAPONS + 1],ws_info[MAXSTICKS];
|
||||
|
||||
////////////// constants
|
||||
#define ___ 1
|
||||
#define XX 10
|
||||
|
||||
const struct obj_info origthings[NUMTHINGS] = {
|
||||
{ 0, 26 }, /* potion */
|
||||
{ 0, 36 }, /* scroll */
|
||||
{ 0, 16 }, /* food */
|
||||
{ 0, 7 }, /* weapon */
|
||||
{ 0, 7 }, /* armor */
|
||||
{ 0, 4 }, /* ring */
|
||||
{ 0, 4 }, /* stick */
|
||||
};
|
||||
|
||||
const struct room origpassages[MAXPASS] = /* One for each passage */
|
||||
{
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
|
||||
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} }
|
||||
};
|
||||
const struct monster origmonsters[26] =
|
||||
{
|
||||
/* Name CARRY FLAG str, exp, lvl, amr, hpt, dmg */
|
||||
{ "aquator", 0, ISMEAN, { XX, 20, 5, 2, ___, "0x0/0x0" } },
|
||||
{ "bat", 0, ISFLY, { XX, 1, 1, 3, ___, "1x2" } },
|
||||
{ "centaur", 15, 0, { XX, 17, 4, 4, ___, "1x2/1x5/1x5" } },
|
||||
{ "dragon", 100, ISMEAN, { XX,5000, 10, -1, ___, "1x8/1x8/3x10" } },
|
||||
{ "emu", 0, ISMEAN, { XX, 2, 1, 7, ___, "1x2" } },
|
||||
{ "venus flytrap", 0, ISMEAN, { XX, 80, 8, 3, ___, "%%%x0" } },
|
||||
/* NOTE: the damage is %%% so that xstr won't merge this */
|
||||
/* string with others, since it is written on in the program */
|
||||
{ "griffin", 20, ISMEAN|ISFLY|ISREGEN, { XX,2000, 13, 2, ___, "4x3/3x5" } },
|
||||
{ "hobgoblin", 0, ISMEAN, { XX, 3, 1, 5, ___, "1x8" } },
|
||||
{ "ice monster", 0, 0, { XX, 5, 1, 9, ___, "0x0" } },
|
||||
{ "jabberwock", 70, 0, { XX,3000, 15, 6, ___, "2x12/2x4" } },
|
||||
{ "kestrel", 0, ISMEAN|ISFLY, { XX, 1, 1, 7, ___, "1x4" } },
|
||||
{ "leprechaun", 0, 0, { XX, 10, 3, 8, ___, "1x1" } },
|
||||
{ "medusa", 40, ISMEAN, { XX,200, 8, 2, ___, "3x4/3x4/2x5" } },
|
||||
{ "nymph", 100, 0, { XX, 37, 3, 9, ___, "0x0" } },
|
||||
{ "orc", 15, ISGREED,{ XX, 5, 1, 6, ___, "1x8" } },
|
||||
{ "phantom", 0, ISINVIS,{ XX,120, 8, 3, ___, "4x4" } },
|
||||
{ "quagga", 0, ISMEAN, { XX, 15, 3, 3, ___, "1x5/1x5" } },
|
||||
{ "rattlesnake", 0, ISMEAN, { XX, 9, 2, 3, ___, "1x6" } },
|
||||
{ "snake", 0, ISMEAN, { XX, 2, 1, 5, ___, "1x3" } },
|
||||
{ "troll", 50, ISREGEN|ISMEAN,{ XX, 120, 6, 4, ___, "1x8/1x8/2x6" } },
|
||||
{ "black unicorn", 0, ISMEAN, { XX,190, 7, -2, ___, "1x9/1x9/2x9" } },
|
||||
{ "vampire", 20, ISREGEN|ISMEAN,{ XX,350, 8, 1, ___, "1x10" } },
|
||||
{ "wraith", 0, 0, { XX, 55, 5, 4, ___, "1x6" } },
|
||||
{ "xeroc", 30, 0, { XX,100, 7, 7, ___, "4x4" } },
|
||||
{ "yeti", 30, 0, { XX, 50, 4, 6, ___, "1x6/1x6" } },
|
||||
{ "zombie", 0, ISMEAN, { XX, 6, 2, 8, ___, "1x8" } }
|
||||
};
|
||||
#undef ___
|
||||
#undef XX
|
||||
|
||||
const struct obj_info origarm_info[MAXARMORS] = {
|
||||
{ "leather armor", 20, 20, NULL, FALSE },
|
||||
{ "ring mail", 15, 25, NULL, FALSE },
|
||||
{ "studded leather armor", 15, 20, NULL, FALSE },
|
||||
{ "scale mail", 13, 30, NULL, FALSE },
|
||||
{ "chain mail", 12, 75, NULL, FALSE },
|
||||
{ "splint mail", 10, 80, NULL, FALSE },
|
||||
{ "banded mail", 10, 90, NULL, FALSE },
|
||||
{ "plate mail", 5, 150, NULL, FALSE },
|
||||
};
|
||||
const struct obj_info origpot_info[MAXPOTIONS] = {
|
||||
{ "confusion", 7, 5, NULL, FALSE },
|
||||
{ "hallucination", 8, 5, NULL, FALSE },
|
||||
{ "poison", 8, 5, NULL, FALSE },
|
||||
{ "gain strength", 13, 150, NULL, FALSE },
|
||||
{ "see invisible", 3, 100, NULL, FALSE },
|
||||
{ "healing", 13, 130, NULL, FALSE },
|
||||
{ "monster detection", 6, 130, NULL, FALSE },
|
||||
{ "magic detection", 6, 105, NULL, FALSE },
|
||||
{ "raise level", 2, 250, NULL, FALSE },
|
||||
{ "extra healing", 5, 200, NULL, FALSE },
|
||||
{ "haste self", 5, 190, NULL, FALSE },
|
||||
{ "restore strength", 13, 130, NULL, FALSE },
|
||||
{ "blindness", 5, 5, NULL, FALSE },
|
||||
{ "levitation", 6, 75, NULL, FALSE },
|
||||
};
|
||||
const struct obj_info origring_info[MAXRINGS] = {
|
||||
{ "protection", 9, 400, NULL, FALSE },
|
||||
{ "add strength", 9, 400, NULL, FALSE },
|
||||
{ "sustain strength", 5, 280, NULL, FALSE },
|
||||
{ "searching", 10, 420, NULL, FALSE },
|
||||
{ "see invisible", 10, 310, NULL, FALSE },
|
||||
{ "adornment", 1, 10, NULL, FALSE },
|
||||
{ "aggravate monster", 10, 10, NULL, FALSE },
|
||||
{ "dexterity", 8, 440, NULL, FALSE },
|
||||
{ "increase damage", 8, 400, NULL, FALSE },
|
||||
{ "regeneration", 4, 460, NULL, FALSE },
|
||||
{ "slow digestion", 9, 240, NULL, FALSE },
|
||||
{ "teleportation", 5, 30, NULL, FALSE },
|
||||
{ "stealth", 7, 470, NULL, FALSE },
|
||||
{ "maintain armor", 5, 380, NULL, FALSE },
|
||||
};
|
||||
const struct obj_info origscr_info[MAXSCROLLS] = {
|
||||
{ "monster confusion", 7, 140, NULL, FALSE },
|
||||
{ "magic mapping", 4, 150, NULL, FALSE },
|
||||
{ "hold monster", 2, 180, NULL, FALSE },
|
||||
{ "sleep", 3, 5, NULL, FALSE },
|
||||
{ "enchant armor", 7, 160, NULL, FALSE },
|
||||
{ "identify potion", 10, 80, NULL, FALSE },
|
||||
{ "identify scroll", 10, 80, NULL, FALSE },
|
||||
{ "identify weapon", 6, 80, NULL, FALSE },
|
||||
{ "identify armor", 7, 100, NULL, FALSE },
|
||||
{ "identify ring, wand or staff", 10, 115, NULL, FALSE },
|
||||
{ "scare monster", 3, 200, NULL, FALSE },
|
||||
{ "food detection", 2, 60, NULL, FALSE },
|
||||
{ "teleportation", 5, 165, NULL, FALSE },
|
||||
{ "enchant weapon", 8, 150, NULL, FALSE },
|
||||
{ "create monster", 4, 75, NULL, FALSE },
|
||||
{ "remove curse", 7, 105, NULL, FALSE },
|
||||
{ "aggravate monsters", 3, 20, NULL, FALSE },
|
||||
{ "protect armor", 2, 250, NULL, FALSE },
|
||||
};
|
||||
const struct obj_info origweap_info[MAXWEAPONS + 1] = {
|
||||
{ "mace", 11, 8, NULL, FALSE },
|
||||
{ "long sword", 11, 15, NULL, FALSE },
|
||||
{ "short bow", 12, 15, NULL, FALSE },
|
||||
{ "arrow", 12, 1, NULL, FALSE },
|
||||
{ "dagger", 8, 3, NULL, FALSE },
|
||||
{ "two handed sword", 10, 75, NULL, FALSE },
|
||||
{ "dart", 12, 2, NULL, FALSE },
|
||||
{ "shuriken", 12, 5, NULL, FALSE },
|
||||
{ "spear", 12, 5, NULL, FALSE },
|
||||
{ NULL, 0 }, /* DO NOT REMOVE: fake entry for dragon's breath */
|
||||
};
|
||||
const struct obj_info origws_info[MAXSTICKS] = {
|
||||
{ "light", 12, 250, NULL, FALSE },
|
||||
{ "invisibility", 6, 5, NULL, FALSE },
|
||||
{ "lightning", 3, 330, NULL, FALSE },
|
||||
{ "fire", 3, 330, NULL, FALSE },
|
||||
{ "cold", 3, 330, NULL, FALSE },
|
||||
{ "polymorph", 15, 310, NULL, FALSE },
|
||||
{ "magic missile", 10, 170, NULL, FALSE },
|
||||
{ "haste monster", 10, 5, NULL, FALSE },
|
||||
{ "slow monster", 11, 350, NULL, FALSE },
|
||||
{ "drain life", 9, 300, NULL, FALSE },
|
||||
{ "nothing", 1, 5, NULL, FALSE },
|
||||
{ "teleport away", 6, 340, NULL, FALSE },
|
||||
{ "teleport to", 6, 50, NULL, FALSE },
|
||||
{ "cancellation", 5, 280, NULL, FALSE },
|
||||
};
|
||||
|
||||
const struct h_list helpstr[] = {
|
||||
{'?', " prints help", TRUE},
|
||||
{'/', " identify object", TRUE},
|
||||
{'h', " left", TRUE},
|
||||
{'j', " down", TRUE},
|
||||
{'k', " up", TRUE},
|
||||
{'l', " right", TRUE},
|
||||
{'y', " up & left", TRUE},
|
||||
{'u', " up & right", TRUE},
|
||||
{'b', " down & left", TRUE},
|
||||
{'n', " down & right", TRUE},
|
||||
{'H', " run left", FALSE},
|
||||
{'J', " run down", FALSE},
|
||||
{'K', " run up", FALSE},
|
||||
{'L', " run right", FALSE},
|
||||
{'Y', " run up & left", FALSE},
|
||||
{'U', " run up & right", FALSE},
|
||||
{'B', " run down & left", FALSE},
|
||||
{'N', " run down & right", FALSE},
|
||||
{CTRL('H'), " run left until adjacent", FALSE},
|
||||
{CTRL('J'), " run down until adjacent", FALSE},
|
||||
{CTRL('K'), " run up until adjacent", FALSE},
|
||||
{CTRL('L'), " run right until adjacent", FALSE},
|
||||
{CTRL('Y'), " run up & left until adjacent", FALSE},
|
||||
{CTRL('U'), " run up & right until adjacent", FALSE},
|
||||
{CTRL('B'), " run down & left until adjacent", FALSE},
|
||||
{CTRL('N'), " run down & right until adjacent", FALSE},
|
||||
{'\0', " <SHIFT><dir>: run that way", TRUE},
|
||||
{'\0', " <CTRL><dir>: run till adjacent", TRUE},
|
||||
{'f', "<dir> fight till death or near death", TRUE},
|
||||
{'t', "<dir> throw something", TRUE},
|
||||
{'m', "<dir> move onto without picking up", TRUE},
|
||||
{'z', "<dir> zap a wand in a direction", TRUE},
|
||||
{'^', "<dir> identify trap type", TRUE},
|
||||
{'s', " search for trap/secret door", TRUE},
|
||||
{'>', " go down a staircase", TRUE},
|
||||
{'<', " go up a staircase", TRUE},
|
||||
{'.', " rest for a turn", TRUE},
|
||||
{',', " pick something up", TRUE},
|
||||
{'i', " inventory", TRUE},
|
||||
{'I', " inventory single item", TRUE},
|
||||
{'q', " quaff potion", TRUE},
|
||||
{'r', " read scroll", TRUE},
|
||||
{'e', " eat food", TRUE},
|
||||
{'w', " wield a weapon", TRUE},
|
||||
{'W', " wear armor", TRUE},
|
||||
{'T', " take armor off", TRUE},
|
||||
{'P', " put on ring", TRUE},
|
||||
{'R', " remove ring", TRUE},
|
||||
{'d', " drop object", TRUE},
|
||||
{'c', " call object", TRUE},
|
||||
{'a', " repeat last command", TRUE},
|
||||
{')', " print current weapon", TRUE},
|
||||
{']', " print current armor", TRUE},
|
||||
{'=', " print current rings", TRUE},
|
||||
{'@', " print current stats", TRUE},
|
||||
{'D', " recall what's been discovered", TRUE},
|
||||
{'o', " examine/set options", TRUE},
|
||||
{CTRL('R'), " redraw screen", TRUE},
|
||||
{CTRL('P'), " repeat last message", TRUE},
|
||||
{ESCAPE, " cancel command", TRUE},
|
||||
{'S', " save game", TRUE},
|
||||
{'Q', " quit", TRUE},
|
||||
{'!', " shell escape", TRUE},
|
||||
{'F', "<dir> fight till either of you dies", TRUE},
|
||||
{'v', " print version number", TRUE},
|
||||
{0, NULL }
|
||||
};
|
||||
|
||||
const char *inv_t_name[] = {
|
||||
"Overwrite",
|
||||
"Slow",
|
||||
"Clear"
|
||||
};
|
||||
|
||||
const char *tr_name[] = { /* Names of the traps */
|
||||
"a trapdoor",
|
||||
"an arrow trap",
|
||||
"a sleeping gas trap",
|
||||
"a beartrap",
|
||||
"a teleport trap",
|
||||
"a poison dart trap",
|
||||
"a rust trap",
|
||||
"a mysterious trap"
|
||||
};
|
||||
|
||||
const int32_t a_class[MAXARMORS] = { /* Armor class for each armor type */
|
||||
8, /* LEATHER */
|
||||
7, /* RING_MAIL */
|
||||
7, /* STUDDED_LEATHER */
|
||||
6, /* SCALE_MAIL */
|
||||
5, /* CHAIN_MAIL */
|
||||
4, /* SPLINT_MAIL */
|
||||
4, /* BANDED_MAIL */
|
||||
3, /* PLATE_MAIL */
|
||||
};
|
||||
|
||||
const int32_t e_levels[] = {
|
||||
10L,
|
||||
20L,
|
||||
40L,
|
||||
80L,
|
||||
160L,
|
||||
320L,
|
||||
640L,
|
||||
1300L,
|
||||
2600L,
|
||||
5200L,
|
||||
13000L,
|
||||
26000L,
|
||||
50000L,
|
||||
100000L,
|
||||
200000L,
|
||||
400000L,
|
||||
800000L,
|
||||
2000000L,
|
||||
4000000L,
|
||||
8000000L,
|
||||
0L
|
||||
};
|
||||
|
||||
#include <memory.h>
|
||||
extern int between;
|
||||
extern int group;
|
||||
extern coord nh;
|
||||
|
||||
void externs_clear()
|
||||
{
|
||||
int i;
|
||||
after = 0; /* True if we want after daemons */
|
||||
again = 0; /* Repeating the last command */
|
||||
noscore = 0; /* Was a wizard sometime */
|
||||
seenstairs = 0; /* Have seen the stairs (for lsd) */
|
||||
amulet = FALSE; /* He found the amulet */
|
||||
door_stop = FALSE; /* Stop running when we pass a door */
|
||||
fight_flush = FALSE; /* True if toilet input */
|
||||
firstmove = FALSE; /* First move after setting door_stop */
|
||||
got_ltc = FALSE; /* We have gotten the local tty chars */
|
||||
has_hit = FALSE; /* Has a "hit" message pending in msg */
|
||||
in_shell = FALSE; /* True if executing a shell */
|
||||
inv_describe = TRUE; /* Say which way items are being used */
|
||||
jump = FALSE; /* Show running as series of jumps */
|
||||
kamikaze = FALSE; /* to_death really to DEATH */
|
||||
lower_msg = FALSE; /* Messages should start w/lower case */
|
||||
move_on = FALSE; /* Next move shouldn't pick up items */
|
||||
msg_esc = FALSE; /* Check for ESC from msg's --More-- */
|
||||
passgo = FALSE; /* Follow passages */
|
||||
playing = TRUE; /* True until he quits */
|
||||
q_comm = FALSE; /* Are we executing a 'Q' command? */
|
||||
running = FALSE; /* True if player is running */
|
||||
save_msg = TRUE; /* Remember last msg */
|
||||
see_floor = TRUE; /* Show the lamp illuminated floor */
|
||||
stat_msg = FALSE; /* Should status() print as a msg() */
|
||||
terse = FALSE; /* True if we should be short */
|
||||
to_death = FALSE; /* Fighting is to the death! */
|
||||
tombstone = TRUE; /* Print out tombstone at end */
|
||||
#ifdef MASTER
|
||||
int wizard = FALSE; /* True if allows wizard commands */
|
||||
#endif
|
||||
for (i=0; i<26; i++)
|
||||
pack_used[i] = FALSE;
|
||||
for (i=0; i<MAXSCROLLS; i++)
|
||||
if ( s_names[i] != 0 )
|
||||
free(s_names[i]);
|
||||
memset(s_names,0,sizeof(s_names));
|
||||
|
||||
dir_ch = 0; /* Direction from last get_dir() call */
|
||||
memset(file_name,0,sizeof(file_name));
|
||||
memset(huh,0,sizeof(huh));
|
||||
memset(p_colors,0,sizeof(p_colors));
|
||||
memset(prbuf,0,sizeof(prbuf));
|
||||
memset(r_stones,0,sizeof(r_stones));
|
||||
//memset(whoami,0,sizeof(whoami));
|
||||
memset(ws_made,0,sizeof(ws_made));
|
||||
memset(ws_type,0,sizeof(ws_type));
|
||||
runch = 0; /* Direction player is running */
|
||||
take = 0; /* Thing she is taking */
|
||||
orig_dsusp = 0; /* Original dsusp char */
|
||||
memset(home,0,sizeof(home));
|
||||
l_last_comm = '\0'; /* Last last_comm */
|
||||
l_last_dir = '\0'; /* Last last_dir */
|
||||
last_comm = '\0'; /* Last command typed */
|
||||
last_dir = '\0'; /* Last direction given */
|
||||
|
||||
n_objs = 0; /* # items listed in inventory() call */
|
||||
ntraps = 0; /* Number of traps on this level */
|
||||
hungry_state = 0; /* How hungry is he */
|
||||
inpack = 0; /* Number of things in pack */
|
||||
inv_type = 0; /* Type of inventory to use */
|
||||
level = 1; /* What level she is on */
|
||||
max_hit= 0; /* Max damage done to her in to_death */
|
||||
max_level = 0; /* Deepest player has gone */
|
||||
mpos = 0; /* Where cursor is on top line */
|
||||
no_food = 0; /* Number of levels without food */
|
||||
|
||||
count = 0; /* Number of times to repeat command */
|
||||
if ( scoreboard != NULL )
|
||||
{
|
||||
fclose(scoreboard);
|
||||
scoreboard = NULL; /* File descriptor for score file */
|
||||
}
|
||||
food_left = 0; /* Amount of food in hero's stomach */
|
||||
lastscore = -1; /* Score before this turn */
|
||||
no_command = 0; /* Number of turns asleep */
|
||||
no_move = 0; /* Number of turns held in place */
|
||||
purse = 0; /* How much gold he has */
|
||||
quiet = 0; /* Number of quiet turns */
|
||||
vf_hit = 0; /* Number of time flytrap has hit */
|
||||
|
||||
|
||||
memset(&delta,0,sizeof(delta));
|
||||
memset(&oldpos,0,sizeof(oldpos));
|
||||
memset(&stairs,0,sizeof(stairs));
|
||||
|
||||
memset(places,0,sizeof(places));
|
||||
cur_armor = NULL; /* What he is wearing */
|
||||
cur_ring[0] = cur_ring[1] = NULL; /* Which rings are being worn */
|
||||
cur_weapon = NULL; /* Which weapon he is weilding */
|
||||
l_last_pick = NULL; /* Last last_pick */
|
||||
last_pick = NULL; /* Last object picked in get_item() */
|
||||
lvl_obj = NULL; /* List of objects on this level */
|
||||
mlist = NULL; /* List of monsters on the level */
|
||||
memset(&player,0,sizeof(player)); /* His stats */
|
||||
/* restart of game */
|
||||
|
||||
max_stats = orig_max_stats; /* The maximum for the player */
|
||||
|
||||
oldrp = 0; /* Roomin(&oldpos) */
|
||||
memset(rooms,0,sizeof(rooms)); /* One for each room -- A level */
|
||||
|
||||
between = 0;
|
||||
group = 0;
|
||||
memset(&nh,0,sizeof(nh));
|
||||
}
|
||||
200
src/cc/rogue/extern.h
Normal file
200
src/cc/rogue/extern.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Defines for things used in mach_dep.c
|
||||
*
|
||||
* @(#)extern.h 4.35 (Berkeley) 02/05/99
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
#ifndef H_EXTERN_ROGUE_H
|
||||
#define H_EXTERN_ROGUE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#ifdef PDCURSES
|
||||
#undef HAVE_UNISTD_H
|
||||
#undef HAVE_LIMITS_H
|
||||
#undef HAVE_MEMORY_H
|
||||
#undef HAVE_STRING_H
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#elif defined(__DJGPP__)
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_PROCESS_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_TERMIOS_H 1
|
||||
#define HAVE_SETGID 1
|
||||
#define HAVE_GETGID 1
|
||||
#define HAVE_SETUID 1
|
||||
#define HAVE_GETUID 1
|
||||
#define HAVE_GETPASS 1
|
||||
#define HAVE_SPAWNL 1
|
||||
#define HAVE_ALARM 1
|
||||
#define HAVE_ERASECHAR 1
|
||||
#define HAVE_KILLCHAR 1
|
||||
#elif defined(_WIN32)
|
||||
#define HAVE_CURSES_H
|
||||
#define HAVE_TERM_H
|
||||
#define HAVE__SPAWNL
|
||||
#define HAVE_SYS_TYPES_H
|
||||
#define HAVE_PROCESS_H
|
||||
#define HAVE_ERASECHAR 1
|
||||
#define HAVE_KILLCHAR 1
|
||||
#elif defined(__CYGWIN__)
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_SYS_UTSNAME_H 1
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_TERMIOS_H 1
|
||||
#define HAVE_NCURSES_TERM_H 1
|
||||
#define HAVE_ESCDELAY
|
||||
#define HAVE_SETGID 1
|
||||
#define HAVE_GETGID 1
|
||||
#define HAVE_SETUID 1
|
||||
#define HAVE_GETUID 1
|
||||
#define HAVE_GETPASS 1
|
||||
#define HAVE_GETPWUID 1
|
||||
#define HAVE_WORKING_FORK 1
|
||||
#define HAVE_ALARM 1
|
||||
#define HAVE_SPAWNL 1
|
||||
#define HAVE__SPAWNL 1
|
||||
#define HAVE_ERASECHAR 1
|
||||
#define HAVE_KILLCHAR 1
|
||||
#else /* POSIX */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_SYS_UTSNAME_H 1
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_TERMIOS_H 1
|
||||
#define HAVE_TERM_H 1
|
||||
#define HAVE_SETGID 1
|
||||
#define HAVE_GETGID 1
|
||||
#define HAVE_SETUID 1
|
||||
#define HAVE_GETUID 1
|
||||
#define HAVE_SETREUID 1
|
||||
#define HAVE_SETREGID 1
|
||||
#define HAVE_GETPASS 1
|
||||
#define HAVE_GETPWUID 1
|
||||
#define HAVE_WORKING_FORK 1
|
||||
#define HAVE_ERASECHAR 1
|
||||
#define HAVE_KILLCHAR 1
|
||||
#ifndef _AIX
|
||||
#define HAVE_GETLOADAVG 1
|
||||
#endif
|
||||
#define HAVE_ALARM 1
|
||||
#endif
|
||||
|
||||
#ifdef __DJGPP__
|
||||
#undef HAVE_GETPWUID /* DJGPP's limited version doesn't even work as documented */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't change the constants, since they are used for sizes in many
|
||||
* places in the program.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef SIGTSTP
|
||||
|
||||
#define MAXSTR 1024 /* maximum length of strings */
|
||||
#define MAXLINES 32 /* maximum number of screen lines used */
|
||||
#define MAXCOLS 80 /* maximum number of screen columns used */
|
||||
|
||||
#define RN ((int32_t)((seed = seed*11109+13849) >> 16) & 0xffff)
|
||||
#ifdef CTRL
|
||||
#undef CTRL
|
||||
#endif
|
||||
#define CTRL(c) (c & 037)
|
||||
|
||||
/*
|
||||
* Now all the global variables
|
||||
*/
|
||||
|
||||
extern bool got_ltc, in_shell;
|
||||
extern int wizard;
|
||||
extern char fruit[], prbuf[], whoami[];
|
||||
extern int orig_dsusp;
|
||||
extern FILE *scoreboard;
|
||||
|
||||
/*
|
||||
* Function types
|
||||
*/
|
||||
void externs_clear();
|
||||
|
||||
void auto_save(int);
|
||||
void endit(int sig);
|
||||
void fatal(char *);
|
||||
void getltchars(void);
|
||||
void leave(int);
|
||||
void my_exit(int st);
|
||||
void playltchars(void);
|
||||
void quit(int);
|
||||
int32_t _quit();
|
||||
|
||||
void resetltchars(void);
|
||||
void set_order(int *order, int numthings);
|
||||
void tstp(int ignored);
|
||||
|
||||
char *killname(char monst, bool doart);
|
||||
char *nothing(char type);
|
||||
char *type_name(int type);
|
||||
|
||||
#ifdef CHECKTIME
|
||||
int checkout(void);
|
||||
#endif
|
||||
|
||||
int md_chmod(char *filename, int mode);
|
||||
char *md_crypt(char *key, char *salt);
|
||||
int md_dsuspchar(void);
|
||||
int md_erasechar(void);
|
||||
char *md_gethomedir(void);
|
||||
char *md_getusername(void);
|
||||
int md_getuid(void);
|
||||
char *md_getpass(char *prompt);
|
||||
int md_getpid(void);
|
||||
char *md_getrealname(int uid);
|
||||
void md_init(void);
|
||||
int md_killchar(void);
|
||||
void md_normaluser(void);
|
||||
void md_raw_standout(void);
|
||||
void md_raw_standend(void);
|
||||
int md_readchar(void);
|
||||
int md_setdsuspchar(int c);
|
||||
int md_shellescape(void);
|
||||
void md_sleep(int s);
|
||||
int md_suspchar(void);
|
||||
int md_hasclreol(void);
|
||||
int md_unlink(char *file);
|
||||
int md_unlink_open_file(char *file, FILE *inf);
|
||||
void md_tstpsignal(void);
|
||||
void md_tstphold(void);
|
||||
void md_tstpresume(void);
|
||||
void md_ignoreallsignals(void);
|
||||
void md_onsignal_autosave(void);
|
||||
void md_onsignal_exit(void);
|
||||
void md_onsignal_default(void);
|
||||
int md_issymlink(char *sp);
|
||||
|
||||
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
|
||||
|
||||
#endif
|
||||
|
||||
681
src/cc/rogue/fight.c
Normal file
681
src/cc/rogue/fight.c
Normal file
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
* All the fighting gets done here
|
||||
*
|
||||
* @(#)fight.c 4.67 (Berkeley) 09/06/83
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <stdlib.h>
|
||||
//#include <curses.h>
|
||||
//#include <string.h>
|
||||
//#include <ctype.h>
|
||||
#include "rogue.h"
|
||||
|
||||
//#define EQSTR(a, b) (strcmp(a, b) == 0)
|
||||
|
||||
const char *h_names[] = { /* strings for hitting */
|
||||
" scored an excellent hit on ",
|
||||
" hit ",
|
||||
" have injured ",
|
||||
" swing and hit ",
|
||||
" scored an excellent hit on ",
|
||||
" hit ",
|
||||
" has injured ",
|
||||
" swings and hits "
|
||||
};
|
||||
|
||||
const char *m_names[] = { /* strings for missing */
|
||||
" miss",
|
||||
" swing and miss",
|
||||
" barely miss",
|
||||
" don't hit",
|
||||
" misses",
|
||||
" swings and misses",
|
||||
" barely misses",
|
||||
" doesn't hit",
|
||||
};
|
||||
|
||||
/*
|
||||
* adjustments to hit probabilities due to strength
|
||||
*/
|
||||
static const int str_plus[] = {
|
||||
-7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
|
||||
};
|
||||
|
||||
/*
|
||||
* adjustments to damage done due to strength
|
||||
*/
|
||||
static const int add_dam[] = {
|
||||
-7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
|
||||
3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6
|
||||
};
|
||||
|
||||
/*
|
||||
* fight:
|
||||
* The player attacks the monster.
|
||||
*/
|
||||
int
|
||||
fight(struct rogue_state *rs,coord *mp, THING *weap, bool thrown)
|
||||
{
|
||||
register THING *tp;
|
||||
register bool did_hit = TRUE;
|
||||
register char *mname, ch;
|
||||
|
||||
/*
|
||||
* Find the monster we want to fight
|
||||
*/
|
||||
#ifdef MASTER
|
||||
if ((tp = moat(mp->y, mp->x)) == NULL)
|
||||
debug("Fight what @ %d,%d", mp->y, mp->x);
|
||||
#else
|
||||
tp = moat(mp->y, mp->x);
|
||||
#endif
|
||||
/*
|
||||
* Since we are fighting, things are not quiet so no healing takes
|
||||
* place.
|
||||
*/
|
||||
count = 0;
|
||||
quiet = 0;
|
||||
runto(rs,mp);
|
||||
/*
|
||||
* Let him know it was really a xeroc (if it was one).
|
||||
*/
|
||||
ch = '\0';
|
||||
if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(player, ISBLIND))
|
||||
{
|
||||
tp->t_disguise = 'X';
|
||||
if (on(player, ISHALU)) {
|
||||
ch = (char)(rnd(26) + 'A');
|
||||
mvaddch(tp->t_pos.y, tp->t_pos.x, ch);
|
||||
}
|
||||
msg(rs,choose_str("heavy! That's a nasty critter!",
|
||||
"wait! That's a xeroc!"));
|
||||
if (!thrown)
|
||||
return FALSE;
|
||||
}
|
||||
mname = set_mname(tp);
|
||||
did_hit = FALSE;
|
||||
has_hit = (terse && !to_death);
|
||||
if (roll_em(&player, tp, weap, thrown))
|
||||
{
|
||||
did_hit = FALSE;
|
||||
if (thrown)
|
||||
thunk(rs,weap, mname, terse);
|
||||
else
|
||||
hit(rs,(char *) NULL, mname, terse);
|
||||
if (on(player, CANHUH))
|
||||
{
|
||||
did_hit = TRUE;
|
||||
tp->t_flags |= ISHUH;
|
||||
player.t_flags &= ~CANHUH;
|
||||
endmsg(rs);
|
||||
has_hit = FALSE;
|
||||
msg(rs,"your hands stop glowing %s", pick_color("red"));
|
||||
}
|
||||
if (tp->t_stats.s_hpt <= 0)
|
||||
killed(rs,tp, TRUE);
|
||||
else if (did_hit && !on(player, ISBLIND))
|
||||
msg(rs,"%s appears confused", mname);
|
||||
did_hit = TRUE;
|
||||
}
|
||||
else
|
||||
if (thrown)
|
||||
bounce(rs,weap, mname, terse);
|
||||
else
|
||||
miss(rs,(char *) NULL, mname, terse);
|
||||
return did_hit;
|
||||
}
|
||||
|
||||
/*
|
||||
* attack:
|
||||
* The monster attacks the player
|
||||
*/
|
||||
int
|
||||
attack(struct rogue_state *rs,THING *mp)
|
||||
{
|
||||
register char *mname;
|
||||
register int oldhp;
|
||||
|
||||
/*
|
||||
* Since this is an attack, stop running and any healing that was
|
||||
* going on at the time.
|
||||
*/
|
||||
running = FALSE;
|
||||
count = 0;
|
||||
quiet = 0;
|
||||
if (to_death && !on(*mp, ISTARGET))
|
||||
{
|
||||
to_death = FALSE;
|
||||
kamikaze = FALSE;
|
||||
}
|
||||
if (mp->t_type == 'X' && mp->t_disguise != 'X' && !on(player, ISBLIND))
|
||||
{
|
||||
mp->t_disguise = 'X';
|
||||
if (on(player, ISHALU))
|
||||
mvaddch(mp->t_pos.y, mp->t_pos.x, rnd(26) + 'A');
|
||||
}
|
||||
mname = set_mname(mp);
|
||||
oldhp = pstats.s_hpt;
|
||||
if (roll_em(mp, &player, (THING *) NULL, FALSE))
|
||||
{
|
||||
if (mp->t_type != 'I')
|
||||
{
|
||||
if (has_hit)
|
||||
addmsg(rs,". ");
|
||||
hit(rs,mname, (char *) NULL, FALSE);
|
||||
}
|
||||
else
|
||||
if (has_hit)
|
||||
endmsg(rs);
|
||||
has_hit = FALSE;
|
||||
if (pstats.s_hpt <= 0)
|
||||
death(rs,mp->t_type); /* Bye bye life ... */
|
||||
else if (!kamikaze)
|
||||
{
|
||||
oldhp -= pstats.s_hpt;
|
||||
if (oldhp > max_hit)
|
||||
max_hit = oldhp;
|
||||
if (pstats.s_hpt <= max_hit)
|
||||
to_death = FALSE;
|
||||
}
|
||||
if (!on(*mp, ISCANC))
|
||||
switch (mp->t_type)
|
||||
{
|
||||
case 'A':
|
||||
/*
|
||||
* If an aquator hits, you can lose armor class.
|
||||
*/
|
||||
rust_armor(rs,cur_armor);
|
||||
when 'I':
|
||||
/*
|
||||
* The ice monster freezes you
|
||||
*/
|
||||
player.t_flags &= ~ISRUN;
|
||||
if (!no_command)
|
||||
{
|
||||
addmsg(rs,"you are frozen");
|
||||
if (!terse)
|
||||
addmsg(rs," by the %s", mname);
|
||||
endmsg(rs);
|
||||
}
|
||||
no_command += rnd(2) + 2;
|
||||
if (no_command > BORE_LEVEL)
|
||||
death(rs,'h');
|
||||
when 'R':
|
||||
/*
|
||||
* Rattlesnakes have poisonous bites
|
||||
*/
|
||||
if (!save(VS_POISON))
|
||||
{
|
||||
if (!ISWEARING(R_SUSTSTR))
|
||||
{
|
||||
chg_str(-1);
|
||||
if (!terse)
|
||||
msg(rs,"you feel a bite in your leg and now feel weaker");
|
||||
else
|
||||
msg(rs,"a bite has weakened you");
|
||||
}
|
||||
else if (!to_death)
|
||||
{
|
||||
if (!terse)
|
||||
msg(rs,"a bite momentarily weakens you");
|
||||
else
|
||||
msg(rs,"bite has no effect");
|
||||
}
|
||||
}
|
||||
when 'W':
|
||||
case 'V':
|
||||
/*
|
||||
* Wraiths might drain energy levels, and Vampires
|
||||
* can steal max_hp
|
||||
*/
|
||||
if (rnd(100) < (mp->t_type == 'W' ? 15 : 30))
|
||||
{
|
||||
register int fewer;
|
||||
|
||||
if (mp->t_type == 'W')
|
||||
{
|
||||
if (pstats.s_exp == 0)
|
||||
death(rs,'W'); /* All levels gone */
|
||||
if (--pstats.s_lvl == 0)
|
||||
{
|
||||
pstats.s_exp = 0;
|
||||
pstats.s_lvl = 1;
|
||||
}
|
||||
else
|
||||
pstats.s_exp = e_levels[pstats.s_lvl-1]+1;
|
||||
fewer = roll(1, 10);
|
||||
}
|
||||
else
|
||||
fewer = roll(1, 3);
|
||||
pstats.s_hpt -= fewer;
|
||||
max_hp -= fewer;
|
||||
if (pstats.s_hpt <= 0)
|
||||
pstats.s_hpt = 1;
|
||||
if (max_hp <= 0)
|
||||
death(rs,mp->t_type);
|
||||
msg(rs,"you suddenly feel weaker");
|
||||
}
|
||||
when 'F':
|
||||
/*
|
||||
* Venus Flytrap stops the poor guy from moving
|
||||
*/
|
||||
player.t_flags |= ISHELD;
|
||||
sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dx1", ++vf_hit);
|
||||
if (--pstats.s_hpt <= 0)
|
||||
death(rs,'F');
|
||||
when 'L':
|
||||
{
|
||||
/*
|
||||
* Leperachaun steals some gold
|
||||
*/
|
||||
register int lastpurse;
|
||||
|
||||
lastpurse = purse;
|
||||
purse -= GOLDCALC;
|
||||
if (!save(VS_MAGIC))
|
||||
purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
|
||||
if (purse < 0)
|
||||
purse = 0;
|
||||
remove_mon(rs,&mp->t_pos, mp, FALSE);
|
||||
mp=NULL;
|
||||
if (purse != lastpurse)
|
||||
msg(rs,"your purse feels lighter");
|
||||
}
|
||||
when 'N':
|
||||
{
|
||||
THING *obj, *steal; int nobj;
|
||||
|
||||
/*
|
||||
* Nymph's steal a magic item, look through the pack
|
||||
* and pick out one we like.
|
||||
*/
|
||||
steal = NULL;
|
||||
for (nobj = 0, obj = pack; obj != NULL; obj = next(obj))
|
||||
if (obj != cur_armor && obj != cur_weapon
|
||||
&& obj != cur_ring[LEFT] && obj != cur_ring[RIGHT]
|
||||
&& is_magic(obj) && rnd(++nobj) == 0)
|
||||
steal = obj;
|
||||
if (steal != NULL)
|
||||
{
|
||||
remove_mon(rs,&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE);
|
||||
mp=NULL;
|
||||
leave_pack(rs,steal, FALSE, FALSE);
|
||||
msg(rs,"she stole %s!", inv_name(steal, TRUE));
|
||||
if ( steal->o_count <= 0 )
|
||||
discard(steal);
|
||||
}
|
||||
}
|
||||
otherwise:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (mp->t_type != 'I')
|
||||
{
|
||||
if (has_hit)
|
||||
{
|
||||
addmsg(rs,". ");
|
||||
has_hit = FALSE;
|
||||
}
|
||||
if (mp->t_type == 'F')
|
||||
{
|
||||
pstats.s_hpt -= vf_hit;
|
||||
if (pstats.s_hpt <= 0)
|
||||
death(rs,mp->t_type); /* Bye bye life ... */
|
||||
}
|
||||
miss(rs,mname, (char *) NULL, FALSE);
|
||||
}
|
||||
if (fight_flush && !to_death)
|
||||
flush_type();
|
||||
count = 0;
|
||||
status(rs);
|
||||
if (mp == NULL)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* set_mname:
|
||||
* return the monster name for the given monster
|
||||
*/
|
||||
char *
|
||||
set_mname(THING *tp)
|
||||
{
|
||||
int ch;
|
||||
char *mname;
|
||||
static char tbuf[MAXSTR] = { 't', 'h', 'e', ' ' };
|
||||
|
||||
if (!see_monst(tp) && !on(player, SEEMONST))
|
||||
return (terse ? (char *)"it" : (char *)"something");
|
||||
else if (on(player, ISHALU))
|
||||
{
|
||||
move(tp->t_pos.y, tp->t_pos.x);
|
||||
ch = toascii(inch());
|
||||
if (!isupper(ch))
|
||||
ch = rnd(26);
|
||||
else
|
||||
ch -= 'A';
|
||||
mname = monsters[ch].m_name;
|
||||
}
|
||||
else
|
||||
mname = monsters[tp->t_type - 'A'].m_name;
|
||||
strcpy(&tbuf[4], mname);
|
||||
return tbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* swing:
|
||||
* Returns true if the swing hits
|
||||
*/
|
||||
int
|
||||
swing(int at_lvl, int op_arm, int wplus)
|
||||
{
|
||||
int res = rnd(20);
|
||||
int need = (20 - at_lvl) - op_arm;
|
||||
|
||||
return (res + wplus >= need);
|
||||
}
|
||||
|
||||
/*
|
||||
* roll_em:
|
||||
* Roll several attacks
|
||||
*/
|
||||
bool
|
||||
roll_em(THING *thatt, THING *thdef, THING *weap, bool hurl)
|
||||
{
|
||||
register struct stats *att, *def;
|
||||
register char *cp;
|
||||
register int ndice, nsides, def_arm;
|
||||
register bool did_hit = FALSE;
|
||||
register int hplus;
|
||||
register int dplus;
|
||||
register int damage;
|
||||
|
||||
att = &thatt->t_stats;
|
||||
def = &thdef->t_stats;
|
||||
if (weap == NULL)
|
||||
{
|
||||
cp = att->s_dmg;
|
||||
dplus = 0;
|
||||
hplus = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
hplus = (weap == NULL ? 0 : weap->o_hplus);
|
||||
dplus = (weap == NULL ? 0 : weap->o_dplus);
|
||||
if (weap == cur_weapon)
|
||||
{
|
||||
if (ISRING(LEFT, R_ADDDAM))
|
||||
dplus += cur_ring[LEFT]->o_arm;
|
||||
else if (ISRING(LEFT, R_ADDHIT))
|
||||
hplus += cur_ring[LEFT]->o_arm;
|
||||
if (ISRING(RIGHT, R_ADDDAM))
|
||||
dplus += cur_ring[RIGHT]->o_arm;
|
||||
else if (ISRING(RIGHT, R_ADDHIT))
|
||||
hplus += cur_ring[RIGHT]->o_arm;
|
||||
}
|
||||
cp = weap->o_damage;
|
||||
if (hurl)
|
||||
{
|
||||
if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
|
||||
cur_weapon->o_which == weap->o_launch)
|
||||
{
|
||||
cp = weap->o_hurldmg;
|
||||
hplus += cur_weapon->o_hplus;
|
||||
dplus += cur_weapon->o_dplus;
|
||||
}
|
||||
else if (weap->o_launch < 0)
|
||||
cp = weap->o_hurldmg;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the creature being attacked is not running (alseep or held)
|
||||
* then the attacker gets a plus four bonus to hit.
|
||||
*/
|
||||
if (!on(*thdef, ISRUN))
|
||||
hplus += 4;
|
||||
def_arm = def->s_arm;
|
||||
if (def == &pstats)
|
||||
{
|
||||
if (cur_armor != NULL)
|
||||
def_arm = cur_armor->o_arm;
|
||||
if (ISRING(LEFT, R_PROTECT))
|
||||
def_arm -= cur_ring[LEFT]->o_arm;
|
||||
if (ISRING(RIGHT, R_PROTECT))
|
||||
def_arm -= cur_ring[RIGHT]->o_arm;
|
||||
}
|
||||
while(cp != NULL && *cp != '\0')
|
||||
{
|
||||
ndice = atoi(cp);
|
||||
if ((cp = strchr(cp, 'x')) == NULL)
|
||||
break;
|
||||
nsides = atoi(++cp);
|
||||
if (swing(att->s_lvl, def_arm, hplus + str_plus[att->s_str]))
|
||||
{
|
||||
int proll;
|
||||
|
||||
proll = roll(ndice, nsides);
|
||||
#ifdef MASTER
|
||||
if (ndice + nsides > 0 && proll <= 0)
|
||||
debug("Damage for %dx%d came out %d, dplus = %d, add_dam = %d, def_arm = %d", ndice, nsides, proll, dplus, add_dam[att->s_str], def_arm);
|
||||
#endif
|
||||
damage = dplus + proll + add_dam[att->s_str];
|
||||
def->s_hpt -= max(0, damage);
|
||||
did_hit = TRUE;
|
||||
}
|
||||
if ((cp = strchr(cp, '/')) == NULL)
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
return did_hit;
|
||||
}
|
||||
|
||||
/*
|
||||
* prname:
|
||||
* The print name of a combatant
|
||||
*/
|
||||
char *
|
||||
prname(char *mname, bool upper)
|
||||
{
|
||||
static char tbuf[MAXSTR];
|
||||
|
||||
*tbuf = '\0';
|
||||
if (mname == 0)
|
||||
strcpy(tbuf, "you");
|
||||
else
|
||||
strcpy(tbuf, mname);
|
||||
if (upper)
|
||||
*tbuf = (char) toupper(*tbuf);
|
||||
return tbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* thunk:
|
||||
* A missile hits a monster
|
||||
*/
|
||||
void
|
||||
thunk(struct rogue_state *rs,THING *weap, char *mname, bool noend)
|
||||
{
|
||||
if (to_death)
|
||||
return;
|
||||
if (weap->o_type == WEAPON)
|
||||
addmsg(rs,"the %s hits ", weap_info[weap->o_which].oi_name);
|
||||
else
|
||||
addmsg(rs,"you hit ");
|
||||
addmsg(rs,"%s", mname);
|
||||
if (!noend)
|
||||
endmsg(rs);
|
||||
}
|
||||
|
||||
/*
|
||||
* hit:
|
||||
* Print a message to indicate a succesful hit
|
||||
*/
|
||||
|
||||
void
|
||||
hit(struct rogue_state *rs,char *er, char *ee, bool noend)
|
||||
{
|
||||
int32_t i; const char *s;
|
||||
|
||||
if (to_death)
|
||||
return;
|
||||
addmsg(rs,prname(er, TRUE));
|
||||
if (terse)
|
||||
s = " hit";
|
||||
else
|
||||
{
|
||||
i = rnd(4);
|
||||
if (er != NULL)
|
||||
i += 4;
|
||||
s = h_names[i];
|
||||
}
|
||||
addmsg(rs,(char *)s);
|
||||
if (!terse)
|
||||
addmsg(rs,prname(ee, FALSE));
|
||||
if (!noend)
|
||||
endmsg(rs);
|
||||
}
|
||||
|
||||
/*
|
||||
* miss:
|
||||
* Print a message to indicate a poor swing
|
||||
*/
|
||||
void
|
||||
miss(struct rogue_state *rs,char *er, char *ee, bool noend)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (to_death)
|
||||
return;
|
||||
addmsg(rs,prname(er, TRUE));
|
||||
if (terse)
|
||||
i = 0;
|
||||
else
|
||||
i = rnd(4);
|
||||
if (er != NULL)
|
||||
i += 4;
|
||||
addmsg(rs,(char *)m_names[i]);
|
||||
if (!terse)
|
||||
addmsg(rs," %s", prname(ee, FALSE));
|
||||
if (!noend)
|
||||
endmsg(rs);
|
||||
}
|
||||
|
||||
/*
|
||||
* bounce:
|
||||
* A missile misses a monster
|
||||
*/
|
||||
void
|
||||
bounce(struct rogue_state *rs,THING *weap, char *mname, bool noend)
|
||||
{
|
||||
if (to_death)
|
||||
return;
|
||||
if (weap->o_type == WEAPON)
|
||||
addmsg(rs,"the %s misses ", weap_info[weap->o_which].oi_name);
|
||||
else
|
||||
addmsg(rs,"you missed ");
|
||||
addmsg(rs,mname);
|
||||
if (!noend)
|
||||
endmsg(rs);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove_mon:
|
||||
* Remove a monster from the screen
|
||||
*/
|
||||
void
|
||||
remove_mon(struct rogue_state *rs,coord *mp, THING *tp, bool waskill)
|
||||
{
|
||||
register THING *obj, *nexti;
|
||||
for (obj = tp->t_pack; obj != NULL; obj = nexti)
|
||||
{
|
||||
nexti = next(obj);
|
||||
obj->o_pos = tp->t_pos;
|
||||
detach(tp->t_pack, obj);
|
||||
if (waskill)
|
||||
fall(rs,obj, FALSE);
|
||||
else discard(obj);
|
||||
}
|
||||
moat(mp->y, mp->x) = NULL;
|
||||
mvaddch(mp->y, mp->x, tp->t_oldch);
|
||||
detach(mlist, tp);
|
||||
if (on(*tp, ISTARGET))
|
||||
{
|
||||
kamikaze = FALSE;
|
||||
to_death = FALSE;
|
||||
if (fight_flush)
|
||||
flush_type();
|
||||
}
|
||||
discard(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
* killed:
|
||||
* Called to put a monster to death
|
||||
*/
|
||||
void
|
||||
killed(struct rogue_state *rs,THING *tp, bool pr)
|
||||
{
|
||||
char *mname;
|
||||
|
||||
pstats.s_exp += tp->t_stats.s_exp;
|
||||
|
||||
/*
|
||||
* If the monster was a venus flytrap, un-hold him
|
||||
*/
|
||||
switch (tp->t_type)
|
||||
{
|
||||
case 'F':
|
||||
player.t_flags &= ~ISHELD;
|
||||
vf_hit = 0;
|
||||
strcpy(monsters['F'-'A'].m_stats.s_dmg, "000x0");
|
||||
when 'L':
|
||||
{
|
||||
THING *gold;
|
||||
|
||||
if (fallpos(&tp->t_pos, &tp->t_room->r_gold) && level >= max_level)
|
||||
{
|
||||
gold = new_item();
|
||||
gold->o_type = GOLD;
|
||||
gold->o_goldval = GOLDCALC;
|
||||
if (save(VS_MAGIC))
|
||||
gold->o_goldval += GOLDCALC + GOLDCALC
|
||||
+ GOLDCALC + GOLDCALC;
|
||||
attach(tp->t_pack, gold);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Get rid of the monster.
|
||||
*/
|
||||
mname = set_mname(tp);
|
||||
remove_mon(rs,&tp->t_pos, tp, TRUE);
|
||||
if (pr)
|
||||
{
|
||||
if (has_hit)
|
||||
{
|
||||
addmsg(rs,". Defeated ");
|
||||
has_hit = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!terse)
|
||||
addmsg(rs,"you have ");
|
||||
addmsg(rs,"defeated ");
|
||||
}
|
||||
msg(rs,mname);
|
||||
}
|
||||
/*
|
||||
* Do adjustments if he went up a level
|
||||
*/
|
||||
check_level(rs);
|
||||
if (fight_flush)
|
||||
flush_type();
|
||||
}
|
||||
495
src/cc/rogue/init.c
Normal file
495
src/cc/rogue/init.c
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* global variable initializaton
|
||||
*
|
||||
* @(#)init.c 4.31 (Berkeley) 02/05/99
|
||||
*
|
||||
* Rogue: Exploring the Dungeons of Doom
|
||||
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file LICENSE.TXT for full copyright and licensing information.
|
||||
*/
|
||||
|
||||
//#include <stdlib.h>
|
||||
//#include <curses.h>
|
||||
//#include <ctype.h>
|
||||
//#include <string.h>
|
||||
#include "rogue.h"
|
||||
|
||||
/*
|
||||
* init_player:
|
||||
* Roll her up
|
||||
*/
|
||||
void rogue_restoreobject(THING *o,struct rogue_packitem *item);
|
||||
|
||||
int32_t rogue_total(THING *o)
|
||||
{
|
||||
if ( (o->o_flags & ISMANY) != 0 )
|
||||
return(1);
|
||||
else return(o->o_count);
|
||||
}
|
||||
|
||||
void restore_player(struct rogue_state *rs)
|
||||
{
|
||||
int32_t i,total = 0; THING *obj;
|
||||
//rs->P.gold = purse;
|
||||
max_hp = rs->P.hitpoints;
|
||||
//pstats.s_hpt = max_hp;
|
||||
pstats.s_str = rs->P.strength & 0xffff;
|
||||
if ( (max_stats.s_str= (rs->P.strength >> 16) & 0xffff) == 0 )
|
||||
max_stats.s_str = 16;
|
||||
if ( pstats.s_str > max_stats.s_str )
|
||||
pstats.s_str = max_stats.s_str;
|
||||
pstats.s_lvl = rs->P.level;
|
||||
pstats.s_exp = rs->P.experience;
|
||||
for (i=0; i<rs->P.packsize&&i<MAXPACK; i++)
|
||||
{
|
||||
obj = new_item();
|
||||
rogue_restoreobject(obj,&rs->P.roguepack[i]);
|
||||
total += rogue_total(obj);
|
||||
if ( total > ROGUE_MAXTOTAL )
|
||||
break;
|
||||
add_pack(rs,obj,TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void init_player(struct rogue_state *rs)
|
||||
{
|
||||
register THING *obj; int32_t i;
|
||||
pstats = max_stats;
|
||||
food_left = HUNGERTIME;
|
||||
|
||||
if ( rs->restoring != 0 )
|
||||
{
|
||||
// duplicate rng usage of normal case
|
||||
obj = new_item();
|
||||
init_weapon(obj, MACE);
|
||||
free(obj);
|
||||
obj = new_item();
|
||||
init_weapon(obj, BOW);
|
||||
free(obj);
|
||||
obj = new_item();
|
||||
init_weapon(obj, ARROW);
|
||||
obj->o_count = rnd(15) + 25;
|
||||
free(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Give him some food
|
||||
*/
|
||||
obj = new_item();
|
||||
obj->o_type = FOOD;
|
||||
obj->o_count = 1;
|
||||
add_pack(rs,obj, TRUE);
|
||||
/*
|
||||
* And his suit of armor
|
||||
*/
|
||||
obj = new_item();
|
||||
obj->o_type = ARMOR;
|
||||
obj->o_which = RING_MAIL;
|
||||
obj->o_arm = a_class[RING_MAIL] - 1;
|
||||
obj->o_flags |= ISKNOW;
|
||||
obj->o_count = 1;
|
||||
cur_armor = obj;
|
||||
add_pack(rs,obj, TRUE);
|
||||
/*
|
||||
* Give him his weaponry. First a mace.
|
||||
*/
|
||||
obj = new_item();
|
||||
init_weapon(obj, MACE);
|
||||
obj->o_hplus = 1;
|
||||
obj->o_dplus = 1;
|
||||
obj->o_flags |= ISKNOW;
|
||||
add_pack(rs,obj, TRUE);
|
||||
cur_weapon = obj;
|
||||
/*
|
||||
* Now a +1 bow
|
||||
*/
|
||||
obj = new_item();
|
||||
init_weapon(obj, BOW);
|
||||
obj->o_hplus = 1;
|
||||
obj->o_flags |= ISKNOW;
|
||||
add_pack(rs,obj, TRUE);
|
||||
/*
|
||||
* Now some arrows
|
||||
*/
|
||||
obj = new_item();
|
||||
init_weapon(obj, ARROW);
|
||||
obj->o_count = rnd(15) + 25;
|
||||
obj->o_flags |= ISKNOW;
|
||||
add_pack(rs,obj, TRUE);
|
||||
//fprintf(stderr,"initial o_count.%d\n",obj->o_count); sleep(3);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Contains defintions and functions for dealing with things like
|
||||
* potions and scrolls
|
||||
*/
|
||||
|
||||
const char *rainbow[] = {
|
||||
"amber",
|
||||
"aquamarine",
|
||||
"black",
|
||||
"blue",
|
||||
"brown",
|
||||
"clear",
|
||||
"crimson",
|
||||
"cyan",
|
||||
"ecru",
|
||||
"gold",
|
||||
"green",
|
||||
"grey",
|
||||
"magenta",
|
||||
"orange",
|
||||
"pink",
|
||||
"plaid",
|
||||
"purple",
|
||||
"red",
|
||||
"silver",
|
||||
"tan",
|
||||
"tangerine",
|
||||
"topaz",
|
||||
"turquoise",
|
||||
"vermilion",
|
||||
"violet",
|
||||
"white",
|
||||
"yellow",
|
||||
};
|
||||
|
||||
#define NCOLORS (sizeof rainbow / sizeof (char *))
|
||||
int cNCOLORS = NCOLORS;
|
||||
|
||||
static const char *sylls[] = {
|
||||
"a", "ab", "ag", "aks", "ala", "an", "app", "arg", "arze", "ash",
|
||||
"bek", "bie", "bit", "bjor", "blu", "bot", "bu", "byt", "comp",
|
||||
"con", "cos", "cre", "dalf", "dan", "den", "do", "e", "eep", "el",
|
||||
"eng", "er", "ere", "erk", "esh", "evs", "fa", "fid", "fri", "fu",
|
||||
"gan", "gar", "glen", "gop", "gre", "ha", "hyd", "i", "ing", "ip",
|
||||
"ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech",
|
||||
"mar", "me", "mi", "mic", "mik", "mon", "mung", "mur", "nej",
|
||||
"nelg", "nep", "ner", "nes", "nes", "nih", "nin", "o", "od", "ood",
|
||||
"org", "orn", "ox", "oxy", "pay", "ple", "plu", "po", "pot",
|
||||
"prok", "re", "rea", "rhov", "ri", "ro", "rog", "rok", "rol", "sa",
|
||||
"san", "sat", "sef", "seh", "shu", "ski", "sna", "sne", "snik",
|
||||
"sno", "so", "sol", "sri", "sta", "sun", "ta", "tab", "tem",
|
||||
"ther", "ti", "tox", "trol", "tue", "turs", "u", "ulk", "um", "un",
|
||||
"uni", "ur", "val", "viv", "vly", "vom", "wah", "wed", "werg",
|
||||
"wex", "whon", "wun", "xo", "y", "yot", "yu", "zant", "zeb", "zim",
|
||||
"zok", "zon", "zum",
|
||||
};
|
||||
|
||||
const STONE stones[] = {
|
||||
{ "agate", 25},
|
||||
{ "alexandrite", 40},
|
||||
{ "amethyst", 50},
|
||||
{ "carnelian", 40},
|
||||
{ "diamond", 300},
|
||||
{ "emerald", 300},
|
||||
{ "germanium", 225},
|
||||
{ "granite", 5},
|
||||
{ "garnet", 50},
|
||||
{ "jade", 150},
|
||||
{ "kryptonite", 300},
|
||||
{ "lapis lazuli", 50},
|
||||
{ "moonstone", 50},
|
||||
{ "obsidian", 15},
|
||||
{ "onyx", 60},
|
||||
{ "opal", 200},
|
||||
{ "pearl", 220},
|
||||
{ "peridot", 63},
|
||||
{ "ruby", 350},
|
||||
{ "sapphire", 285},
|
||||
{ "stibotantalite", 200},
|
||||
{ "tiger eye", 50},
|
||||
{ "topaz", 60},
|
||||
{ "turquoise", 70},
|
||||
{ "taaffeite", 300},
|
||||
{ "zircon", 80},
|
||||
};
|
||||
|
||||
#define NSTONES (sizeof stones / sizeof (STONE))
|
||||
int cNSTONES = NSTONES;
|
||||
|
||||
const char *wood[] = {
|
||||
"avocado wood",
|
||||
"balsa",
|
||||
"bamboo",
|
||||
"banyan",
|
||||
"birch",
|
||||
"cedar",
|
||||
"cherry",
|
||||
"cinnibar",
|
||||
"cypress",
|
||||
"dogwood",
|
||||
"driftwood",
|
||||
"ebony",
|
||||
"elm",
|
||||
"eucalyptus",
|
||||
"fall",
|
||||
"hemlock",
|
||||
"holly",
|
||||
"ironwood",
|
||||
"kukui wood",
|
||||
"mahogany",
|
||||
"manzanita",
|
||||
"maple",
|
||||
"oaken",
|
||||
"persimmon wood",
|
||||
"pecan",
|
||||
"pine",
|
||||
"poplar",
|
||||
"redwood",
|
||||
"rosewood",
|
||||
"spruce",
|
||||
"teak",
|
||||
"walnut",
|
||||
"zebrawood",
|
||||
};
|
||||
|
||||
#define NWOOD (sizeof wood / sizeof (char *))
|
||||
int cNWOOD = NWOOD;
|
||||
|
||||
const char *metal[] = {
|
||||
"aluminum",
|
||||
"beryllium",
|
||||
"bone",
|
||||
"brass",
|
||||
"bronze",
|
||||
"copper",
|
||||
"electrum",
|
||||
"gold",
|
||||
"iron",
|
||||
"lead",
|
||||
"magnesium",
|
||||
"mercury",
|
||||
"nickel",
|
||||
"pewter",
|
||||
"platinum",
|
||||
"steel",
|
||||
"silver",
|
||||
"silicon",
|
||||
"tin",
|
||||
"titanium",
|
||||
"tungsten",
|
||||
"zinc",
|
||||
};
|
||||
|
||||
#define NMETAL (sizeof metal / sizeof (char *))
|
||||
int cNMETAL = NMETAL;
|
||||
#define MAX3(a,b,c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
|
||||
|
||||
static bool used[MAX3(NCOLORS, NSTONES, NWOOD)];
|
||||
|
||||
/*
|
||||
* init_colors:
|
||||
* Initialize the potion color scheme for this time
|
||||
*/
|
||||
void
|
||||
init_colors()
|
||||
{
|
||||
register int i, j;
|
||||
memset(used,0,sizeof(used));
|
||||
for (i = 0; i < NCOLORS; i++)
|
||||
used[i] = FALSE;
|
||||
for (i = 0; i < MAXPOTIONS; i++)
|
||||
{
|
||||
do
|
||||
j = rnd(NCOLORS);
|
||||
until (!used[j]);
|
||||
used[j] = TRUE;
|
||||
p_colors[i] = rainbow[j];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* init_names:
|
||||
* Generate the names of the various scrolls
|
||||
*/
|
||||
#define MAXNAME 40 /* Max number of characters in a name */
|
||||
|
||||
void
|
||||
init_names()
|
||||
{
|
||||
register int nsyl;
|
||||
register char *cp; const char *sp;
|
||||
register int i, nwords;
|
||||
|
||||
for (i = 0; i < MAXSCROLLS; i++)
|
||||
{
|
||||
cp = prbuf;
|
||||
nwords = rnd(3) + 2;
|
||||
while (nwords--)
|
||||
{
|
||||
nsyl = rnd(3) + 1;
|
||||
while (nsyl--)
|
||||
{
|
||||
sp = sylls[rnd((sizeof sylls) / (sizeof (char *)))];
|
||||
if (&cp[strlen(sp)] > &prbuf[MAXNAME])
|
||||
break;
|
||||
while (*sp)
|
||||
*cp++ = *sp++;
|
||||
}
|
||||
*cp++ = ' ';
|
||||
}
|
||||
*--cp = '\0';
|
||||
s_names[i] = (char *) malloc((unsigned) strlen(prbuf)+1);
|
||||
strcpy(s_names[i], prbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* init_stones:
|
||||
* Initialize the ring stone setting scheme for this time
|
||||
*/
|
||||
void
|
||||
init_stones()
|
||||
{
|
||||
register int i, j;
|
||||
for (i = 0; i < NSTONES; i++)
|
||||
used[i] = FALSE;
|
||||
for (i = 0; i < MAXRINGS; i++)
|
||||
{
|
||||
do
|
||||
j = rnd(NSTONES);
|
||||
until (!used[j]);
|
||||
used[j] = TRUE;
|
||||
r_stones[i] = stones[j].st_name;
|
||||
ring_info[i].oi_worth += stones[j].st_value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* init_materials:
|
||||
* Initialize the construction materials for wands and staffs
|
||||
*/
|
||||
void
|
||||
init_materials()
|
||||
{
|
||||
register int i, j;
|
||||
register const char *str;
|
||||
static bool metused[NMETAL];
|
||||
memset(metused,0,sizeof(metused));
|
||||
for (i = 0; i < NWOOD; i++)
|
||||
used[i] = FALSE;
|
||||
for (i = 0; i < NMETAL; i++)
|
||||
metused[i] = FALSE;
|
||||
for (i = 0; i < MAXSTICKS; i++)
|
||||
{
|
||||
for (;;)
|
||||
if (rnd(2) == 0)
|
||||
{
|
||||
j = rnd(NMETAL);
|
||||
if (!metused[j])
|
||||
{
|
||||
ws_type[i] = "wand";
|
||||
str = metal[j];
|
||||
metused[j] = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
j = rnd(NWOOD);
|
||||
if (!used[j])
|
||||
{
|
||||
ws_type[i] = "staff";
|
||||
str = wood[j];
|
||||
used[j] = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ws_made[i] = str;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MASTER
|
||||
# define NT NUMTHINGS, "things"
|
||||
# define MP MAXPOTIONS, "potions"
|
||||
# define MS MAXSCROLLS, "scrolls"
|
||||
# define MR MAXRINGS, "rings"
|
||||
# define MWS MAXSTICKS, "sticks"
|
||||
# define MW MAXWEAPONS, "weapons"
|
||||
# define MA MAXARMORS, "armor"
|
||||
#else
|
||||
# define NT NUMTHINGS
|
||||
# define MP MAXPOTIONS
|
||||
# define MS MAXSCROLLS
|
||||
# define MR MAXRINGS
|
||||
# define MWS MAXSTICKS
|
||||
# define MW MAXWEAPONS
|
||||
# define MA MAXARMORS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* sumprobs:
|
||||
* Sum up the probabilities for items appearing
|
||||
*/
|
||||
void
|
||||
sumprobs(struct obj_info *info, int bound
|
||||
#ifdef MASTER
|
||||
, char *name
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef MASTER
|
||||
struct obj_info *start = info;
|
||||
#endif
|
||||
struct obj_info *endp;
|
||||
endp = info + bound;
|
||||
while (++info < endp)
|
||||
info->oi_prob += (info - 1)->oi_prob;
|
||||
#ifdef MASTER
|
||||
badcheck(name, start, bound);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* init_probs:
|
||||
* Initialize the probabilities for the various items
|
||||
*/
|
||||
void
|
||||
init_probs()
|
||||
{
|
||||
sumprobs(things, NT);
|
||||
sumprobs(pot_info, MP);
|
||||
sumprobs(scr_info, MS);
|
||||
sumprobs(ring_info, MR);
|
||||
sumprobs(ws_info, MWS);
|
||||
sumprobs(weap_info, MW);
|
||||
sumprobs(arm_info, MA);
|
||||
}
|
||||
|
||||
#ifdef MASTER
|
||||
/*
|
||||
* badcheck:
|
||||
* Check to see if a series of probabilities sums to 100
|
||||
*/
|
||||
void
|
||||
badcheck(char *name, struct obj_info *info, int bound)
|
||||
{
|
||||
register struct obj_info *end;
|
||||
|
||||
if (info[bound - 1].oi_prob == 100)
|
||||
return;
|
||||
printf("\nBad percentages for %s (bound = %d):\n", name, bound);
|
||||
for (end = &info[bound]; info < end; info++)
|
||||
printf("%3d%% %s\n", info->oi_prob, info->oi_name);
|
||||
printf("[hit RETURN to continue]");
|
||||
fflush(stdout);
|
||||
while (getchar() != '\n')
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pick_color:
|
||||
* If he is halucinating, pick a random color name and return it,
|
||||
* otherwise return the given color.
|
||||
*/
|
||||
char *
|
||||
pick_color(char *col)
|
||||
{
|
||||
return (on(player, ISHALU) ? (char *)rainbow[rnd(NCOLORS)] : col);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user