Browse Source

1. Fixed pending information containing other people's information.

2. Fixed keva undo.
cn
Jianping Wu 5 years ago
parent
commit
37dfb034a6
  1. 3
      src/keva/common.cpp
  2. 30
      src/keva/main.cpp
  3. 13
      src/keva/main.h
  4. 1
      src/txmempool.cpp
  5. 6
      src/txmempool.h
  6. 1
      src/undo.h
  7. 3
      src/wallet/rpckeva.cpp
  8. 14
      src/wallet/wallet.cpp
  9. 89
      test/functional/feature_keva.py

3
src/keva/common.cpp

@ -226,8 +226,9 @@ CKevaCache::remove(const valtype& nameSpace, const valtype& key)
{ {
auto name = std::make_tuple(nameSpace, key); auto name = std::make_tuple(nameSpace, key);
const EntryMap::iterator ei = entries.find(name); const EntryMap::iterator ei = entries.find(name);
if (ei != entries.end()) if (ei != entries.end()) {
entries.erase(ei); entries.erase(ei);
}
deleted.insert(name); deleted.insert(name);
} }

30
src/keva/main.cpp

@ -36,33 +36,35 @@ CKevaTxUndo::fromOldState(const valtype& nameSpace, const valtype& key, const CC
void void
CKevaTxUndo::apply(CCoinsViewCache& view) const CKevaTxUndo::apply(CCoinsViewCache& view) const
{ {
if (isNew) if (isNew) {
view.DeleteName(nameSpace, key); view.DeleteName(nameSpace, key);
else }
else {
view.SetName(nameSpace, key, oldData, true); view.SetName(nameSpace, key, oldData, true);
}
} }
/* ************************************************************************** */ /* ************************************************************************** */
/* CKevaMemPool. */ /* CKevaMemPool. */
void void
CKevaMemPool::addUnchecked (const uint256& hash, const CTxMemPoolEntry& entry) CKevaMemPool::addUnchecked(const uint256& hash, const CKevaScript& kevaOp)
{ {
AssertLockHeld (pool.cs); AssertLockHeld (pool.cs);
if (entry.isNamespaceRegistration()) { if (kevaOp.isNamespaceRegistration()) {
const valtype& nameSpace = entry.getNamespace(); const valtype& nameSpace = kevaOp.getOpNamespace();
listUnconfirmedNamespaces.push_back(std::make_tuple(hash, nameSpace, entry.getDisplayName())); listUnconfirmedNamespaces.push_back(std::make_tuple(hash, nameSpace, kevaOp.getOpNamespaceDisplayName()));
} }
if (entry.isKeyUpdate()) { if (kevaOp.getKevaOp() == OP_KEVA_PUT) {
const valtype& nameSpace = entry.getNamespace(); const valtype& nameSpace = kevaOp.getOpNamespace();
listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, entry.getKey(), entry.getValue())); listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, kevaOp.getOpKey(), kevaOp.getOpValue()));
} }
if (entry.isKeyDelete()) { if (kevaOp.getKevaOp() == OP_KEVA_DELETE) {
const valtype& nameSpace = entry.getNamespace(); const valtype& nameSpace = kevaOp.getOpNamespace();
const valtype& empty = ValtypeFromString(""); const valtype& empty = ValtypeFromString("");
listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, entry.getKey(), empty)); listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, kevaOp.getOpKey(), empty));
} }
} }
@ -375,8 +377,8 @@ void ApplyKevaTransaction(const CTransaction& tx, unsigned nHeight,
} else if (op.isAnyUpdate()) { } else if (op.isAnyUpdate()) {
const valtype& nameSpace = op.getOpNamespace(); const valtype& nameSpace = op.getOpNamespace();
const valtype& key = op.getOpKey(); const valtype& key = op.getOpKey();
LogPrint (BCLog::KEVA, "Updating name at height %d: %s\n", LogPrint (BCLog::KEVA, "Updating key at height %d: %s %s\n",
nHeight, ValtypeToString (nameSpace).c_str ()); nHeight, ValtypeToString(nameSpace).c_str(), ValtypeToString(key).c_str());
CKevaTxUndo opUndo; CKevaTxUndo opUndo;
opUndo.fromOldState(nameSpace, key, view); opUndo.fromOldState(nameSpace, key, view);

13
src/keva/main.h

@ -147,18 +147,17 @@ public:
} }
/** /**
* Add an entry without checking it. It should have been checked * Added unconfirmed keva values.
* already. If this conflicts with the mempool, it may throw.
* @param hash The tx hash. * @param hash The tx hash.
* @param entry The new mempool entry. * @param entry The new keva entry.
*/ */
void addUnchecked (const uint256& hash, const CTxMemPoolEntry& entry); void addUnchecked(const uint256& hash, const CKevaScript& kevaOp);
/** /**
* Remove the given mempool entry. It is assumed that it is present. * Remove the given mempool entry. It is assumed that it is present.
* @param entry The entry to remove. * @param entry The entry to remove.
*/ */
void remove (const CTxMemPoolEntry& entry); void remove(const CTxMemPoolEntry& entry);
/** /**
* Remove conflicts for the given tx, based on name operations. I. e., * Remove conflicts for the given tx, based on name operations. I. e.,
@ -167,7 +166,7 @@ public:
* @param tx The transaction for which we look for conflicts. * @param tx The transaction for which we look for conflicts.
* @param removed Put removed tx here. * @param removed Put removed tx here.
*/ */
void removeConflicts (const CTransaction& tx); void removeConflicts(const CTransaction& tx);
/** /**
* Check if a tx can be added (based on name criteria) without * Check if a tx can be added (based on name criteria) without
@ -175,7 +174,7 @@ public:
* @param tx The transaction to check. * @param tx The transaction to check.
* @return True if it doesn't conflict. * @return True if it doesn't conflict.
*/ */
bool checkTx (const CTransaction& tx) const; bool checkTx(const CTransaction& tx) const;
/** Keva get unconfirmed namespaces. */ /** Keva get unconfirmed namespaces. */
void getUnconfirmedNamespaceList(std::vector<std::tuple<valtype, valtype, uint256>>& nameSpaces) const; void getUnconfirmedNamespaceList(std::vector<std::tuple<valtype, valtype, uint256>>& nameSpaces) const;

