mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Add detection of liquidv1 fedpeg script, startup sanity check
This commit is contained in:
parent
32aec9af0b
commit
592a622b4b
6 changed files with 96 additions and 8 deletions
|
|
@ -70,20 +70,23 @@ bool GetAmountFromParentChainPegin(CAmount& amount, const CTransaction& txBTC, u
|
|||
}
|
||||
|
||||
// Takes federation redeem script and adds HMAC_SHA256(pubkey, scriptPubKey) as a tweak to each pubkey
|
||||
CScript calculate_contract(const CScript& federationRedeemScript, const CScript& scriptPubKey) {
|
||||
CScript calculate_contract(const CScript& federation_script, const CScript& scriptPubKey) {
|
||||
CScript scriptDestination;
|
||||
txnouttype type;
|
||||
std::vector<std::vector<unsigned char> > solutions;
|
||||
// Sanity check fedRedeemScript
|
||||
if (!Solver(federationRedeemScript, type, solutions) || (type != TX_MULTISIG && type != TX_TRUE)) {
|
||||
unsigned int required;
|
||||
std::vector<std::vector<unsigned char>> keys;
|
||||
// Sanity check federation_script only to match 3 templates
|
||||
if (federation_script != CScript() << OP_TRUE &&
|
||||
!MatchMultisig(federation_script, required, keys) &&
|
||||
!MatchLiquidWatchman(federation_script)) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
{
|
||||
CScript::const_iterator sdpc = federationRedeemScript.begin();
|
||||
CScript::const_iterator sdpc = federation_script.begin();
|
||||
std::vector<unsigned char> vch;
|
||||
opcodetype opcodeTmp;
|
||||
while (federationRedeemScript.GetOp(sdpc, opcodeTmp, vch))
|
||||
while (federation_script.GetOp(sdpc, opcodeTmp, vch))
|
||||
{
|
||||
size_t pub_len = 33;
|
||||
if (vch.size() == pub_len)
|
||||
|
|
@ -352,3 +355,75 @@ CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness) {
|
|||
//return CTxOut(CAsset(pegin_witness.stack[1]), value, CScript(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end()));
|
||||
return CTxOut(value, CScript(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end()));
|
||||
}
|
||||
|
||||
bool MatchLiquidWatchman(const CScript& script)
|
||||
{
|
||||
CScript::const_iterator it = script.begin();
|
||||
std::vector<unsigned char> data;
|
||||
opcodetype opcode;
|
||||
|
||||
// Stack depth check for branch choice
|
||||
if (!script.GetOp(it, opcode, data) || opcode != OP_DEPTH) {
|
||||
return false;
|
||||
}
|
||||
// Take in value, then check equality
|
||||
if (!script.GetOp(it, opcode, data) ||
|
||||
!script.GetOp(it, opcode, data) ||
|
||||
opcode != OP_EQUAL) {
|
||||
return false;
|
||||
}
|
||||
// IF EQUAL
|
||||
if (!script.GetOp(it, opcode, data) || opcode != OP_IF) {
|
||||
return false;
|
||||
}
|
||||
// Take in value k, make sure minimally encoded number from 1 to 16
|
||||
if (!script.GetOp(it, opcode, data) ||
|
||||
opcode > OP_16 ||
|
||||
(opcode < OP_1NEGATE && !CheckMinimalPush(data, opcode))) {
|
||||
return false;
|
||||
}
|
||||
opcodetype opcode2 = opcode;
|
||||
std::vector<unsigned char> num = data;
|
||||
// Iterate through multisig stuff until ELSE is hit
|
||||
while (opcode != OP_ELSE) {
|
||||
if (!script.GetOp(it, opcode, data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Take minimally-encoded CSV push number k'
|
||||
if (!script.GetOp(it, opcode, data) ||
|
||||
opcode > OP_16 || (opcode < OP_1NEGATE && !CheckMinimalPush(data, opcode))) {
|
||||
return false;
|
||||
}
|
||||
// CSV
|
||||
if (!script.GetOp(it, opcode, data) || opcode != OP_CHECKSEQUENCEVERIFY) {
|
||||
return false;
|
||||
}
|
||||
// Drop the CSV number
|
||||
if (!script.GetOp(it, opcode, data) || opcode != OP_DROP) {
|
||||
return false;
|
||||
}
|
||||
// Take the minimally-encoded n of k-of-n multisig arg
|
||||
if (!script.GetOp(it, opcode, data) ||
|
||||
opcode > OP_16 || (opcode < OP_1NEGATE && !CheckMinimalPush(data, opcode)) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The two multisig k-numbers must not match, otherwise ELSE branch can not be reached
|
||||
if (opcode == opcode2 && num == data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the ENDIF
|
||||
while (opcode != OP_ENDIF) {
|
||||
if (!script.GetOp(it, opcode, data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// CHECKMULTISIG
|
||||
if (!script.GetOp(it, opcode, data) || opcode != OP_CHECKMULTISIG) {
|
||||
return false;
|
||||
}
|
||||
// No more pushes
|
||||
return (it + 1 == script.end());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,4 +22,13 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
|
|||
// Constructs unblinded output to be used in amount and scriptpubkey checks during pegin
|
||||
CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness);
|
||||
|
||||
/* Belt-and-suspenders-only matching against telescoped multisig used on Liquid v1:
|
||||
* Pseudo-structure:
|
||||
* Check number of elements on stack
|
||||
* If enough for federation multisig, push all multisig args onto stack except OP_CMS
|
||||
* If not, check CSV timeout, then if successful, push emergency key multisig args on
|
||||
* stack except OP_CMS. End if, then push OP_CMS.
|
||||
*/
|
||||
bool MatchLiquidWatchman(const CScript& script);
|
||||
|
||||
#endif // BITCOIN_PEGINS_H
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, co
|
|||
return true;
|
||||
}
|
||||
|
||||
bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
||||
bool CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
||||
// Excludes OP_1NEGATE, OP_1-16 since they are by definition minimal
|
||||
assert(0 <= opcode && opcode <= OP_PUSHDATA4);
|
||||
if (data.size() == 0) {
|
||||
|
|
|
|||
|
|
@ -196,4 +196,6 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
|
|||
|
||||
int FindAndDelete(CScript& script, const CScript& b);
|
||||
|
||||
bool CheckMinimalPush(const std::vector<unsigned char>& data, opcodetype opcode);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ static constexpr bool IsSmallInteger(opcodetype opcode)
|
|||
return opcode >= OP_1 && opcode <= OP_16;
|
||||
}
|
||||
|
||||
static bool MatchMultisig(const CScript& script, unsigned int& required, std::vector<valtype>& pubkeys)
|
||||
bool MatchMultisig(const CScript& script, unsigned int& required, std::vector<valtype>& pubkeys)
|
||||
{
|
||||
opcodetype opcode;
|
||||
valtype data;
|
||||
|
|
|
|||
|
|
@ -203,4 +203,6 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
|||
*/
|
||||
CScript GetScriptForWitness(const CScript& redeemscript);
|
||||
|
||||
bool MatchMultisig(const CScript& script, unsigned int& required, std::vector<std::vector<unsigned char>>& pubkeys);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_STANDARD_H
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue