Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make script interpreter independent from storage type CScript #13062

Closed
wants to merge 8 commits into from

Conversation

sipa
Copy link
Member

@sipa sipa commented Apr 23, 2018

This introduces versions of GetScriptOp, EvalScript, and VerifyScript that operate on scripts represented by Span<const unsigned char>. This makes it possible to use different representation types for scripts, as Spans can be used to refer to scripts stored in any continuous fashion in memory, regardless of the container.

This is also a step towards reducing the consensus-criticalness of CScript, but not entirely. The interpreter code still uses CScript internally for a few purposes (notably DecodeOP_N, and operator<<).

Longer term, the goal is removing the need for all scripts to share the same representation. Currently CScript is a prevector with 28 preallocated bytes - a choice we need because it's favorable for scriptPubKeys in the UTXO cache, but it's pretty terrible for storing scriptSigs. With this change, separate (or even custom) data structures can be used for UTXO scriptPubKeys, and scriptPubKeys/scriptSigs in transactions. One possibility for the latter is storing all scripts in a transaction concatenated in a single allocated area, rather than using separate allocations for each.

Copy link
Member

@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, will look more closely later.

src/span.h Outdated
constexpr std::ptrdiff_t size() const noexcept { return m_size; }
constexpr C& operator[](std::ptrdiff_t pos) const noexcept { return m_data[pos]; }

constexpr Span<C> subspan(std::ptrdiff_t offset) const noexcept { return Span<C>(m_data + offset, m_size - offset); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, equivalent to count = std::dynamic_extent in std::span.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is the default, so I think it's fine. Generally all methods here mimic a subset of the behaviour of std::span, but sometimes with optional arguments/types omitted.

@laanwj
Copy link
Member

laanwj commented Apr 25, 2018

Makes interpreter.cpp more self-contained, that's good.
Verified that:

  • Consensus IsPayToScriptHash matches CScript::IsPayToScriptHash: copy-only apart from variable names
  • Consensus IsWitnessProgram matches CScript::IsWitnessProgram:
    • a size_t becomes ptr_diff_t: not an issue as only positive values are possible (unsigned char + 2)
    • std::vector<unsigned char>(this->begin() + 2, this->end()) becomes script.subspan(2): should be ok, it's defined as Span(m_data + offset, m_size - offset)
  • Consensus IsPushOnly matches CScript::IsPushOnly:
    • pc becomes Span instead of a const_iterator: effective behavior is the same
    • GetOp becomes GetScriptOp: GetOp is already defined in that way, so should be fine

Other changes look straightforward.

utACK 91c12000dd97d7b9b9c82d1bbc92c7bbadd3d6ed

@TheBlueMatt
Copy link
Contributor

This seems to be lacking a bunch of motivation. Can you clarify why you want to run a script stored in a span?

@sipa
Copy link
Member Author

sipa commented Apr 27, 2018

@TheBlueMatt They're not stored in a Span; a Span is just a way to refer to a script stored anywhere (vector, array, prevector, whatever custom structure that can hold a continuous sequence of bytes).

I'll add some more motivation.

@TheBlueMatt
Copy link
Contributor

Suresure, I was asking for motivation of where we want to do this in the immediate future (do you have any branches that run scripts in non-prevector form?). The only place I can think of it being useful is in libbitcoinconsensus.

@sipa
Copy link
Member Author

sipa commented Apr 27, 2018

@TheBlueMatt No code to show, but I added some thoughts to the PR description.

@TheBlueMatt
Copy link
Contributor

Ah, the scriptPubKey/scriptSig distinction seems like a reasonable idea. Would love to see a branch with that implemented to see the feasibility of using this in the short-term after a merge.

src/script/script.cpp Show resolved Hide resolved
src/script/script.cpp Outdated Show resolved Hide resolved
src/script/interpreter.cpp Outdated Show resolved Hide resolved
@ryanofsky
Copy link
Contributor

Related discussion in IRC: https://botbot.me/freenode/bitcoin-core-dev/msg/99929791/

src/span.h Outdated Show resolved Hide resolved
@sipa
Copy link
Member Author

sipa commented May 31, 2018

Rebased.

src/script/script.cpp Outdated Show resolved Hide resolved
src/script/script.cpp Outdated Show resolved Hide resolved
@achow101
Copy link
Member

utACK 6ae8a5d

src/span.h Outdated Show resolved Hide resolved
@jb55
Copy link
Contributor

jb55 commented Jun 21, 2018

utACK ae8df82ad34a6baaf883411308255e6c6d093c53

@promag
Copy link
Member

promag commented Jun 21, 2018

utACK ae8df82.

@achow101
Copy link
Member

re-utACK ae8df82ad34a6baaf883411308255e6c6d093c53

@sipa
Copy link
Member Author

sipa commented Aug 1, 2018

Rebased.

fanquake added a commit that referenced this pull request Feb 14, 2022
… witness programs

34d0e07 Test that OP_1-OP_16 (but not lower/higher) start witness programs (Pieter Wuille)

Pull request description:

  Cherry-picks one of the commits adding test coverage from #13062. As [pointed out by aj](https://github.com/bitcoin/bitcoin/pull/13062/files#r492723037):
  > could move the test additions to the first commit, since they're testing things that are already true

  Pull the additional test code into master earlier.

ACKs for top commit:
  laanwj:
    Code review ACK 34d0e07

Tree-SHA512: ff0ab2a54613ea6e8246b443363b362dd41b5e464faba4d11be6003aa6588a626cf56e142a3b94465cd37dd3ac4debea08455db96bade336171b6c30ea894950
laanwj pushed a commit to laanwj/bitcoin that referenced this pull request Feb 14, 2022
…) start witness programs

