1 /********************************************************************
2 * (C) 2019 Michael Toutonghi
4 * Distributed under the MIT software license, see the accompanying
5 * file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 * This provides support for PBaaS identity definition,
9 * This is a decentralized identity class that provides the minimum
10 * basic function needed to enable persistent DID-similar identities,
11 * needed for signatories, that will eventually bridge compatibly to
28 #include "crosschainrpc.h"
29 #include "zcash/Address.hpp"
30 #include "script/script.h"
31 #include "script/standard.h"
32 #include "primitives/transaction.h"
33 #include "arith_uint256.h"
35 std::string CleanName(const std::string &Name, uint160 &Parent, bool displayapproved=false);
36 std::vector<std::string> ParseSubNames(const std::string &Name, std::string &ChainOut, bool displayfilter=false, bool addVerus=true);
41 static const CAmount DEFAULT_OUTPUT_AMOUNT = 0;
45 CCommitmentHash(const uint256 &Hash) : hash(Hash) {}
47 CCommitmentHash(const UniValue &uni)
49 hash = uint256S(uni_get_str(uni));
52 CCommitmentHash(const std::vector<unsigned char> &asVector)
54 ::FromVector(asVector, *this);
57 CCommitmentHash(const CTransaction &tx);
59 ADD_SERIALIZE_METHODS;
61 template <typename Stream, typename Operation>
62 inline void SerializationOp(Stream& s, Operation ser_action) {
66 UniValue ToUniValue() const
68 return UniValue(hash.GetHex());
72 class CNameReservation
75 static const CAmount DEFAULT_OUTPUT_AMOUNT = 0;
76 static const int MAX_NAME_SIZE = (KOMODO_ASSETCHAIN_MAXLEN - 1);
82 CNameReservation(const std::string &Name, const CIdentityID &Referral, const uint256 &Salt) : name(Name.size() > MAX_NAME_SIZE ? std::string(Name.begin(), Name.begin() + MAX_NAME_SIZE) : Name), referral(Referral), salt(Salt) {}
84 CNameReservation(const UniValue &uni)
87 name = CleanName(uni_get_str(find_value(uni, "name")), parent);
88 salt = uint256S(uni_get_str(find_value(uni, "salt")));
89 CTxDestination dest = DecodeDestination(uni_get_str(find_value(uni, "referral")));
90 if (dest.which() == COptCCParams::ADDRTYPE_ID)
92 referral = CIdentityID(GetDestinationID(dest));
94 else if (dest.which() != COptCCParams::ADDRTYPE_INVALID)
96 salt.SetNull(); // either valid destination, no destination, or invalid reservation
100 CNameReservation(const CTransaction &tx, int *pNumOut=nullptr);
102 CNameReservation(std::vector<unsigned char> &asVector)
104 ::FromVector(asVector, *this);
105 if (name.size() > MAX_NAME_SIZE)
107 name = std::string(name.begin(), name.begin() + MAX_NAME_SIZE);
111 ADD_SERIALIZE_METHODS;
113 template <typename Stream, typename Operation>
114 inline void SerializationOp(Stream& s, Operation ser_action) {
120 UniValue ToUniValue() const;
122 CCommitmentHash GetCommitment()
124 return CCommitmentHash(GetHash(*this));
129 return (name != "" && name.size() <= MAX_NAME_SIZE) && !salt.IsNull();
133 // this includes the necessary data for a principal to sign, but does not
134 // include enough information to derive a persistent identity
138 static const uint8_t VERSION_INVALID = 0;
139 static const uint8_t VERSION_VERUSID = 1;
140 static const uint8_t VERSION_PBAAS = 2;
141 static const uint8_t VERSION_FIRSTVALID = 1;
142 static const uint8_t VERSION_LASTVALID = 2;
148 std::vector<CTxDestination> primaryAddresses;
151 CPrincipal() : nVersion(VERSION_INVALID) {}
153 CPrincipal(uint32_t Version,
155 const std::vector<CTxDestination> &primary,
156 int32_t minPrimarySigs) :
159 primaryAddresses(primary),
160 minSigs(minPrimarySigs)
163 CPrincipal(const UniValue &uni);
164 CPrincipal(std::vector<unsigned char> &asVector)
166 ::FromVector(asVector, *this);
169 ADD_SERIALIZE_METHODS;
171 template <typename Stream, typename Operation>
172 inline void SerializationOp(Stream& s, Operation ser_action) {
175 std::vector<std::vector<unsigned char>> addressVs;
176 if (ser_action.ForRead())
178 READWRITE(addressVs);
180 for (auto vec : addressVs)
182 if (vec.size() == 20)
184 primaryAddresses.push_back(CTxDestination(CKeyID(uint160(vec))));
186 else if (vec.size() == 33)
188 primaryAddresses.push_back(CTxDestination(CPubKey(vec)));
192 primaryAddresses.push_back(CTxDestination(CNoDestination()));
198 for (auto dest : primaryAddresses)
200 addressVs.push_back(GetDestinationBytes(dest));
203 READWRITE(addressVs);
208 UniValue ToUniValue() const;
212 return nVersion >= VERSION_FIRSTVALID &&
213 nVersion <= VERSION_LASTVALID &&
214 primaryAddresses.size() &&
215 primaryAddresses.size() <= 10 &&
217 minSigs <= primaryAddresses.size();
220 bool IsPrimaryMutation(const CPrincipal &newPrincipal) const
222 if (nVersion != newPrincipal.nVersion ||
223 minSigs != minSigs ||
224 primaryAddresses.size() != newPrincipal.primaryAddresses.size())
228 for (int i = 0; i < primaryAddresses.size(); i++)
230 if (primaryAddresses[i] != newPrincipal.primaryAddresses[i])
239 class CIdentity : public CPrincipal
244 FLAG_REVOKED = 0x8000, // set when this identity is revoked
245 FLAG_ACTIVECURRENCY = 0x1, // flag that is set when this ID is being used as an active currency name
246 FLAG_LOCKED = 0x2, // set when this identity is revoked
247 MAX_UNLOCK_DELAY = 60 * 24 * 3 // 3 day maximum unlock time for an ID
250 static const int MAX_NAME_LEN = 64;
254 // real name or pseudonym, must be unique on the blockchain on which it is defined and can be used
255 // as a name for blockchains or other purposes on any chain in the Verus ecosystem once exported to
256 // the Verus chain. The hash of this name hashed with the parent if present, must equal the principal ID
258 // this name is always normalized to lower case. any identity that is registered
259 // on a PBaaS chain may be exported to the Verus chain and referenced by appending
260 // a dot ".", followed by the chain name on which this identity was registered.
261 // that will eventually create a domain name system as follows:
262 // root == VRSC (implicit), so a name that is defined on the Verus chain may be referenced as
265 // name from another chain == name.chainname
266 // the chainID that would derive from such a name will be Hash(ChainID(chainname) + Hash(name));
270 // content hashes, key value, where key is 20 byte ripemd160
271 std::map<uint160, uint256> contentMap;
273 // revocation authority - can only invalidate identity or update revocation
274 uint160 revocationAuthority;
276 // recovery authority - can change primary addresses in case of primary key loss or compromise
277 uint160 recoveryAuthority;
279 // z-addresses for contact and privately made attestations that can be proven to others
280 std::vector<libzcash::SaplingPaymentAddress> privateAddresses;
282 uint32_t unlockAfter;
284 CIdentity() : CPrincipal(), unlockAfter(0) {}
286 CIdentity(uint32_t Version,
288 const std::vector<CTxDestination> &primary,
289 int32_t minPrimarySigs,
290 const uint160 &Parent,
291 const std::string &Name,
292 const std::vector<std::pair<uint160, uint256>> &hashes,
293 const uint160 &Revocation,
294 const uint160 &Recovery,
295 const std::vector<libzcash::SaplingPaymentAddress> &Inboxes = std::vector<libzcash::SaplingPaymentAddress>(),
296 int32_t unlockTime=0) :
297 CPrincipal(Version, Flags, primary, minPrimarySigs),
300 revocationAuthority(Revocation),
301 recoveryAuthority(Recovery),
302 privateAddresses(Inboxes),
303 unlockAfter(unlockTime)
305 for (auto &entry : hashes)
307 if (!entry.first.IsNull())
309 contentMap[entry.first] = entry.second;
313 // any recognizable error should make this invalid
314 nVersion = VERSION_INVALID;
319 CIdentity(const UniValue &uni);
320 CIdentity(const CTransaction &tx, int *voutNum=nullptr);
321 CIdentity(const CScript &scriptPubKey);
322 CIdentity(const std::vector<unsigned char> &asVector)
324 ::FromVector(asVector, *this);
327 ADD_SERIALIZE_METHODS;
329 template <typename Stream, typename Operation>
330 inline void SerializationOp(Stream& s, Operation ser_action) {
331 READWRITE(*(CPrincipal *)this);
333 READWRITE(LIMITED_STRING(name, MAX_NAME_LEN));
335 std::vector<std::pair<uint160, uint256>> kvContent;
336 if (ser_action.ForRead())
338 READWRITE(kvContent);
339 for (auto &entry : kvContent)
341 if (!entry.first.IsNull())
343 contentMap[entry.first] = entry.second;
347 // any recognizable error should make this invalid
348 nVersion = VERSION_INVALID;
354 for (auto entry : contentMap)
356 kvContent.push_back(entry);
358 READWRITE(kvContent);
361 READWRITE(contentMap);
362 READWRITE(revocationAuthority);
363 READWRITE(recoveryAuthority);
364 READWRITE(privateAddresses);
366 if (nVersion >= VERSION_PBAAS)
368 READWRITE(unlockAfter);
372 UniValue ToUniValue() const;
376 flags |= FLAG_REVOKED;
382 flags &= ~FLAG_REVOKED;
385 bool IsRevoked() const
387 return flags & FLAG_REVOKED;
390 void Lock(int32_t unlockTime)
396 else if (unlockTime > MAX_UNLOCK_DELAY)
398 unlockTime = MAX_UNLOCK_DELAY;
400 flags |= FLAG_LOCKED;
401 unlockAfter = unlockTime;
404 void Unlock(uint32_t height, uint32_t txExpiryHeight)
408 flags &= ~FLAG_LOCKED;
413 flags &= ~FLAG_LOCKED;
414 unlockAfter += txExpiryHeight;
416 else if (height > unlockAfter)
420 if (unlockAfter > (txExpiryHeight + MAX_UNLOCK_DELAY))
422 unlockAfter = txExpiryHeight + MAX_UNLOCK_DELAY;
426 // This only returns the state of the lock flag. Note that an ID stays locked from spending or
427 // signing until the height it was unlocked plus the time lock applied when it was locked.
428 bool IsLocked() const
430 return flags & FLAG_LOCKED;
433 // consider the unlockAfter height as well
434 // this continues to return that it is locked after it is unlocked
435 // until passed the parameter of the height at which it was unlocked, plus the time lock
436 bool IsLocked(uint32_t height) const
438 return nVersion >= VERSION_PBAAS &&
439 (IsLocked() || unlockAfter >= height) &&
443 int32_t UnlockHeight() const
448 void ActivateCurrency()
450 if (nVersion == VERSION_FIRSTVALID)
452 nVersion = VERSION_PBAAS;
454 flags |= FLAG_ACTIVECURRENCY;
457 void DeactivateCurrency()
459 flags &= ~FLAG_ACTIVECURRENCY;
462 bool HasActiveCurrency() const
464 return flags & FLAG_ACTIVECURRENCY;
469 return CPrincipal::IsValid() && name.size() > 0 && (name.size() <= MAX_NAME_LEN);
472 bool IsValidUnrevoked() const
474 return IsValid() && !IsRevoked();
477 CIdentityID GetID() const;
478 CIdentityID GetID(const std::string &Name) const;
479 static CIdentityID GetID(const std::string &Name, uint160 &parent);
481 CIdentity LookupIdentity(const std::string &name, uint32_t height=0, uint32_t *pHeightOut=nullptr, CTxIn *pTxIn=nullptr);
482 static CIdentity LookupIdentity(const CIdentityID &nameID, uint32_t height=0, uint32_t *pHeightOut=nullptr, CTxIn *pTxIn=nullptr);
483 static CIdentity LookupFirstIdentity(const CIdentityID &idID, uint32_t *pHeightOut=nullptr, CTxIn *idTxIn=nullptr, CTransaction *pidTx=nullptr);
485 CIdentity RevocationAuthority() const
487 return GetID() == revocationAuthority ? *this : LookupIdentity(revocationAuthority);
490 CIdentity RecoveryAuthority() const
492 return GetID() == recoveryAuthority ? *this : LookupIdentity(recoveryAuthority);
495 template <typename TOBJ>
496 CTxOut TransparentOutput(uint8_t evalcode, CAmount nValue, const TOBJ &obj) const
500 if (IsValidUnrevoked())
502 CConditionObj<TOBJ> ccObj = CConditionObj<TOBJ>(evalcode, std::vector<CTxDestination>({CTxDestination(CIdentityID(GetID()))}), 1, &obj);
503 ret = CTxOut(nValue, MakeMofNCCScript(ccObj));
508 template <typename TOBJ>
509 CTxOut TransparentOutput(CAmount nValue) const
513 if (IsValidUnrevoked())
515 CConditionObj<TOBJ> ccObj = CConditionObj<TOBJ>(0, std::vector<CTxDestination>({CTxDestination(CIdentityID(GetID()))}), 1);
516 ret = CTxOut(nValue, MakeMofNCCScript(ccObj));
521 CScript TransparentOutput() const;
522 static CScript TransparentOutput(const CIdentityID &destinationID);
524 // creates an output script to control updates to this identity
525 CScript IdentityUpdateOutputScript(uint32_t height) const;
527 bool IsInvalidMutation(const CIdentity &newIdentity, uint32_t height, uint32_t expiryHeight) const
529 auto nSolVersion = CConstVerusSolutionVector::GetVersionByHeight(height);
530 if (parent != newIdentity.parent ||
531 (nSolVersion < CActivationHeight::ACTIVATE_IDCONSENSUS2 && name != newIdentity.name) ||
532 (nSolVersion < CActivationHeight::ACTIVATE_PBAAS && (newIdentity.HasActiveCurrency() ||
533 newIdentity.IsLocked() ||
534 newIdentity.nVersion >= VERSION_PBAAS)) ||
535 (nSolVersion >= CActivationHeight::ACTIVATE_PBAAS && newIdentity.nVersion < VERSION_PBAAS) ||
536 GetID() != newIdentity.GetID() ||
537 ((newIdentity.flags & ~FLAG_REVOKED) && (newIdentity.nVersion == VERSION_FIRSTVALID)) ||
538 ((newIdentity.flags & ~(FLAG_REVOKED + FLAG_ACTIVECURRENCY + FLAG_LOCKED)) && (newIdentity.nVersion >= VERSION_PBAAS)) ||
539 ((flags & FLAG_ACTIVECURRENCY) && !(newIdentity.flags & FLAG_ACTIVECURRENCY)) ||
540 newIdentity.nVersion < VERSION_FIRSTVALID ||
541 newIdentity.nVersion > VERSION_LASTVALID)
546 // we cannot unlock instantly unless we are revoked, we also cannot relock
547 // to enable an earlier unlock time
548 if (newIdentity.nVersion >= VERSION_PBAAS)
550 if (IsLocked(height))
552 if (!newIdentity.IsLocked(height) && !newIdentity.IsRevoked())
556 else if (!newIdentity.IsRevoked())
558 if (IsLocked() && !newIdentity.IsLocked())
560 if ((newIdentity.unlockAfter != (unlockAfter + expiryHeight)) &&
561 !(unlockAfter > MAX_UNLOCK_DELAY && newIdentity.unlockAfter == (MAX_UNLOCK_DELAY + expiryHeight)))
566 else if (!IsLocked())
568 // only revocation can change unlock after time, and we don't allow re-lock until unlock either, which
569 // can change the new unlock time
570 if (newIdentity.IsLocked())
572 if ((expiryHeight + newIdentity.unlockAfter < unlockAfter))
577 else if (newIdentity.unlockAfter != unlockAfter)
584 else if (newIdentity.IsLocked(height))
586 if (newIdentity.unlockAfter > MAX_UNLOCK_DELAY)
595 bool IsPrimaryMutation(const CIdentity &newIdentity, uint32_t height) const
597 auto nSolVersion = CConstVerusSolutionVector::GetVersionByHeight(height);
598 if (CPrincipal::IsPrimaryMutation(newIdentity) ||
599 (nSolVersion >= CActivationHeight::ACTIVATE_IDCONSENSUS2 && name != newIdentity.name && GetID() == newIdentity.GetID()) ||
600 contentMap != newIdentity.contentMap ||
601 privateAddresses != newIdentity.privateAddresses ||
602 unlockAfter != newIdentity.unlockAfter ||
603 (HasActiveCurrency() != newIdentity.HasActiveCurrency()) ||
604 IsLocked() != newIdentity.IsLocked())
611 bool IsRevocation(const CIdentity &newIdentity) const
613 if (!IsRevoked() && newIdentity.IsRevoked())
620 bool IsRevocationMutation(const CIdentity &newIdentity, uint32_t height) const
622 auto nSolVersion = CConstVerusSolutionVector::GetVersionByHeight(height);
623 if (revocationAuthority != newIdentity.revocationAuthority &&
624 (nSolVersion < CActivationHeight::ACTIVATE_IDCONSENSUS2 || !IsRevoked()))
631 bool IsRecovery(const CIdentity &newIdentity) const
633 if (IsRevoked() && !newIdentity.IsRevoked())
640 bool IsRecoveryMutation(const CIdentity &newIdentity, uint32_t height) const
642 auto nSolVersion = CConstVerusSolutionVector::GetVersionByHeight(height);
643 if (recoveryAuthority != newIdentity.recoveryAuthority ||
645 ((nSolVersion >= CActivationHeight::ACTIVATE_IDCONSENSUS2 && revocationAuthority != newIdentity.revocationAuthority) ||
646 IsPrimaryMutation(newIdentity, height))))
654 class CIdentityMapKey
658 static const uint16_t VALID = 1;
659 static const uint16_t CAN_SPEND = 0x8000;
660 static const uint16_t CAN_SIGN = 0x4000;
661 static const uint16_t MANUAL_HOLD = 0x2000; // we were CAN_SIGN in the past, so keep a last state updated after we are removed, keep it updated so its useful when signing related txes
662 static const uint16_t BLACKLIST = 0x1000; // do not track identities that are blacklisted
663 static const uint32_t MAX_BLOCKHEIGHT = INT32_MAX;
665 // these elements are used as a sort key for the identity map
666 // with most significant member first. flags have no effect on sort order, since elements will be unique already
667 CIdentityID idID; // 20 byte ID
668 uint32_t blockHeight; // four byte blockheight
669 uint32_t blockOrder; // 1-based numerical order if in the same block based on first to last spend, 1 otherwise, 0 is invalid except for queries
672 CIdentityMapKey() : blockHeight(0), blockOrder(1), flags(0) {}
673 CIdentityMapKey(const CIdentityID &id, uint32_t blkHeight=0, uint32_t orderInBlock=1, uint32_t Flags=0) : idID(id), blockHeight(blkHeight), blockOrder(orderInBlock), flags(Flags) {}
675 CIdentityMapKey(const arith_uint256 &mapKey)
677 flags = mapKey.GetLow64() & 0xffffffff;
678 blockOrder = mapKey.GetLow64() >> 32;
679 blockHeight = (mapKey >> 64).GetLow64() & 0xffffffff;
680 uint256 keyBytes(ArithToUint256(mapKey));
681 idID = CIdentityID(uint160(std::vector<unsigned char>(keyBytes.begin() + 12, keyBytes.end())));
684 ADD_SERIALIZE_METHODS;
686 template <typename Stream, typename Operation>
687 inline void SerializationOp(Stream& s, Operation ser_action) {
689 READWRITE(blockHeight);
690 READWRITE(blockOrder);
694 arith_uint256 MapKey() const
696 std::vector<unsigned char> vch(idID.begin(), idID.end());
697 vch.insert(vch.end(), 12, 0);
698 arith_uint256 retVal = UintToArith256(uint256(vch));
699 retVal = (retVal << 32) | blockHeight;
700 retVal = (retVal << 32) | blockOrder;
701 retVal = (retVal << 32) | flags;
705 // if it actually represents a real identity and not just a key for queries. blockOrder is 1-based
708 return !idID.IsNull() && blockHeight != 0 && flags & VALID && blockOrder >= 1;
711 std::string ToString() const
713 return "{\"id\":" + idID.GetHex() + ", \"blockheight\":" + std::to_string(blockHeight) + ", \"blockorder\":" + std::to_string(blockOrder) + ", \"flags\":" + std::to_string(flags) + ", \"mapkey\":" + ArithToUint256(MapKey()).GetHex() + "}";
718 return flags & CAN_SIGN;
721 bool CanSpend() const
723 return flags & CAN_SPEND;
727 class CIdentityMapValue : public CIdentity
732 CIdentityMapValue() : CIdentity() {}
733 CIdentityMapValue(const CTransaction &tx) : CIdentity(tx), txid(tx.GetHash()) {}
735 ADD_SERIALIZE_METHODS;
737 template <typename Stream, typename Operation>
738 inline void SerializationOp(Stream& s, Operation ser_action) {
739 READWRITE(*(CIdentity *)this);
744 // an identity signature is a compound signature consisting of the block height of its creation, and one or more cryptographic
745 // signatures of the controlling addresses. validation can be performed based on the validity when signed, using the block height
746 // stored in the signature instance, or based on the continued signature validity of the current identity, which may automatically
747 // invalidate when the identity is updated.
748 class CIdentitySignature
758 uint32_t blockHeight;
759 std::set<std::vector<unsigned char>> signatures;
761 CIdentitySignature() : version(VERSION_VERUSID), blockHeight(0) {}
762 CIdentitySignature(uint32_t height, const std::vector<unsigned char> &oneSig) : version(VERSION_VERUSID), blockHeight(height), signatures({oneSig}) {}
763 CIdentitySignature(uint32_t height, const std::set<std::vector<unsigned char>> &sigs) : version(VERSION_VERUSID), blockHeight(height), signatures(sigs) {}
764 CIdentitySignature(const std::vector<unsigned char> &asVector)
766 ::FromVector(asVector, *this);
769 template <typename Stream, typename Operation>
770 inline void SerializationOp(Stream& s, Operation ser_action) {
772 if (version <= VERSION_LAST && version >= VERSION_FIRST)
774 READWRITE(blockHeight);
775 std::vector<std::vector<unsigned char>> sigs;
776 if (ser_action.ForRead())
780 for (auto &oneSig : sigs)
782 signatures.insert(oneSig);
787 for (auto &oneSig : signatures)
789 sigs.push_back(oneSig);
797 ADD_SERIALIZE_METHODS;
799 void AddSignature(const std::vector<unsigned char> &signature)
801 signatures.insert(signature);
811 return version <= VERSION_LAST && version >= VERSION_FIRST;
815 struct CCcontract_info;
817 class CValidationState;
819 bool ValidateIdentityPrimary(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled);
820 bool ValidateIdentityRevoke(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled);
821 bool ValidateIdentityRecover(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled);
822 bool ValidateIdentityCommitment(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled);
823 bool ValidateIdentityReservation(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled);
824 bool PrecheckIdentityReservation(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height);
825 bool PrecheckIdentityReservation(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height, int referralLevels, int64_t referralAmount);
826 bool PrecheckIdentityPrimary(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height);
827 bool IsIdentityInput(const CScript &scriptSig);
828 bool ValidateQuantumKeyOut(struct CCcontract_info *cp, Eval* eval, const CTransaction &spendingTx, uint32_t nIn, bool fulfilled);
829 bool IsQuantumKeyOutInput(const CScript &scriptSig);
830 bool PrecheckQuantumKeyOut(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height);
831 bool ValidateFinalizeExport(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled);
832 bool IsFinalizeExportInput(const CScript &scriptSig);
833 bool FinalizeExportContextualPreCheck(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height);