1
src/txmempool.cpp

@ -423,7 +423,6 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
nTransactionsUpdated++; nTransactionsUpdated++;
totalTxSize += entry.GetTxSize(); totalTxSize += entry.GetTxSize();
if (minerPolicyEstimator) {minerPolicyEstimator->processTransaction(entry, validFeeEstimate);} if (minerPolicyEstimator) {minerPolicyEstimator->processTransaction(entry, validFeeEstimate);}
kevaMemPool.addUnchecked (hash, entry);
vTxHashes.emplace_back(tx.GetWitnessHash(), newit); vTxHashes.emplace_back(tx.GetWitnessHash(), newit);
newit->vTxHashesIdx = vTxHashes.size() - 1; newit->vTxHashesIdx = vTxHashes.size() - 1;

6
src/txmempool.h

@ -693,6 +693,12 @@ public:
return kevaMemPool.checkTx(tx); return kevaMemPool.checkTx(tx);
} }
inline void addKevaUnchecked(const uint256& hash, const CKevaScript& kevaOp)
{
AssertLockHeld(cs);
kevaMemPool.addUnchecked(hash, kevaOp);
}
/** Keva get unconfirmed key values. */ /** Keva get unconfirmed key values. */
bool getUnconfirmedKeyValue(const valtype& nameSpace, const valtype& key, valtype& value) const; bool getUnconfirmedKeyValue(const valtype& nameSpace, const valtype& key, valtype& value) const;

1
src/undo.h

@ -110,6 +110,7 @@ public:
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) { inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vtxundo); READWRITE(vtxundo);
READWRITE(vkevaundo);
} }
}; };

3
src/wallet/rpckeva.cpp

@ -184,7 +184,8 @@ UniValue keva_list_namespaces(const JSONRPCRequest& request)
UniValue res(UniValue::VARR); UniValue res(UniValue::VARR);
for (const auto& item : mapObjects) { for (const auto& item : mapObjects) {
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV(item.first, item.second); obj.pushKV("namespaceId", item.first);
obj.pushKV("displayName", item.second);
res.push_back(obj); res.push_back(obj);
} }

14
src/wallet/wallet.cpp

@ -3176,6 +3176,20 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
return false; return false;
} }
} else { } else {
CKevaScript kevaOp;
auto _tx = wtx.tx;
if (_tx->IsKevacoin()) {
for (const auto& txOut : _tx->vout) {
const CKevaScript curKevaOp(txOut.scriptPubKey);
if (!curKevaOp.isKevaOp()) {
continue;
}
assert(!kevaOp.isKevaOp());
kevaOp = curKevaOp;
}
assert(kevaOp.isKevaOp());
mempool.addKevaUnchecked(wtx.GetHash(), kevaOp);
}
wtx.RelayWalletTransaction(connman); wtx.RelayWalletTransaction(connman);
} }
} }