34d0e07 Test that OP_1-OP_16 (but not lower/higher) start witness programs (Pieter Wuille)

Pull request description:

  Cherry-picks one of the commits adding test coverage from bitcoin#13062. As [pointed out by aj](https://github.com/bitcoin/bitcoin/pull/13062/files#r492723037):
  > could move the test additions to the first commit, since they're testing things that are already true

  Pull the additional test code into master earlier.

ACKs for top commit:
  laanwj:
    Code review ACK 34d0e07

Tree-SHA512: ff0ab2a54613ea6e8246b443363b362dd41b5e464faba4d11be6003aa6588a626cf56e142a3b94465cd37dd3ac4debea08455db96bade336171b6c30ea894950
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Feb 14, 2022
…) start witness programs

34d0e07 Test that OP_1-OP_16 (but not lower/higher) start witness programs (Pieter Wuille)

Pull request description:

  Cherry-picks one of the commits adding test coverage from bitcoin#13062. As [pointed out by aj](https://github.com/bitcoin/bitcoin/pull/13062/files#r492723037):
  > could move the test additions to the first commit, since they're testing things that are already true

  Pull the additional test code into master earlier.

ACKs for top commit:
  laanwj:
    Code review ACK 34d0e07

Tree-SHA512: ff0ab2a54613ea6e8246b443363b362dd41b5e464faba4d11be6003aa6588a626cf56e142a3b94465cd37dd3ac4debea08455db96bade336171b6c30ea894950
sipa and others added 8 commits April 5, 2022 14:45
This introduces a version of GetScriptOp that is independent from the script
storage type.
The CScript methods IsPayToScriptHash, IsWitnessProgram, and IsPushOnly are currently
consensus critical, and dependent on the storage type (CScript).

This creates new consensus-critical versions inside interpreter that operate on the
more efficient Span<const unsigned char> type, independent from the script storage.

The CScript methods remain, but are no longer consensus-critical.
This introduces a version of EvalScript that is independent from the storage type.
@sipa
Copy link
Member Author

sipa commented Apr 5, 2022

Rebased.

Copy link
Contributor

@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review ACK f5ad705

@DrahtBot
Copy link
Contributor

🐙 This pull request conflicts with the target branch and needs rebase.

Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft".

@ajtowns
Copy link
Contributor

ajtowns commented Oct 5, 2022

I think rebasing this to current master only requires:

+++ src/script/interpreter.cpp
-+    return (CHashWriter(HASHER_TAPLEAF) << leaf_version << COMPACTSIZE(script.size()) << script).GetSHA256();
++    return (HashWriter(HASHER_TAPLEAF) << leaf_version << COMPACTSIZE(script.size()) << script).GetSHA256();

+++ src/psbt.h
@@ -889,7 +889,7 @@ struct PSBTOutput
                     } else if (key.size() != 33) {
                         throw std::ios_base::failure("Output Taproot BIP32 keypath key is not at 33 bytes");
                     }
-                    XOnlyPubKey xonly(uint256({key.begin() + 1, key.begin() + 33}));
+                    XOnlyPubKey xonly(Span<const unsigned char>(key).subspan(1, 32));

@achow101
Copy link
Member

Closing this as it has not had any activity in a while. If you are interested in continuing work on this, please leave a comment so that it can be reopened.

@achow101 achow101 closed this Oct 12, 2022
@bitcoin bitcoin locked and limited conversation to collaborators Oct 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet