Raven Core  3.0.0
P2P Digital Currency
sign.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Copyright (c) 2017-2019 The Raven Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include "script/sign.h"
8 
9 #include "key.h"
10 #include "keystore.h"
11 #include "policy/policy.h"
12 #include "primitives/transaction.h"
13 #include "script/standard.h"
14 #include "uint256.h"
15 
16 
17 typedef std::vector<unsigned char> valtype;
18 
19 TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
20 
21 bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
22 {
23  CKey key;
24  if (!keystore->GetKey(address, key))
25  return false;
26 
27  // Signing with uncompressed keys is disabled in witness scripts
28  if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed())
29  return false;
30 
31  uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
32  if (!key.Sign(hash, vchSig))
33  return false;
34  vchSig.push_back((unsigned char)nHashType);
35  return true;
36 }
37 
38 static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
39 {
40  std::vector<unsigned char> vchSig;
41  if (!creator.CreateSig(vchSig, address, scriptCode, sigversion))
42  return false;
43  ret.push_back(vchSig);
44  return true;
45 }
46 
47 static bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
48 {
49  int nSigned = 0;
50  int nRequired = multisigdata.front()[0];
51  for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
52  {
53  const valtype& pubkey = multisigdata[i];
54  CKeyID keyID = CPubKey(pubkey).GetID();
55  if (Sign1(keyID, creator, scriptCode, ret, sigversion))
56  ++nSigned;
57  }
58  return nSigned==nRequired;
59 }
60 
67 static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
68  std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion)
69 {
70  CScript scriptRet;
71  uint160 h160;
72  ret.clear();
73 
74  std::vector<valtype> vSolutions;
75  if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
76  return false;
77 
78  CKeyID keyID;
79  switch (whichTypeRet)
80  {
81  case TX_NONSTANDARD:
82  case TX_NULL_DATA:
83  return false;
85  return false;
87  case TX_NEW_ASSET:
88  keyID = CKeyID(uint160(vSolutions[0]));
89  if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion))
90  return false;
91  else
92  {
93  CPubKey vch;
94  creator.KeyStore().GetPubKey(keyID, vch);
95  ret.push_back(ToByteVector(vch));
96  }
97  return true;
98  case TX_TRANSFER_ASSET:
99  keyID = CKeyID(uint160(vSolutions[0]));
100  if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion))
101  return false;
102  else
103  {
104  CPubKey vch;
105  creator.KeyStore().GetPubKey(keyID, vch);
106  ret.push_back(ToByteVector(vch));
107  }
108  return true;
109 
110  case TX_REISSUE_ASSET:
111  keyID = CKeyID(uint160(vSolutions[0]));
112  if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion))
113  return false;
114  else
115  {
116  CPubKey vch;
117  creator.KeyStore().GetPubKey(keyID, vch);
118  ret.push_back(ToByteVector(vch));
119  }
120  return true;
122  case TX_PUBKEY:
123  keyID = CPubKey(vSolutions[0]).GetID();
124  return Sign1(keyID, creator, scriptPubKey, ret, sigversion);
125  case TX_PUBKEYHASH:
126  keyID = CKeyID(uint160(vSolutions[0]));
127  if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion))
128  return false;
129  else
130  {
131  CPubKey vch;
132  creator.KeyStore().GetPubKey(keyID, vch);
133  ret.push_back(ToByteVector(vch));
134  }
135  return true;
136  case TX_SCRIPTHASH:
137  if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) {
138  ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
139  return true;
140  }
141  return false;
142 
143  case TX_MULTISIG:
144  ret.push_back(valtype()); // workaround CHECKMULTISIG bug
145  return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion));
146 
148  ret.push_back(vSolutions[0]);
149  return true;
150 
152  CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
153  if (creator.KeyStore().GetCScript(h160, scriptRet)) {
154  ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
155  return true;
156  }
157  return false;
158 
159  default:
160  return false;
161  }
162 }
163 
164 static CScript PushAll(const std::vector<valtype>& values)
165 {
166  CScript result;
167  for (const valtype& v : values) {
168  if (v.size() == 0) {
169  result << OP_0;
170  } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {
171  result << CScript::EncodeOP_N(v[0]);
172  } else {
173  result << v;
174  }
175  }
176  return result;
177 }
178 
179 bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
180 {
181  CScript script = fromPubKey;
182  std::vector<valtype> result;
183  txnouttype whichType;
184  bool solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE);
185  bool P2SH = false;
186  CScript subscript;
187  sigdata.scriptWitness.stack.clear();
188 
189  if (solved && whichType == TX_SCRIPTHASH)
190  {
191  // Solver returns the subscript that needs to be evaluated;
192  // the final scriptSig is the signatures from that
193  // and then the serialized subscript:
194  script = subscript = CScript(result[0].begin(), result[0].end());
195  solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH;
196  P2SH = true;
197  }
198 
199  if (solved && whichType == TX_WITNESS_V0_KEYHASH)
200  {
201  CScript witnessscript;
202  witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
203  txnouttype subType;
204  solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0);
205  sigdata.scriptWitness.stack = result;
206  result.clear();
207  }
208  else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH)
209  {
210  CScript witnessscript(result[0].begin(), result[0].end());
211  txnouttype subType;
212  solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH;
213  result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
214  sigdata.scriptWitness.stack = result;
215  result.clear();
216  }
217 
218  if (P2SH) {
219  result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));
220  }
221  sigdata.scriptSig = PushAll(result);
222 
223  // Test solution
224  return solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
225 }
226 
228 {
229  SignatureData data;
230  assert(tx.vin.size() > nIn);
231  data.scriptSig = tx.vin[nIn].scriptSig;
232  data.scriptWitness = tx.vin[nIn].scriptWitness;
233  return data;
234 }
235 
236 void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)
237 {
238  assert(tx.vin.size() > nIn);
239  tx.vin[nIn].scriptSig = data.scriptSig;
240  tx.vin[nIn].scriptWitness = data.scriptWitness;
241 }
242 
243 bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
244 {
245  assert(nIn < txTo.vin.size());
246 
247  CTransaction txToConst(txTo);
248  TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType);
249 
250  SignatureData sigdata;
251  bool ret = ProduceSignature(creator, fromPubKey, sigdata);
252  UpdateTransaction(txTo, nIn, sigdata);
253  return ret;
254 }
255 
256 bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
257 {
258  assert(nIn < txTo.vin.size());
259  CTxIn& txin = txTo.vin[nIn];
260  assert(txin.prevout.n < txFrom.vout.size());
261  const CTxOut& txout = txFrom.vout[txin.prevout.n];
262 
263  return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
264 }
265 
266 static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
267  const std::vector<valtype>& vSolutions,
268  const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion)
269 {
270  // Combine all the signatures we've got:
271  std::set<valtype> allsigs;
272  for (const valtype& v : sigs1)
273  {
274  if (!v.empty())
275  allsigs.insert(v);
276  }
277  for (const valtype& v : sigs2)
278  {
279  if (!v.empty())
280  allsigs.insert(v);
281  }
282 
283  // Build a map of pubkey -> signature by matching sigs to pubkeys:
284  assert(vSolutions.size() > 1);
285  unsigned int nSigsRequired = vSolutions.front()[0];
286  unsigned int nPubKeys = vSolutions.size()-2;
287  std::map<valtype, valtype> sigs;
288  for (const valtype& sig : allsigs)
289  {
290  for (unsigned int i = 0; i < nPubKeys; i++)
291  {
292  const valtype& pubkey = vSolutions[i+1];
293  if (sigs.count(pubkey))
294  continue; // Already got a sig for this pubkey
295 
296  if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion))
297  {
298  sigs[pubkey] = sig;
299  break;
300  }
301  }
302  }
303  // Now build a merged CScript:
304  unsigned int nSigsHave = 0;
305  std::vector<valtype> result; result.push_back(valtype()); // pop-one-too-many workaround
306  for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
307  {
308  if (sigs.count(vSolutions[i+1]))
309  {
310  result.push_back(sigs[vSolutions[i+1]]);
311  ++nSigsHave;
312  }
313  }
314  // Fill any missing with OP_0:
315  for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
316  result.push_back(valtype());
317 
318  return result;
319 }
320 
321 namespace
322 {
323 struct Stacks
324 {
325  std::vector<valtype> script;
326  std::vector<valtype> witness;
327 
328  Stacks() {}
329  explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_), witness() {}
330  explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) {
332  }
333 
334  SignatureData Output() const {
335  SignatureData result;
336  result.scriptSig = PushAll(script);
337  result.scriptWitness.stack = witness;
338  return result;
339  }
340 };
341 }
342 
343 static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
344  const txnouttype txType, const std::vector<valtype>& vSolutions,
345  Stacks sigs1, Stacks sigs2, SigVersion sigversion)
346 {
347  switch (txType)
348  {
349  case TX_NONSTANDARD:
350  case TX_NULL_DATA:
351  // Don't know anything about this, assume bigger one is correct:
352  if (sigs1.script.size() >= sigs2.script.size())
353  return sigs1;
354  return sigs2;
356  // Don't know anything about this, assume bigger one is correct:
357  if (sigs1.script.size() >= sigs2.script.size())
358  return sigs1;
359  return sigs2;
360  case TX_PUBKEY:
361  case TX_PUBKEYHASH:
362  // Signatures are bigger than placeholders or empty scripts:
363  if (sigs1.script.empty() || sigs1.script[0].empty())
364  return sigs2;
365  return sigs1;
367  // Signatures are bigger than placeholders or empty scripts:
368  if (sigs1.witness.empty() || sigs1.witness[0].empty())
369  return sigs2;
370  return sigs1;
371  case TX_SCRIPTHASH:
372  if (sigs1.script.empty() || sigs1.script.back().empty())
373  return sigs2;
374  else if (sigs2.script.empty() || sigs2.script.back().empty())
375  return sigs1;
376  else
377  {
378  // Recur to combine:
379  valtype spk = sigs1.script.back();
380  CScript pubKey2(spk.begin(), spk.end());
381 
382  txnouttype txType2;
383  std::vector<std::vector<unsigned char> > vSolutions2;
384  Solver(pubKey2, txType2, vSolutions2);
385  sigs1.script.pop_back();
386  sigs2.script.pop_back();
387  Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion);
388  result.script.push_back(spk);
389  return result;
390  }
391  case TX_MULTISIG:
392  return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion));
394  if (sigs1.witness.empty() || sigs1.witness.back().empty())
395  return sigs2;
396  else if (sigs2.witness.empty() || sigs2.witness.back().empty())
397  return sigs1;
398  else
399  {
400  // Recur to combine:
401  CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end());
402  txnouttype txType2;
403  std::vector<valtype> vSolutions2;
404  Solver(pubKey2, txType2, vSolutions2);
405  sigs1.witness.pop_back();
406  sigs1.script = sigs1.witness;
407  sigs1.witness.clear();
408  sigs2.witness.pop_back();
409  sigs2.script = sigs2.witness;
410  sigs2.witness.clear();
411  Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SIGVERSION_WITNESS_V0);
412  result.witness = result.script;
413  result.script.clear();
414  result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end()));
415  return result;
416  }
417  case TX_TRANSFER_ASSET:
418  // Signatures are bigger than placeholders or empty scripts:
419  if (sigs1.script.empty() || sigs1.script[0].empty())
420  return sigs2;
421  return sigs1;
422  case TX_NEW_ASSET:
423  // Signatures are bigger than placeholders or empty scripts:
424  if (sigs1.script.empty() || sigs1.script[0].empty())
425  return sigs2;
426  return sigs1;
427  case TX_REISSUE_ASSET:
428  // Signatures are bigger than placeholders or empty scripts:
429  if (sigs1.script.empty() || sigs1.script[0].empty())
430  return sigs2;
431  return sigs1;
432 
433  default:
434  return Stacks();
435  }
436 }
437 
438 SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
439  const SignatureData& scriptSig1, const SignatureData& scriptSig2)
440 {
441  txnouttype txType;
442  std::vector<std::vector<unsigned char> > vSolutions;
443  Solver(scriptPubKey, txType, vSolutions);
444 
445  return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output();
446 }
447 
448 namespace {
450 class DummySignatureChecker : public BaseSignatureChecker
451 {
452 public:
453  DummySignatureChecker() {}
454 
455  bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
456  {
457  return true;
458  }
459 };
460 const DummySignatureChecker dummyChecker;
461 } // namespace
462 
464 {
465  return dummyChecker;
466 }
467 
468 bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const
469 {
470  // Create a dummy signature that is a valid DER-encoding
471  vchSig.assign(72, '\000');
472  vchSig[0] = 0x30;
473  vchSig[1] = 69;
474  vchSig[2] = 0x02;
475  vchSig[3] = 33;
476  vchSig[4] = 0x01;
477  vchSig[4 + 33] = 0x02;
478  vchSig[5 + 33] = 32;
479  vchSig[6 + 33] = 0x01;
480  vchSig[6 + 33 + 32] = SIGHASH_ALL;
481  return true;
482 }
void UpdateTransaction(CMutableTransaction &tx, unsigned int nIn, const SignatureData &data)
Definition: sign.cpp:236
SignatureData DataFromTransaction(const CMutableTransaction &tx, unsigned int nIn)
Extract signature data from a transaction, and insert it.
Definition: sign.cpp:227
unspendable OP_RETURN script that carries data
Definition: standard.h:65
bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType)
Produce a script signature for a transaction.
Definition: sign.cpp:243
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, unsigned int flags, const BaseSignatureChecker &checker, ScriptError *serror)
CScript scriptSig
Definition: sign.h:64
std::vector< CTxIn > vin
Definition: transaction.h:391
Virtual base class for signature creators.
Definition: sign.h:20
A signature creator for transactions.
Definition: sign.h:35
std::vector< std::vector< unsigned char > > stack
Definition: script.h:701
unsigned char * begin()
Definition: uint256.h:57
bool ProduceSignature(const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata)
Produce a script signature using a generic signature creator.
Definition: sign.cpp:179
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:143
bool Sign(const uint256 &hash, std::vector< unsigned char > &vchSig, uint32_t test_case=0) const
Create a DER-serialized signature.
Definition: key.cpp:161
SignatureData CombineSignatures(const CScript &scriptPubKey, const BaseSignatureChecker &checker, const SignatureData &scriptSig1, const SignatureData &scriptSig2)
Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 pl...
Definition: sign.cpp:438
unsigned int nIn
Definition: sign.h:37
int64_t CAmount
Amount in corbies (Can be negative)
Definition: amount.h:13
const CKeyStore * keystore
Definition: sign.h:22
iterator end()
Definition: prevector.h:293
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, int nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache)
const BaseSignatureChecker & Checker() const override
Definition: sign.cpp:463
An input of a transaction.
Definition: transaction.h:67
virtual bool CreateSig(std::vector< unsigned char > &vchSig, const CKeyID &keyid, const CScript &scriptCode, SigVersion sigversion) const =0
Create a singular (non-script) signature.
const CKeyStore & KeyStore() const
Definition: sign.h:26
An encapsulated public key.
Definition: pubkey.h:40
const std::vector< CTxOut > vout
Definition: transaction.h:288
virtual bool GetKey(const CKeyID &address, CKey &keyOut) const =0
TransactionSignatureCreator(const CKeyStore *keystoreIn, const CTransaction *txToIn, unsigned int nInIn, const CAmount &amountIn, int nHashTypeIn=SIGHASH_ALL)
Definition: sign.cpp:19
bool CreateSig(std::vector< unsigned char > &vchSig, const CKeyID &keyid, const CScript &scriptCode, SigVersion sigversion) const override
Create a singular (non-script) signature.
Definition: sign.cpp:21
An output of a transaction.
Definition: transaction.h:137
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:91
bool EvalScript(std::vector< std::vector< unsigned char > > &stack, const CScript &script, unsigned int flags, const BaseSignatureChecker &checker, SigVersion sigversion, ScriptError *serror)
CScriptWitness scriptWitness
Definition: sign.h:65
virtual bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const =0
bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:47
const TransactionSignatureChecker checker
Definition: sign.h:40
CRIPEMD160 & Write(const unsigned char *data, size_t len)
Definition: ripemd160.cpp:248
txnouttype
Definition: standard.h:57
256-bit opaque blob.
Definition: uint256.h:123
static opcodetype EncodeOP_N(int n)
Definition: script.h:590
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:396
A virtual base class for key stores.
Definition: keystore.h:19
RVN START.
Definition: standard.h:69
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:30
virtual bool CheckSig(const std::vector< unsigned char > &scriptSig, const std::vector< unsigned char > &vchPubKey, const CScript &scriptCode, SigVersion sigversion) const
Definition: interpreter.h:136
160-bit opaque blob.
Definition: uint256.h:112
std::vector< unsigned char > valtype
Definition: interpreter.cpp:16
std::vector< unsigned char > valtype
Definition: sign.cpp:17
iterator begin()
Definition: prevector.h:291
A mutable version of CTransaction.
Definition: transaction.h:389
An encapsulated private key.
Definition: key.h:36
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:270
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: ripemd160.cpp:274
bool CreateSig(std::vector< unsigned char > &vchSig, const CKeyID &keyid, const CScript &scriptCode, SigVersion sigversion) const override
Create a singular (non-script) signature.
Definition: sign.cpp:468
const CTransaction * txTo
Definition: sign.h:36
Definition: script.h:54
unspendable OP_RAVEN_ASSET script that carries data
Definition: standard.h:72
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const =0
A hasher class for RIPEMD-160.
Definition: ripemd160.h:13
Definition: script.h:103
virtual const BaseSignatureChecker & Checker() const =0
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:45
SigVersion
Definition: interpreter.h:125