Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kycfile contract #204

Merged
merged 17 commits into from
Sep 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This vector is only used inside sync_whitelist_wallet. why do we need two methods for this?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where keysNotFound is used.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may add an RPC for this if needed - keysNotFound will be used for that.

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