Skip to content

Commit

Permalink
Merge pull request #204 from commerceblock/kycfileContract
Browse files Browse the repository at this point in the history
Kycfile contract
  • Loading branch information
lawlawlaw authored Sep 3, 2019
2 parents 01c870c + 30f46c6 commit 33b9140
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 50 deletions.
17 changes: 14 additions & 3 deletions qa/rpc-tests/onboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,22 @@ def run_test (self):
except JSONRPCException as e:
assert("No unassigned KYC public keys available" in e.error['message'])

#Register a KYC public key
self.nodes[0].topupkycpubkeys(1)
kycpkfile=self.initfile(os.path.join(self.options.tmpdir,"kycpkfile.dat"))
self.nodes[0].dumpkycpubkeys(kycpkfile)
nlines=self.linecount(kycpkfile)
assert_equal(nlines,2)

#Top up to one KYC public key
nkyckeys=1
self.nodes[0].topupkycpubkeys(nkyckeys)
self.nodes[0].generate(101)
self.sync_all()


self.nodes[0].dumpkycpubkeys(kycpkfile)
nlines=self.linecount(kycpkfile)
assert_equal(nlines,2+nkyckeys)


wb0_1=float(self.nodes[0].getbalance("", 1, False, "WHITELIST"))
assert_equal(wb0_1*coin,float(50000000000000-1))

Expand Down
90 changes: 85 additions & 5 deletions qa/rpc-tests/onboard_cit.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,76 @@ def run_test (self):
except JSONRPCException as e:
assert("No unassigned KYC public keys available" in e.error['message'])

kycpkfile=self.initfile(os.path.join(self.options.tmpdir,"kycpkfile.dat"))
self.nodes[0].dumpkycpubkeys(kycpkfile)
nlines=self.linecount(kycpkfile)
assert_equal(nlines,2)

#Register a KYC public key
nkyckeys=50
self.nodes[0].topupkycpubkeys(nkyckeys)
self.nodes[0].generate(101)
self.sync_all()

self.nodes[0].dumpkycpubkeys(kycpkfile)
nlines=self.linecount(kycpkfile)
assert_equal(nlines,2+nkyckeys)

#Register more keys (top up to 100)
nkyckeys=100
self.nodes[0].topupkycpubkeys(nkyckeys)
self.nodes[0].generate(101)
self.sync_all()

self.nodes[0].dumpkycpubkeys(kycpkfile)
nlines=self.linecount(kycpkfile)
assert_equal(nlines,2+nkyckeys)


#Remove all kycpubkeys
with open(kycpkfile) as fp:
for line in fp:
x=line.split()
if len(x) == 3:
try:
self.nodes[0].removekycpubkey(x[1])
except JSONRPCException as e:
print(e.error['message'])
assert(False)

time.sleep(5)
self.nodes[0].generate(101)
self.sync_all()

self.nodes[0].dumpkycpubkeys(kycpkfile)
nlines=self.linecount(kycpkfile)
assert_equal(nlines,2)

#Register a KYC public key
self.nodes[0].topupkycpubkeys(1)
self.nodes[0].generate(101)
self.sync_all()

self.nodes[0].dumpkycpubkeys(kycpkfile)
nlines=self.linecount(kycpkfile)
assert_equal(nlines,3)

wb0_1=float(self.nodes[0].getbalance("", 1, False, "WHITELIST"))
assert_equal(wb0_1*coin,float(50000000000000-1))

#Dump empty whitelist
wl1file_empty=self.initfile(os.path.join(self.options.tmpdir,"wl1_empty.dat"))
self.nodes[1].dumpwhitelist(wl1file_empty)

#Assert node1 address not in whitelist yet
node1addr=self.nodes[1].getnewaddress()
try:
iswl=self.nodes[0].querywhitelist(node1addr)
except JSONRPCException as e:
print(e.error['message'])
assert(False)
assert_equal(iswl, False)

#Onboard node0
kycfile0=self.initfile(os.path.join(self.options.tmpdir,"kycfile0.dat"))
userOnboardPubKey=self.nodes[0].dumpkycfile(kycfile0)
Expand All @@ -179,7 +237,6 @@ def run_test (self):
nlines_empty=self.linecount(wl1file_empty)
assert_equal(nlines-nlines_empty,keypool)


#Onboard node1
userOnboardPubKey=self.nodes[1].dumpkycfile(kycfile)
kycfile_plain=self.initfile(os.path.join(self.options.tmpdir,"kycfile_plain.dat"))
Expand All @@ -190,25 +247,48 @@ def run_test (self):

balance_1=self.nodes[0].getwalletinfo()["balance"]["WHITELIST"]
self.nodes[0].onboarduser(kycfile)

self.nodes[0].generate(101)
self.sync_all()