89
test/functional/feature_keva.py

@ -16,15 +16,91 @@ import re
class KevaTest(BitcoinTestFramework): class KevaTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
self.setup_clean_chain = True self.setup_clean_chain = True
self.num_nodes = 3 self.num_nodes = 2
def setup_network(self): def setup_network(self):
super().setup_network() super().setup_network()
connect_nodes(self.nodes[0], 2) connect_nodes_bi(self.nodes, 0, 1)
self.sync_all() self.sync_all()
def run_unconfirmed_namespaces(self):
self.sync_all()
response = self.nodes[1].keva_namespace('second_namespace')
namespaceId = response['namespaceId']
response = self.nodes[1].keva_list_namespaces()
# Node 0's unconfirmed namespace should not be here
assert(len(response) == 1)
# Node 0's unconfirmed operations should not be here
self.nodes[1].keva_put(namespaceId, 'second_key', 'second_value')
response = self.nodes[1].keva_pending()
# Pending namespace and put operation.
assert(len(response) == 2)
self.sync_all()
def run_test_disconnect_block(self, namespaceId):
key = 'This is the test key'
value = 'This is the test value'
self.nodes[0].keva_put(namespaceId, key, value)
self.nodes[0].generate(1)
response = self.nodes[0].keva_get(namespaceId, key)
assert(response['value'] == value)
# Disconnect the block
self.sync_all()
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
self.sync_all()
response = self.nodes[0].keva_get(namespaceId, key)
assert(response['value'] == '')
self.log.info("Test undeleting after disconnecting blocks")
keyToDelete = 'This is the test key to delete'
valueToDelete = 'This is the test value of the key'
self.nodes[0].keva_put(namespaceId, keyToDelete, valueToDelete)
self.nodes[0].generate(1)
response = self.nodes[0].keva_get(namespaceId, keyToDelete)
assert(response['value'] == valueToDelete)
# Now delete the key
self.nodes[0].keva_delete(namespaceId, keyToDelete)
self.nodes[0].generate(1)
response = self.nodes[0].keva_get(namespaceId, keyToDelete)
assert(response['value'] == '')
# Disconnect the block
self.sync_all()
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
self.sync_all()
response = self.nodes[0].keva_get(namespaceId, keyToDelete)
# The value should be undeleted.
assert(response['value'] == valueToDelete)
self.log.info("Test namespace after disconnecting blocks")
displayName = 'A new namspace'
response = self.nodes[0].keva_namespace(displayName)
newNamespaceId = response['namespaceId']
self.nodes[0].generate(1)
response = self.nodes[0].keva_list_namespaces()
found = False
print(response)
for ns in response:
if (ns['namespaceId'] == newNamespaceId):
found = True
assert(found)
# Now disconnect the block and the namespace should be gone.
self.sync_all()
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
self.sync_all()
found = False
for ns in response:
if (ns['namespaceId'] == newNamespaceId):
found = True
assert(not found)
def run_test(self): def run_test(self):
self.nodes[0].generate(161) #block 161 self.nodes[0].generate(105)
self.nodes[1].generate(105)
response = self.nodes[0].keva_namespace('first_namespace') response = self.nodes[0].keva_namespace('first_namespace')
namespaceId = response['namespaceId'] namespaceId = response['namespaceId']
@ -38,6 +114,9 @@ class KevaTest(BitcoinTestFramework):
response = self.nodes[0].keva_get(namespaceId, key) response = self.nodes[0].keva_get(namespaceId, key)
assert(response['value'] == value) assert(response['value'] == value)
self.log.info("Test other wallet's unconfirmed namespaces do not show up in ours")
self.run_unconfirmed_namespaces()
self.nodes[0].generate(1) self.nodes[0].generate(1)
response = self.nodes[0].keva_pending() response = self.nodes[0].keva_pending()
assert(len(response) == 0) assert(len(response) == 0)
@ -99,5 +178,9 @@ class KevaTest(BitcoinTestFramework):
response = self.nodes[0].keva_get(namespaceId, keyToDelete) response = self.nodes[0].keva_get(namespaceId, keyToDelete)
assert(response['value'] == newValue) assert(response['value'] == newValue)
self.log.info("Test disconnecting blocks")
self.run_test_disconnect_block(namespaceId)
if __name__ == '__main__': if __name__ == '__main__':
KevaTest().main() KevaTest().main()

Loading…
Cancel
Save