aboutsummaryrefslogtreecommitdiff
path: root/src/script
AgeCommit message (Collapse)Author
2018-06-05Merge #13269: refactoring: Drop UpdateTransaction in favor of UpdateInputWladimir J. van der Laan
6aa33feadbe11bfa505a80a691d84db966aca134 Drop UpdateTransaction in favor of UpdateInput (Ben Woosley) Pull request description: Updating the input explicitly requires the caller to present a mutable input, which more clearly communicates the effects and intent of the call (and, often, the enclosing loop). In most cases, this input is already immediately available and need not be looked up. Tree-SHA512: 8c7914a8b7ae975d8ad0e9d760e3c5da65776a5f79d060b8ffb6b3ff7a32235f71ad705f2185b368d9263742d7796bb562395d22b806d90e8502d8c496011e57
2018-06-05Merge #13351: wallet: Prevent segfault when sending to unspendable witnessMarcoFalke
fa36aa7965 wallet: Prevent segfault when sending to unspendable witness (MarcoFalke) Pull request description: Previously we wouldn't care about the `txnouttype`, but after 4e91820531889e309dc4335fe0de8229c6426040 we `switch` on the type. Tree-SHA512: 6b597aba80cb43881671ad7b3a4ad97753864e8005a05c23fdd8ee79953483c08f241b5c392a9b494298eadc5cfba895b0480d916ef4f11d122fd6196f31b84a
2018-05-31Merge #13309: Directly operate with CMutableTransaction in SignSignatureWladimir J. van der Laan
6b8b63af1461dc11ffd813401e2c36fa44656715 Generic TransactionSignatureCreator works with both CTransaction and CMutableTransaction (Martin Ankerl) Pull request description: Refactored `TransactionSignatureCreator` into a templated `GenericTransactionSignatureCreator` that works with both `CMutableTransaction` and `CTransaction`. The advantage is that now in `SignSignature`, the `MutableTransactionSignatureCreator` can now operate directly with the `CMutableTransaction` without the need to copy the data into a `CTransaction`. Running all unit tests brings a very noticable speedup on my machine: 48.4 sec before this change 36.4 sec with this change -------- 12.0 seconds saved running only `--run_test=transaction_tests/test_big_witness_transaction`: 16.7 sec before this change 5.9 sec with this change -------- 10.8 seconds saved This relates to my first attempt with the const_cast hack #13202, and to the slow unit test issue #10026. Also see #13050 which modifies the tests but not the production code (like this PR) to get a speedup. Tree-SHA512: 2cff0e9699f484f26120a40e431a24c8bc8f9e780fd89cb0ecf20c5be3eab6c43f9c359cde244abd9f3620d06c7c354e3b9dd3da41fa2ca1ac1e09386fea25fb
2018-05-30wallet: Prevent segfault when sending to unspendable witnessMarcoFalke
2018-05-30Merge #13194: Remove template matching and pseudo opcodesWladimir J. van der Laan
c814e2e7e81fd01fcb07f4a28435741bdc463801 Remove template matching and pseudo opcodes (Pieter Wuille) Pull request description: The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are easier to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Tree-SHA512: 643b409c5c36821519f613a43efd399af0ec99b6131f35cd4024decfb2d483d719e0e921cd088bc9832a7ac797cb4a6b1158b8574c82f7fbebb75f1b31b359df
2018-05-30Generic TransactionSignatureCreator works with both CTransaction and ↵Martin Ankerl
CMutableTransaction Templated version so that no copying of CMutableTransaction into a CTransaction is necessary. This speeds up the test case transaction_tests/test_big_witness_transaction from 7.9 seconds to 3.1 seconds on my machine.
2018-05-29Remove template matching and pseudo opcodesPieter Wuille
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack.
2018-05-29Merge #13142: Separate IsMine from solvabilityWladimir J. van der Laan
c004ffc9b42a738043e19e4c812fc7e0566119c5 Make handling of invalid in IsMine more uniform (Pieter Wuille) a53f0feff8d42b7a40d417f77dc8de682dd88fd9 Add some checks for invalid recursion in IsMine (Pieter Wuille) b5802a9f5f69815d3290361fd8c96d76a037832f Simplify IsMine logic (Pieter Wuille) 4e91820531889e309dc4335fe0de8229c6426040 Make IsMine stop distinguishing solvable/unsolvable (Pieter Wuille) 6d714c3419b368671bd071a8992950c3dc00e613 Make coincontrol use IsSolvable to determine solvability (Pieter Wuille) Pull request description: Our current `IsMine` logic does several things with outputs: * Determine "spendability" (roughly corresponding to "could we sign for this") * Determine "watching" (is this an output directly or indirectly a watched script) * Determine invalidity (is this output definitely not legally spendable, detecting accidental uncompressed pubkeys in witnesses) * Determine "solvability" (would we be able to sign for this ignoring the fact that we may be missing some private keys). The last item (solvability) is mostly unrelated and only rarely needed (there is just one instance, inside the wallet's coin control logic). This PR changes that instance to use the separate `IsSolvable` function, and stop `IsMine` from distinguishing between solvable and unsolvable. As an extra, this also simplifies the `IsMine` logic and adds some extra checks (which wouldn't be hit unless someone adds already invalid scripts to their wallet). Tree-SHA512: 95a6ef75fbf2eedc5ed938c48a8e5d77dcf09c933372acdd0333129fb7301994a78498f9aacce2c8db74275e19260549dd67a83738e187d40b5090cc04f33adf
2018-05-24Make handling of invalid in IsMine more uniformPieter Wuille
2018-05-18Drop UpdateTransaction in favor of UpdateInputBen Woosley
Updating the input explicitly requires the caller to present a mutable input, which more clearly communicates the effects and intent of the method. In most cases, this input is already immediately available and need not be looked up.
2018-05-05Add constant scriptCode policy in non-segwit scriptsJohnson Lau
This disables OP_CODESEPARATOR in non-segwit scripts (even in an unexecuted branch), and makes a positive FindAndDelete result invalid. This ensures that the scriptCode serialized in SignatureHash() is always the same as the script passing to the EvalScript.
2018-05-03Add some checks for invalid recursion in IsMinePieter Wuille
2018-05-03Simplify IsMine logicPieter Wuille
2018-05-03Make IsMine stop distinguishing solvable/unsolvablePieter Wuille
2018-04-26Merge #13002: Do not treat bare multisig outputs as IsMine unless watchedWladimir J. van der Laan
7d0f80b Use anonymous namespace instead of static functions (Pieter Wuille) b61fb71 Mention removal of bare multisig IsMine in release notes (Pieter Wuille) 9c2a8b8 Do not treat bare multisig as IsMine (Pieter Wuille) 08f3228 Optimization: only test for witness scripts at top level (Pieter Wuille) 3619735 Track difference between scriptPubKey and P2SH execution in IsMine (Pieter Wuille) ac6ec62 Switch to a private version of SigVersion inside IsMine (Pieter Wuille) 19fc973 Do not expose SigVersion argument to IsMine (Pieter Wuille) fb1dfbb Remove unused IsMine overload (Pieter Wuille) 952d821 Make CScript -> CScriptID conversion explicit (Pieter Wuille) Pull request description: Currently our wallet code will treat bare multisig outputs (meaning scriptPubKeys with multiple public keys + `OP_CHECKMULTISIG` operator in it) as ours without the user asking for it, as long as all private keys in it are in our wallet. This is a pointless feature. As it only works when all private keys are in one place, it's useless compared to single key outputs (P2PK, P2PKH, P2WPKH, P2SH-P2WPKH), and worse in terms of space, cost, UTXO size, and ability to test (due to lack of address format for them). Furthermore, they are problematic in that producing a list of all `scriptPubKeys` we accept is not tractable (it involves all combinations of all public keys that are ours). In further wallet changes I'd like to move to a model where all scriptPubKeys that are treated as ours are explicit, rather than defined by whatever keys we have. The current behavior of the wallet is very hard to model in such a design, so I'd like to get rid of it. I think there are two options: * Remove it entirely (do not ever accept bare multisig outputs as ours, unless watched) * Only accept bare multisig outputs in situations where the P2SH version of that output would also be acceptable This PR implements the first option. The second option was explored in #12874. Tree-SHA512: 917ed45b3cac864cee53e27f9a3e900390c576277fbd6751b1250becea04d692b3b426fa09065a3399931013bd579c4f3dbeeb29d51d19ed0c64da75d430ad9a
2018-04-19Use anonymous namespace instead of static functionsPieter Wuille
2018-04-19Do not treat bare multisig as IsMinePieter Wuille
Such outputs can still be watched, and signed for, but they aren't treated as valid payments. That means they won't cause transactions to appear in listtransactions, their outputs to be shown under listunspent, or affect balances.
2018-04-19Optimization: only test for witness scripts at top levelPieter Wuille
Inside P2SH scripts we already know that the P2SH script version of witness keys/scripts are acceptable, so there is no need to test for it again.
2018-04-19Track difference between scriptPubKey and P2SH execution in IsMinePieter Wuille
Inside IsMine we care about the distinction between scriptPubKey execution and P2SH redeemScript execution. The consensus code does not care about this distinction, and thus SigVersion does not have a field for P2SH. As the IsMine code will care, it uses a separate enum with more fields.
2018-04-19Switch to a private version of SigVersion inside IsMinePieter Wuille
This will allow us to have the consensus code and IsMine code diverge.
2018-04-19Do not expose SigVersion argument to IsMinePieter Wuille
Only IsMine's internal code needs this, as part of a recursion into P2SH and P2WSH scripts. The exposed functions always operate on actual scriptPubKeys and not on redeemScripts or witness scripts.
2018-04-18Remove unused IsMine overloadPieter Wuille
2018-04-18Make CScript -> CScriptID conversion explicitPieter Wuille
2018-04-13[MOVEONLY] Turn CScript::GetOp2 into a function and move to cppPieter Wuille
2018-04-13[MOVEONLY] Move CSCript::FindAndDelete to interpreterPieter Wuille
2018-04-13Delete unused non-const-iterator CSCript::GetOp overloadsPieter Wuille
2018-04-13Make iterators in CScript::FindAndDelete constPieter Wuille
2018-04-12Drop dead code CScript::FindBen Woosley
Last use removed in 922e8e2929a2e78270868385aa46f96002fbcff3 (2012!)
2018-04-12Merge #12803: Make BaseSignatureCreator a pure interfaceWladimir J. van der Laan
be67831 Make DummySignatureCreator a singleton (Pieter Wuille) 190b8d2 Make BaseSignatureCreator a pure interface (Pieter Wuille) Pull request description: * Removes the `m_provider` field from `BaseSignatureCreator`. Instead both a `SigningProvider` (which provides keys and scripts) and a `BaseSignatureCreator` (which implements the transaction-specific (or other) signing logic) are passed into and down in `ProduceSignature`, making the two concepts orthogonal. * Makes `BaseSignatureCreator` a pure interface without constructor, making it easier to implement new derivations of it (for example for message signing). * As `DummySignatureCreator` now becomes a stateless object, turn it into a singleton `DUMMY_SIGNATURE_CREATOR`. Tree-SHA512: 5f1f4512e4ea7d02a31df7b9ede55008efa716c5b74a2630ca1c2fc6599584d8bf5f5641487266127f4b3788033803539fbd22b03ef1219c83c10da2d3da3dcd
2018-04-10Extract consts for WITNESS_V0 hash sizesBen Woosley
2018-04-10Merge #12731: Support serialization as another type without castingWladimir J. van der Laan
818dc74 Support serialization as another type without casting (Pieter Wuille) Pull request description: This adds a `READWRITEAS(type, obj)` macro which serializes `obj` as if it were converted to `const type&` when `const`, and to `type&` when non-`const`. No actual cast is involved, so this only works when this conversion can be done automatically. This makes it usable in serialization code that uses a single implementation for both serialization and deserializing, which doesn't know the constness of the object involved. This is a redo of #12712, using a slightly different interface. Tree-SHA512: 262f0257284ff99b5ffaec9b997c194e221522ba35c3ac8eaa9bb344449d7ea0a314de254dc77449fa7aaa600f8cd9a24da65aade8c1ec6aa80c6e9a7bba5ca7
2018-04-10Make DummySignatureCreator a singletonPieter Wuille
2018-04-10Make BaseSignatureCreator a pure interfacePieter Wuille
2018-04-04Merge #12167: Make segwit failure due to CLEANSTACK violation return a ↵Pieter Wuille
SCRIPT_ERR_CLEANSTACK error code 1e747e3c1e Make segwit failure due to CLEANSTACK violation return a SCRIPT_ERR_CLEANSTACK error code. (Mark Friedenbach) Pull request description: If a segwit script terminates with a stack size not equal to one, the current error code is EVAL_FALSE. This is semantically wrong, and prevents explicitly checking CLEANSTACK violations in the unit tests. This PR changes the error code (and affected unit tests) to use SCRIPT_ERROR_CLEANSTACK instead of SCRIPT_ERROR_EVAL_FALSE. Tree-SHA512: 8f7b1650f7a23a942cde1070e3e56420be456b4a7be42515b237e95557bf2bd5e7ba9aabd213c8092bea28c165dbe73f5a3486300089aeb01e698151b42484b1
2018-04-04Merge #12460: Assert CPubKey::ValidLength to the pubkey's header-relevant sizeMarcoFalke
f8c249ab91 Assert CPubKey::ValidLength to the pubkey's header-relevent size (Ben Woosley) Pull request description: A pubkey's length is specific to its type which is indicated by its header value. GetLen returns the header-indicated length, so this change ensures that a key matches its header-indicated length. And replace some magic values with their constant equivalents. Tree-SHA512: b727b39a631babe0932326396fc4d796ade8ec1e37454ff0c709ae9b78ecbd0cfdf59d84089ba8415e6efa7bc180e3cd39a14ddaf0871cbac54b96851e1b7b44
2018-04-01Merge #12757: Clarify include guard naming conventionMarcoFalke
3bcc0059b8 Add lint-include-guards.sh which checks include guard consistency (practicalswift) 8fd6af89a0 Fix missing or inconsistent include guards (practicalswift) 8af65d96f4 Document include guard convention (practicalswift) Pull request description: * **Documentation**: Document include guard convention * **Fix**: Fix missing or inconsistent include guards * **Regression test**: Add `lint-include-guards.sh` which checks include guard consistency Tree-SHA512: 8171878f60fd08ccbea943a11e835195750592abb9d7ab74eaa4265ae7fac523b1da9d31ca13d6ab73dd596e49986bfb7593c696e5f39567c93e610165bc2acc
2018-03-27Merge #12714: Introduce interface for signing providersWladimir J. van der Laan
d40f06a Introduce interface for signing providers (Pieter Wuille) Pull request description: `CKeyStore` is a rich interface that provides many features, including knowledge of scripts and pubkeys for solving, private keys for signing, in addition to watch-only keys and scripts, and distinguishing lack of keys from them just being encrypted. The signing logic in script/sign does not actually need most of these features. Here we introduce a simpler interface (`SigningProvider`) which *only* provides keys and scripts. This is actually sufficient for signing. In addtion, we swap the dependency between keystore and script/sign (keystore now depends on script/script with `CKeyStore` deriving from `SigningProvider`, rather than `CKeyStore` being the interface that signing relies on). This is a very early step towards the design in https://gist.github.com/sipa/125cfa1615946d0c3f3eec2ad7f250a2, separating the concern between deciding what outputs are ours and signing. Tree-SHA512: d511b7b03eec0e513530db1d9ae5aacf6d0bfa1d3e1c03d06c5bde396bafb5824c4491b227d32bcda9288530caf49835da18e846ccf66538d6c0cc6ae27291c9
2018-03-27Merge #10742: scripted-diff: Use scoped enumerations (C++11, "enum class")Wladimir J. van der Laan
1f45e21 scripted-diff: Convert 11 enums into scoped enums (C++11) (practicalswift) Pull request description: Rationale (from Bjarne Stroustrup's ["C++11 FAQ"](http://www.stroustrup.com/C++11FAQ.html#enum)): > > The enum classes ("new enums", "strong enums") address three problems with traditional C++ enumerations: > > * conventional enums implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer. > * conventional enums export their enumerators to the surrounding scope, causing name clashes. > * the underlying type of an enum cannot be specified, causing confusion, compatibility problems, and makes forward declaration impossible. > > The new enums are "enum class" because they combine aspects of traditional enumerations (names values) with aspects of classes (scoped members and absence of conversions). Tree-SHA512: 9656e1cf4c3cabd4378c7a38d0c2eaf79e4a54d204a3c5762330840e55ee7e141e188a3efb2b4daf0ef3110bbaff80d8b9253abf2a9b015cdc4d60b49ac2b914
2018-03-25Introduce interface for signing providersPieter Wuille
CKeyStore is a rich interface that provides many features, including knowledge of scripts and pubkeys for solving, private keys for signing, in addition to watch-only keys and scripts, and distinguishing lack of keys from them just being encrypted. The signing logic in script/sign does not actually need most of these features. Here we introduce a simpler interface (SigningProvider) which *only* provides keys and scripts. This is actually sufficient for signing. In addtion, we swap the dependency between keystore and script/sign (keystore now depends on script/script with CKeyStore deriving from SigningProvider, rather than CKeyStore being the interface that signing relies on).
2018-03-22Fix missing or inconsistent include guardspracticalswift
2018-03-21Fix typosDimitris Apostolou
2018-03-20Support serialization as another type without castingPieter Wuille
This adds a READWRITEAS(type, obj) macro which serializes obj as if it were casted to (const type&) when const, and to (type&) when non-const. This makes it usable in serialization code that uses a single implementation for both serialization and deserializing, which doesn't know the constness of the object involved.
2018-03-15Merge #12683: Fix more constness violations in serialization codePieter Wuille
172f5fa738 Support deserializing into temporaries (Pieter Wuille) 2761bca997 Merge READWRITEMANY into READWRITE (Pieter Wuille) Pull request description: This is another fragment of improvements from #10785. The current serialization code does not support serializing/deserializing from/to temporaries (like `s >> CFlatData(script)`). As a result, there are many invocations of the `REF` macro which in addition to changing the reference type also changes the constness. This is unnecessary in C++11 as we can use rvalue references now instead. The first commit is an extra simplification we can make that removes the duplication of code between `READWRITE` and `READWRITEMANY` (and related functions). Tree-SHA512: babfa9cb268cc3bc39917e4f0a90e4651c33d85032161e16547a07f3b257b7ca7940e0cbfd69f09439d26fafbb1a6cf6359101043407e2c7aeececf7f20b6eed
2018-03-13Support deserializing into temporariesPieter Wuille
Currently, the READWRITE macro cannot be passed any non-const temporaries, as the SerReadWrite function only accepts lvalue references. Deserializing into a temporary is very common, however. See for example things like 's >> VARINT(n)'. The VARINT macro produces a temporary wrapper that holds a reference to n. Fix this by accepting non-const rvalue references instead of lvalue references. We don't propagate the rvalue-ness down, as there are no useful optimizations that only apply to temporaries. Then use this new functionality to get rid of many (but not all) uses of the 'REF' macro (which casts away constness).
2018-03-09Calculate and store the number of bytes required to spend an inputAndrew Chow
2018-03-09scripted-diff: Convert 11 enums into scoped enums (C++11)practicalswift
-BEGIN VERIFY SCRIPT- sed -i 's/enum DBErrors/enum class DBErrors/g' src/wallet/walletdb.h git grep -l DB_ | xargs sed -i 's/DB_\(LOAD_OK\|CORRUPT\|NONCRITICAL_ERROR\|TOO_NEW\|LOAD_FAIL\|NEED_REWRITE\)/DBErrors::\1/g' sed -i 's/^ DBErrors::/ /g' src/wallet/walletdb.h sed -i 's/enum VerifyResult/enum class VerifyResult/g' src/wallet/db.h sed -i 's/\(VERIFY_OK\|RECOVER_OK\|RECOVER_FAIL\)/VerifyResult::\1/g' src/wallet/db.cpp sed -i 's/enum ThresholdState/enum class ThresholdState/g' src/versionbits.h git grep -l THRESHOLD_ | xargs sed -i 's/THRESHOLD_\(DEFINED\|STARTED\|LOCKED_IN\|ACTIVE\|FAILED\)/ThresholdState::\1/g' sed -i 's/^ ThresholdState::/ /g' src/versionbits.h sed -i 's/enum SigVersion/enum class SigVersion/g' src/script/interpreter.h git grep -l SIGVERSION_ | xargs sed -i 's/SIGVERSION_\(BASE\|WITNESS_V0\)/SigVersion::\1/g' sed -i 's/^ SigVersion::/ /g' src/script/interpreter.h sed -i 's/enum RetFormat {/enum class RetFormat {/g' src/rest.cpp sed -i 's/RF_\(UNDEF\|BINARY\|HEX\|JSON\)/RetFormat::\1/g' src/rest.cpp sed -i 's/^ RetFormat::/ /g' src/rest.cpp sed -i 's/enum HelpMessageMode {/enum class HelpMessageMode {/g' src/init.h git grep -l HMM_ | xargs sed -i 's/HMM_BITCOIN/HelpMessageMode::BITCOIN/g' sed -i 's/^ HelpMessageMode::/ /g' src/init.h sed -i 's/enum FeeEstimateHorizon/enum class FeeEstimateHorizon/g' src/policy/fees.h sed -i 's/enum RBFTransactionState/enum class RBFTransactionState/g' src/policy/rbf.h git grep -l RBF_ | xargs sed -i 's/RBF_TRANSACTIONSTATE_\(UNKNOWN\|REPLACEABLE_BIP125\|FINAL\)/RBFTransactionState::\1/g' sed -i 's/^ RBFTransactionState::/ /g' src/policy/rbf.h sed -i 's/enum BlockSource {/enum class BlockSource {/g' src/qt/clientmodel.h git grep -l BLOCK_SOURCE_ | xargs sed -i 's/BLOCK_SOURCE_\(NONE\|REINDEX\|DISK\|NETWORK\)/BlockSource::\1/g' sed -i 's/^ BlockSource::/ /g' src/qt/clientmodel.h sed -i 's/enum FlushStateMode {/enum class FlushStateMode {/g' src/validation.cpp sed -i 's/FLUSH_STATE_\(NONE\|IF_NEEDED\|PERIODIC\|ALWAYS\)/FlushStateMode::\1/g' src/validation.cpp sed -i 's/^ FlushStateMode::/ /g' src/validation.cpp sed -i 's/enum WitnessMode {/enum class WitnessMode {/g' src/test/script_tests.cpp sed -i 's/WITNESS_\(NONE\|PKH\|SH\)/WitnessMode::\1/g' src/test/script_tests.cpp sed -i 's/^ WitnessMode::/ /g' src/test/script_tests.cpp -END VERIFY SCRIPT-
2018-03-07Merge #11900: [script] simplify CheckMinimalPush checks, add safety assertWladimir J. van der Laan
0749808a7 CheckMinimalPush comments are prescriptive (Gregory Sanders) 176db6147 simplify CheckMinimalPush checks, add safety assert (Gregory Sanders) Pull request description: the two conditions could simply never be hit as `true`, as those opcodes have a push payload of size 0 in `data`. Added the assert for clarity for future readers(matching the gating in the interpreter) and safety for future use. This effects policy only. Tree-SHA512: f49028a1d5e907ef697b9bf5104c81ba8f6a331dbe5d60d8d8515ac17d2d6bfdc9dcc856a7e3dbd54814871b7d0695584d28da6553e2d9d7715430223f0b3690
2018-03-07CheckMinimalPush comments are prescriptiveGregory Sanders
2018-03-05Merge #11889: Drop extra script variable in ProduceSignatureWladimir J. van der Laan
9360f5032 Drop extra script variable in ProduceSignature (Russell Yanofsky) Pull request description: Was slightly confusing. Tree-SHA512: 1d18f92c133772ffc8eb71826c8d778988839a14bcefc50f9c591111b0a5f81ebc12bca0f1ab25d5fdd02d3d50c2325c04cbfcbdcd18a7b80ca112d049c2327d
2018-02-16Assert CPubKey::ValidLength to the pubkey's header-relevent sizeBen Woosley
Previously this was an inline test where the specificity was probably judged overly specific. As a class method it makes sense to maintain consistency. And replace some magic values with their constant equivalents.