with open(kycfile_plain) as fp:
nline=0
for nline, line in enumerate(fp):
x=line.split()
if nline > 6 and len(x) > 1 and len(x[0]) > 1 and x[0][0] != '#':
try:
validate=self.nodes[1].validateaddress(x[0])
assert_equal(validate['isvalid'],True)
ismine=validate['ismine']
assert_equal(ismine, True)
except JSONRPCException as e:
print(e.error['message'])
assert(False)


balance_2=self.nodes[0].getwalletinfo()["balance"]["WHITELIST"]
#Make sure the onboard transaction fee was zero
assert((balance_1-balance_2) == 0)

self.nodes[1].dumpwhitelist(wl1file)
nlines=self.linecount(wl1file)
assert_equal(nlines-nlines_empty,2*keypool)

node1addr=self.nodes[1].getnewaddress()

node1addr=self.nodes[1].getnewaddress()
try:
iswl=self.nodes[0].querywhitelist(node1addr)
except JSONRPCException as e:
print(e.error['message'])
assert(False)
assert(iswl)
assert_equal(iswl, True)

node2addr=self.nodes[2].getnewaddress()

try:
iswl=self.nodes[0].querywhitelist(node2addr)
except JSONRPCException as e:
print(e.error['message'])
assert(False)
assert_equal(iswl, False)


#Send some tokens to node 1
Expand Down
97 changes: 92 additions & 5 deletions src/policy/whitelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "policy/policy.h"
#include "rpc/server.h"
#include "random.h"
#include <fstream>
#include <iostream>

CWhiteList::CWhiteList(){
_asset=whitelistAsset;
Expand Down Expand Up @@ -43,7 +45,7 @@ bool CWhiteList::Load(CCoinsView *view)
CCoinsViewCache coins(view);
std::unique_ptr<CCoinsViewCursor> pcursor(coins.Cursor());
LOCK(cs_main);

//main loop over coins (transactions with > 0 unspent outputs
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
Expand Down Expand Up @@ -75,7 +77,8 @@ bool CWhiteList::Load(CCoinsView *view)
// LogPrintf("POLICY: not adding invalid KYC pub key"+HexStr(kycPubKey.begin(), kycPubKey.end())+"\n");
} else {
//LogPrintf("POLICY: added unassigned KYC pub key "+HexStr(kycPubKey.begin(), kycPubKey.end())+"\n");
add_unassigned_kyc(kycPubKey);
COutPoint outPoint(key, i);
add_unassigned_kyc(kycPubKey, outPoint);
}
} else if ((whichType == TX_REGISTERADDRESS ||
whichType == TX_DEREGISTERADDRESS)
Expand All @@ -86,9 +89,49 @@ bool CWhiteList::Load(CCoinsView *view)
}
pcursor->Next();
}

sync_whitelist_wallet();

return true;
}

//Modifies a vector of the kyc public keys whose private keys were not found in the wallet.
void CWhiteList::sync_whitelist_wallet(std::vector<CPubKey>& keysNotFound){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
#ifndef ENABLE_WALLET
return false;
#endif
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
keysNotFound.clear();
int nTries = 0;
int nKeys = _kycUnassignedSet.size();
int nTriesMax = MAX_KYCPUBKEY_GAP + nKeys;
bool bKeyFound = true;
for(auto key : _kycUnassignedSet){
bKeyFound=true;
CKeyID kycKey=key.GetID();
CKey privKey;
while(!pwalletMain->GetKey(kycKey, privKey)){
pwalletMain->GenerateNewKey(true);
if(++nTries > nTriesMax){
keysNotFound.push_back(key);
bKeyFound=false;
break;
}
}
//Reset the gap if a key was found.
if(bKeyFound) nTries=std::min(nTries, nKeys);
}
}

void CWhiteList::sync_whitelist_wallet(){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
std::vector<CPubKey> keysNotFound;
sync_whitelist_wallet(keysNotFound);
}


void CWhiteList::add_destination(const CTxDestination& dest){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
if (dest.which() == ((CTxDestination)CNoDestination()).which()){
Expand Down Expand Up @@ -539,7 +582,8 @@ bool CWhiteList::Update(const CTransaction& tx, const CCoinsViewCache& mapInputs
if (!kycPubKey.IsFullyValid()) {
LogPrintf("POLICY: not adding invalid KYC pub key"+HexStr(kycPubKey.begin(), kycPubKey.end())+"\n");
} else {
add_unassigned_kyc(kycPubKey);
COutPoint outPoint(tx.GetHash(), i);
add_unassigned_kyc(kycPubKey, outPoint);
LogPrintf("POLICY: added KYC pub key "+HexStr(kycPubKey.begin(), kycPubKey.end())+"\n");
}
}
Expand Down Expand Up @@ -571,16 +615,43 @@ bool CWhiteList::is_unassigned_kyc(const CPubKey& kycPubKey){
return true;
}

void CWhiteList::add_unassigned_kyc(const CPubKey& id){
void CWhiteList::add_unassigned_kyc(const CPubKey& kycPubKey, const COutPoint& outPoint){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
_kycUnassignedSet.insert(id);
CKeyID kycKey=kycPubKey.GetID();
_kycPubkeyOutPointMap[kycKey]=outPoint;
_kycUnassignedSet.insert(kycPubKey);
}

bool CWhiteList::remove_unassigned_kyc(const CPubKey& id){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
return _kycUnassignedSet.erase(id);
}


void CWhiteList::dump_unassigned_kyc(std::ofstream& fStream){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
// add the base58check encoded tweaked public key and untweaked pubkey hex
for(auto it = _kycUnassignedSet.begin(); it != _kycUnassignedSet.end(); ++it) {
const CPubKey &pubKey = *it;
const CKeyID keyid = pubKey.GetID();
const CBitcoinAddress address(keyid);
std::string strAddr = address.ToString();
fStream << strAddr;
fStream << " ";
fStream << std::string(HexStr(pubKey.begin(), pubKey.end()));
fStream << " ";
isminetype mine = pwalletMain ? IsMine(*pwalletMain, keyid) : ISMINE_NO;
if (mine != ISMINE_NO && address.IsBlinded() && address.GetBlindingKey()
!= pwalletMain->GetBlindingPubKey(GetScriptForDestination(keyid))) {
// Note: this will fail to return ismine for deprecated static blinded addresses.
mine = ISMINE_NO;
}
bool bMine = (mine & ISMINE_SPENDABLE) ? true : false;
fStream << bMine;
fStream << std::endl;
}
}

void CWhiteList::clear(){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
CPolicyList::clear();
Expand Down Expand Up @@ -611,4 +682,20 @@ unsigned int CWhiteList::n_my_pending(){
return _myPending.size();
}

bool CWhiteList::get_kycpubkey_outpoint(const CKeyID& keyId, COutPoint& outPoint){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
auto it = _kycPubkeyOutPointMap.find(keyId);
if (it == _kycPubkeyOutPointMap.end()) return false;
outPoint = it->second;
return true;
}

bool CWhiteList::get_kycpubkey_outpoint(const CPubKey& pubKey, COutPoint& outPoint){
boost::recursive_mutex::scoped_lock scoped_lock(_mtx);
if(!pubKey.IsFullyValid())
return false;
return get_kycpubkey_outpoint(pubKey.GetID(), outPoint);
}



27 changes: 19 additions & 8 deletions src/policy/whitelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class CWhiteList : public CPolicyList{
CWhiteList();
virtual ~CWhiteList();

static const int64_t MAX_UNASSIGNED_KYCPUBKEYS=10000;
static const int64_t MAX_UNASSIGNED_KYCPUBKEYS=1000;
static const int64_t MAX_KYCPUBKEY_GAP=MAX_UNASSIGNED_KYCPUBKEYS;


void init_defaults();
Expand Down Expand Up @@ -73,6 +74,8 @@ class CWhiteList : public CPolicyList{

virtual bool peek_unassigned_kyc(CPubKey& pubKey);

void dump_unassigned_kyc(std::ofstream& fStream);

virtual bool LookupKYCKey(const CTxDestination& keyId, CKeyID& kycKeyIdFound){return false;}
virtual bool LookupKYCKey(const CTxDestination& keyId, CPubKey& pubKeyFound){return false;}
virtual bool LookupKYCKey(const CTxDestination& keyId, CKeyID& kycKeyIdFound, CPubKey& kycPubKeyFound){return false;}
Expand All @@ -98,15 +101,17 @@ class CWhiteList : public CPolicyList{
//Does nothing for unencrypted whitelist.
virtual void whitelist_kyc(const CPubKey& pubKey, const COutPoint* outPoint=nullptr){;}

virtual void add_unassigned_kyc(const CPubKey& pubKey);
bool get_kycpubkey_outpoint(const CKeyID& kycPubKeyId, COutPoint& outPoint);

virtual bool get_kycpubkey_outpoint(const CKeyID& kycPubKeyId, COutPoint& outPoint){
return false;
}
bool get_kycpubkey_outpoint(const CPubKey& kycPubKey, COutPoint& outPoint);

virtual void add_unassigned_kyc(const CPubKey& pubKey){
;
}

virtual bool get_kycpubkey_outpoint(const CPubKey& kycPubKey, COutPoint& outPoint){
return false;
}
void sync_whitelist_wallet(std::vector<CPubKey>& keysNotFound);

void sync_whitelist_wallet();


protected:
Expand All @@ -127,4 +132,10 @@ class CWhiteList : public CPolicyList{
const unsigned int nMultisigSize=1;
const unsigned int minPayloadSize=2;

std::map<CKeyID, COutPoint> _kycPubkeyOutPointMap;



private:
void add_unassigned_kyc(const CPubKey& pubKey, const COutPoint& outPoint);
};
Loading

0 comments on commit 33b9140

Please sign in to comment.