Git Product home page Git Product logo

bpu's Introduction

BPU

Bitcoin Processing Unit

Transform Bitcoin Transactions into Virtual Procedure Call Units.

bpu

Features

  1. Turns a Bitcoin transaction inputs and outputs into a structured format called "tape"
  2. Chunk the push data sequence into "cells"
  3. Transform each push data through a custom transform function

Schema

BPU is a fork of TXO, but with a little different structure, and with customization features.

At a high level, BPU is a library that creates a nested structure of tapes and cells from a Bitcoin transaction with the following rule:

  1. i: positional index for whichever item it's attached to. applies to both tape and cell.
  2. ii: global positional index. only applies to cell. For example, a cell can have a local index i of 0, but global index ii of 3.
  3. b: base64 representation of a push data.
  4. s: UTF8 representation of a push data.
  5. op: a Bitcoin opcode number. only applies to push data items which are opcodes. (not buffer type push data)
  6. ops: a Bitcoin opcode string. only applies to push data items which are opcodes. (not buffer type push data)

BPU also lets you generate your own custom serialization format. One example is BOB (Bitcoin OP_RETURN Bytecode).

You can learn more about BOB here: https://medium.com/@_unwriter/hello-bob-94701d278afb

Also see how this format can be stored in a DB: https://bob.planaria.network/

Here's an example BPU parsed object, more specifically a BOB serialization format:

{
  "tx": {
    "h": "7e5011d81d01c67e81ab9a50ab3077bb62b340d1b50592931e4b52afa7198e65"
  },
  "in": [
    {
      "i": 0,
      "tape": [
        {
          "cell": [
            {
              "b": "MEQCIAwf5m6RfA1UICSFTlG2h4NEyfFui7qtxgria2EL1iVJAiA23uD0THoqzh9ONMMoxRMlJqqI8YU0dacNhqCkMaPY0kE=",
              "s": "0D\u0002 \f\u001f�n�|\rT $�NQ���D��n����\n�ka\u000b�%I\u0002 6���Lz*�\u001fN4�(�\u0013%&���4u�\r���1���A",
              "ii": 0,
              "i": 0
            },
            {
              "b": "AvLkgpq1RgHcLPYH7Q9uxCZnRgT0TDQwP2OEYmHZuWWb",
              "s": "\u0002�䂚�F\u0001�,�\u0007�\u000fn�&gF\u0004�L40?c�baٹe�",
              "ii": 1,
              "i": 1
            }
          ],
          "i": 0
        }
      ],
      "e": {
        "h": "9c4e6f32d9b49d439c7413ecb14662cc4853f9fb7f66b99965d8eb2610c0653d",
        "i": 1,
        "a": "17SnqQYGNZuD4zpu8eemt26TrdbvoJC5ie"
      }
    }
  ],
  "out": [
    {
      "i": 0,
      "tape": [
        {
          "cell": [
            {
              "op": 106,
              "ops": "OP_RETURN",
              "ii": 0,
              "i": 0
            }
          ],
          "i": 0
        },
        {
          "cell": [
            {
              "b": "MTlIeGlnVjRReUJ2M3RIcFFWY1VFUXlxMXB6WlZkb0F1dA==",
              "s": "19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut",
              "ii": 1,
              "i": 0
            },
            {
              "b": "SEFIQUhBSEE=",
              "s": "HAHAHAHA",
              "ii": 2,
              "i": 1
            },
            {
              "b": "dGV4dC9wbGFpbg==",
              "s": "text/plain",
              "ii": 3,
              "i": 2
            },
            {
              "b": "dGV4dA==",
              "s": "text",
              "ii": 4,
              "i": 3
            },
            {
              "b": "dHdldGNoX3R3dGV4dF8xNTY1MTMxNDIzNTU2LnR4dA==",
              "s": "twetch_twtext_1565131423556.txt",
              "ii": 5,
              "i": 4
            }
          ],
          "i": 1
        },
        {
          "cell": [
            {
              "b": "fA==",
              "s": "|",
              "ii": 6,
              "i": 0
            }
          ],
          "i": 2
        },
        {
          "cell": [
            {
              "b": "MVB1UWE3SzYyTWlLQ3Rzc1NMS3kxa2g1NldXVTdNdFVSNQ==",
              "s": "1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5",
              "ii": 7,
              "i": 0
            },
            {
              "b": "U0VU",
              "s": "SET",
              "ii": 8,
              "i": 1
            },
            {
              "b": "dHdkYXRhX2pzb24=",
              "s": "twdata_json",
              "ii": 9,
              "i": 2
            },
            {
              "b": "bnVsbA==",
              "s": "null",
              "ii": 10,
              "i": 3
            },
            {
              "b": "dXJs",
              "s": "url",
              "ii": 11,
              "i": 4
            },
            {
              "b": "bnVsbA==",
              "s": "null",
              "ii": 12,
              "i": 5
            },
            {
              "b": "Y29tbWVudA==",
              "s": "comment",
              "ii": 13,
              "i": 6
            },
            {
              "b": "bnVsbA==",
              "s": "null",
              "ii": 14,
              "i": 7
            },
            {
              "b": "bWJfdXNlcg==",
              "s": "mb_user",
              "ii": 15,
              "i": 8
            },
            {
              "b": "MzY2Nw==",
              "s": "3667",
              "ii": 16,
              "i": 9
            },
            {
              "b": "cmVwbHk=",
              "s": "reply",
              "ii": 17,
              "i": 10
            },
            {
              "b": "ODg0OTc3MDA4ZjdkMGE2Y2U1YjM5NzZkNTA4MzJjMGJiOGQ3ZTU5MjRiMWZkZTYwMGQ0YjE3NDFjZTVkYTBmOQ==",
              "s": "884977008f7d0a6ce5b3976d50832c0bb8d7e5924b1fde600d4b1741ce5da0f9",
              "ii": 18,
              "i": 11
            },
            {
              "b": "dHlwZQ==",
              "s": "type",
              "ii": 19,
              "i": 12
            },
            {
              "b": "cmVwbHk=",
              "s": "reply",
              "ii": 20,
              "i": 13
            },
            {
              "b": "dGltZXN0YW1w",
              "s": "timestamp",
              "ii": 21,
              "i": 14
            },
            {
              "b": "Mzk5NjU4OTEwMTMwMDc=",
              "s": "39965891013007",
              "ii": 22,
              "i": 15
            },
            {
              "b": "YXBw",
              "s": "app",
              "ii": 23,
              "i": 16
            },
            {
              "b": "dHdldGNo",
              "s": "twetch",
              "ii": 24,
              "i": 17
            }
          ],
          "i": 3
        },
        {
          "cell": [
            {
              "b": "fA==",
              "s": "|",
              "ii": 25,
              "i": 0
            }
          ],
          "i": 4
        },
        {
          "cell": [
            {
              "b": "MTVQY2lIRzIyU05MUUpYTW9TVWFXVmk3V1NxYzdoQ2Z2YQ==",
              "s": "15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva",
              "ii": 26,
              "i": 0
            },
            {
              "b": "QklUQ09JTl9FQ0RTQQ==",
              "s": "BITCOIN_ECDSA",
              "ii": 27,
              "i": 1
            },
            {
              "b": "MUFLSFZpWWdCR2JteGk4cWlKa052b0hOZUR1OW0zTWZQRQ==",
              "s": "1AKHViYgBGbmxi8qiJkNvoHNeDu9m3MfPE",
              "ii": 28,
              "i": 2
            },
            {
              "b": "IyNjb21wdXRlZF9zaWcjIw==",
              "s": "##computed_sig##",
              "ii": 29,
              "i": 3
            }
          ],
          "i": 5
        }
      ],
      "e": {
        "v": 0,
        "i": 0,
        "a": "false"
      }
    },
    {
      "i": 1,
      "tape": [
        {
          "cell": [
            {
              "op": 118,
              "ops": "OP_DUP",
              "ii": 0,
              "i": 0
            },
            {
              "op": 169,
              "ops": "OP_HASH160",
              "ii": 1,
              "i": 1
            },
            {
              "b": "CUcuns23XoX3EFhf0EVmDIPPqXk=",
              "s": "\tG.�ͷ^��\u0010X_�Ef\f�ϩy",
              "ii": 2,
              "i": 2
            },
            {
              "op": 136,
              "ops": "OP_EQUALVERIFY",
              "ii": 3,
              "i": 3
            },
            {
              "op": 172,
              "ops": "OP_CHECKSIG",
              "ii": 4,
              "i": 4
            }
          ],
          "i": 0
        }
      ],
      "e": {
        "v": 6900,
        "i": 1,
        "a": "1r4MYgWbmzz7g2HdEqLDusTQ4ZwrtEVCY"
      }
    },
    {
      "i": 2,
      "tape": [
        {
          "cell": [
            {
              "op": 118,
              "ops": "OP_DUP",
              "ii": 0,
              "i": 0
            },
            {
              "op": 169,
              "ops": "OP_HASH160",
              "ii": 1,
              "i": 1
            },
            {
              "b": "QRtHnMuB1770Vq3uNkvofZDiKyM=",
              "s": "A\u001bG�ˁ׾�V��6K�}��+#",
              "ii": 2,
              "i": 2
            },
            {
              "op": 136,
              "ops": "OP_EQUALVERIFY",
              "ii": 3,
              "i": 3
            },
            {
              "op": 172,
              "ops": "OP_CHECKSIG",
              "ii": 4,
              "i": 4
            }
          ],
          "i": 0
        }
      ],
      "e": {
        "v": 6900,
        "i": 2,
        "a": "16wFbu6pRa2sqDrnha6N56HVN91VppofyF"
      }
    },
    {
      "i": 3,
      "tape": [
        {
          "cell": [
            {
              "op": 118,
              "ops": "OP_DUP",
              "ii": 0,
              "i": 0
            },
            {
              "op": 169,
              "ops": "OP_HASH160",
              "ii": 1,
              "i": 1
            },
            {
              "b": "QRtHnMuB1770Vq3uNkvofZDiKyM=",
              "s": "A\u001bG�ˁ׾�V��6K�}��+#",
              "ii": 2,
              "i": 2
            },
            {
              "op": 136,
              "ops": "OP_EQUALVERIFY",
              "ii": 3,
              "i": 3
            },
            {
              "op": 172,
              "ops": "OP_CHECKSIG",
              "ii": 4,
              "i": 4
            }
          ],
          "i": 0
        }
      ],
      "e": {
        "v": 43793,
        "i": 3,
        "a": "16wFbu6pRa2sqDrnha6N56HVN91VppofyF"
      }
    }
  ]
}

Install

npm install --save bpu

Usage

1. Parse from raw transaction

const BPU = require('bpu');
// 'rawtx' is a raw transaction string
(async function() {
  let result = await BPU.parse({
    tx: { r: rawtx }
  })
})();

2. Parse from transaction id

In case you have access to JSON-RPC, you can parse directly from txid.

The first step is to update the .env file

BITCOIN_USERNAME=[Bitcoin Node Username]
BITCOIN_PASSWORD=[Bitcoin Node Password]
BITCOIN_IP=[Bitcoin Node IP]
BITCOIN_PORT=[Bitcoin Node Port]

Then you can use it like this:

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid }
  })
})();

3. Split

a. Split with "s"

Split with "|" (in UTF8)

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { s: "|" }
    }]
  })
})();

b. Split with "b"

Split with "fA==" in base64

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { b: "fA==" }
    }]
  })
})();

c. Split with "op"

Split with OP_RETURN ({op: 106})

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { op: 106 }
    }]
  })
})();

d. Split with "ops"

Split with OP_RETURN ({ops: "OP_RETURN"})

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { ops: "OP_RETURN" }
    }]
  })
})();

Split with OP_CODESEPARATOR ({ops: "OP_CODESEPARATOR"})

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { ops: "OP_CODESEPARATOR" }
    }]
  })
})();

e. Split and Discard

By default, "split" discards the delimiter from the result.

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { s: "|" }
    }]
  })
})();

f. Split and include the delimiter to the left

With "include": "l", you can merge the delimiter to the left side of the split arrays:

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { s: "|" },
      include: "l"
    }]
  })
})();

g. Split and include the delimiter to the right

With "include": "r", you can merge the delimiter to the right side of the split arrays:

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { s: "|" },
      include: "r"
    }]
  })
})();

h. Split and create a new cell in the center

With "include": "c", you can create a new standalone cell which contains the delimiter

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { s: "|" },
      include: "c"
    }]
  })
})();

i. Split with multiple tokens

You can split based on multiple delimiters. For example BOB chunks scripts based on OP_RETURN and |.

const BPU = require('bpu');
(async function() {
  let result = await BPU.parse({
    tx: { r: raw },
    split: [{
      token: { s: "|" }
    }, {
      token: { ops: "OP_RETURN" },
      include: "l"
    }]
  })
})();

4. transform

Transform each input/output script object:

const BPU = require('bpu');
// 'txid' is a transaction id
(async function() {
  let result = await BPU.parse({
    tx: { h: txid },
    split: [{
      token: { s: "|" }
    }],
    transform: function(o, c) {
      // if the buffer is larger than 512 bytes,
      // replace the key with "l" prepended attribute
      if (c.buf && c.buf.byteLength > 512) {
        o["ls"] = o.s;
        o["lb"] = o.b;
        delete o.s;
        delete o.b;
      }
      return o;
    },
  })
})

bpu's People

Contributors

unwriter avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.