• Stars
    star
    143
  • Rank 256,382 (Top 6 %)
  • Language
    Solidity
  • License
    MIT License
  • Created about 6 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

BokkyPooBah's Red-Black Binary Search Tree Library



BokkyPooBahs Red-Black Binary Search Tree Library

Status: Currently being tested and bug bounty open. Don't use in production without an audit, yet.

A gas-efficient Solidity library using the iterative (rather than recursive) Red-Black binary search tree algorithm to help you maintain a sorted uint key index for your data. Insertions, deletions and searches are in O(log n) time (and ~gas). Note that the key of 0 is prohibited. Use the sorted keys as indices to your mapping tables of data to access your data in sorted order.

Inserting a key into an empty tree costs 68,459 gas. Inserting a key into a tree with 9,999 keys costs 127,210 gas on average. Removing an element from a tree with a single key costs 44,835 gas. Removing a key from a tree with 10,000 keys cost 81,486 gas on average.

An important use-case for this library is to maintain a sorted on-chain order book in decentralised exchange smart contracts, providing a provably fair order matching algorithm.

Check out the online Red-black tree visualization tool- type in some 4 digit numbers and press Insert or Delete to see the insertions and rebalances animated.

See also Hitchen's Order Statistics Tree, an extension built from this library.



Table Of Contents



Overview

Binary Search Tree

The Red-Black Tree binary search tree is a self-rebalancing binary search tree. Following is a diagram of a fairly well-balanced binary search tree.

The following unbalanced binary search tree was generated by inserting the numbers 1 to 32 in sequential order [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]:

Inserting the keys into the binary search tree in sequential order will result in this unbalanced tree resembling a linked-list.


Red-Black Binary Search Tree

The red-black algorithm maintains a red or black colouring for each node in the tree, and uses this information to maintain a reasonably balanced tree. From Wikipedia:

In addition to the requirements imposed on a binary search tree the following must be satisfied by a red–black tree:

  • Each node is either red or black.
  • The root is black. This rule is sometimes omitted. Since the root can always be changed from red to black, but not necessarily vice versa, this rule has little effect on analysis.
  • All leaves (NIL) are black.
  • If a node is red, then both its children are black.
  • Every path from a given node to any of its descendant NIL nodes contains the same number of black nodes.

When an element is inserted into or removed from a red-black tree, the binary search tree is rebalanced to satisfy the red-black rules.

From Wikipedia's Red-Black Tree page, the following Red-Black tree was created by inserting the items [13,8,17,11,15,22,25,27,1,6]:


Red-Black Tree With Random Insertion

The following fairly well-balanced red-black tree was generated by inserting the numbers 1 to 32 in random order [15,14,20,3,7,10,11,16,18,2,4,5,8,19,1,9,12,6,17,13]:

The root node of the tree is 18, k represents the key numbers, p the parent, l the left node, r the right node. Nodes with l0 r0 are the leaves of the tree.


Red-Black Tree With Sequential Insertion

The following red-black tree was generated by inserting the numbers 1 to 32 in sequential order [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]:

A property of the red-black tree is that the path from the root to the farthest leaf is no more than twice as long as the path from the root to the nearest leaf. The shortest path has all black nodes and the longest path alternate between red and black nodes.

The shortest path is 4 levels deep: (8 black), (4 black), (2 black), (1 black).

The longest path is 8 levels deep: (8 black), (16 red), (20 black), (24 red), (28 black), (30 red), (31 black), (32 red). This is no more than twice as long as the shortest path.



Gas Cost

Following is a chart with the minimum, average and maximum gas cost for insertions and deletions from a Red-Black Tree. The result have been generated by insering random data in the first case, and sequential data in the second case.

Data and chart - docs/GasStatistics.xlsx. These statistics have been generated using the test/02_test2.sh script with the results logged in test/test2results.txt - the parameters NUMBEROFITEMS, BATCHSIZE were varied for the results with different number of items, and the insertItems = shuffle(insertItems); and removeItems = shuffle(removeItems); commented out for sequential insertions.


Random Insertion Gas Cost

The following table shows the minimum, average and maximum gas cost for the insertion of items in a random order and removal of items from a red-black tree:

Items Ins Min Ins Avg Ins Max Rem Min Rem Avg Rem Max
1 68,913 68,913 68,913 44,654 44,654 44,654
5 68,913 99,588 140,404 29,827 40,891 56,405
10 68,913 108,635 141,518 27,375 44,880 90,688
50 68,913 121,753 182,645 27,375 64,977 179,109
100 68,913 122,549 186,766 27,375 65,447 143,832
500 68,913 124,790 191,559 27,375 66,629 215,994
1,000 68,977 128,550 195,719 27,375 67,331 195,574
5,000 68,977 127,029 200,233 27,375 66,966 258,858
10,000 68,977 127,516 200,907 27,375 66,781 240,152

Note that the statistics above will change with each execution, as the data inserted is randomised.


Sequential Insertion Gas Cost

The following table shows the minimum, average and maximum gas cost for the insertion of items in a sequential order and removal of items from a red-black tree:

Items Ins Min Ins Avg Ins Max Rem Min Rem Avg Rem Max
1 68,913 68,913 68,913 44,654 44,654 44,654
5 68,913 107,761 141,129 29,827 44,883 80,922
10 68,913 116,896 149,938 29,827 53,457 104,650
50 68,913 138,234 158,844 29,827 61,485 151,002
100 68,913 143,145 163,297 29,827 63,540 174,178
500 68,913 149,417 191,134 29,859 66,239 219,978
1,000 68,913 150,878 208,360 29,859 66,774 243,154
5,000 68,913 153,219 242,813 29,859 67,276 304,485
10,000 68,913 154,017 260,040 29,859 67,352 327,661


History

Version Date Notes
v0.90-pre-release Feb 17 2019 Bug bounty added
v1.0 pre-release-a Mar 8 2019 Incorporated suggestions from Rob Hitchens


Bug Bounty Scope And Donations

Details of the bug bounty program for this project can be found at BokkyPooBah's Hall Of Fame And Bug Bounties. Please consider donating to support the bug bounty, and the development and maintenance of decentralised applications.

The scope of the bug bounty for this project follows:


Bounties awarded for this project:



Deployment

This library has been designed to be automatically compiled into your Ethereum Solidity contract or library, instead of having to deploy this library and then linking your contract or library to this library.



Questions And Answers

What would I use this library for?

Any smart contract where you need to maintain a sorted list of unsigned integers. One major use case is for this RBT library to maintain a decentralised exchange orderbook, sorted by price.


Why does this library only store unsigned integers and not any additional data?

This library was designed to be a simple component to be used within your smart contract project.

Store any additional data, e.g., key/value pairs, by adding the functionality into your smart contract. Sample code from contracts/TestBokkyPooBahsRedBlackTree.sol follows:

contract TestBokkyPooBahsRedBlackTree {
    using BokkyPooBahsRedBlackTreeLibrary for BokkyPooBahsRedBlackTreeLibrary.Tree;

    BokkyPooBahsRedBlackTreeLibrary.Tree tree;
    mapping(uint => uint) values;

    event Log(string where, uint key, uint value);

    ...

    function getNode(uint _key) public view returns (uint key, uint parent, uint left, uint right, bool red, uint value) {
        if (tree.exists(_key)) {
            BokkyPooBahsRedBlackTreeLibrary.Node memory node = tree.getNode(_key);
            (key, parent, left, right, red) = (_key, node.parent, node.left, node.right, node.red);
            value = values[_key];
        }
    }

    function insert(uint _key, uint _value) public {
        tree.insert(_key);
        values[_key] = _value;
        emit Log("insert", _key, _value);
    }
    function remove(uint _key) public {
        tree.remove(_key);
        emit Log("remove", _key, values[_key]);
        delete values[_key];
    }
}

Why can't I use 0 as a key?

This library has been configured with the EMPTY marker set to '0'. This can be set to non-0, but you will have to add some additional functionality - you can get an idea of the functionality you will need to add back from an older untested version of the library. Search for init(...) and the last line of getNode(...). Please test carefully!


Can duplicate keys be inserted?

No



Functions

See contracts/TestBokkyPooBahsRedBlackTree.sol (or the flattened version) for an example contract that uses this library.

Notes:

  • The function parameter Tree storage self has been omitted in the documentation below, as Solidity automatically injects the library data structure in place of this first parameter
  • There is a constant EMPTY that is set to 0 in the library source code by default
  • The insert(...) and remove(...) functions have internal visibility so it is easy to deploy your contract, as these function calls will be inlined. There may be cases where you may want to specify a public visibility so the is not inlined and duplicated in the deployment EVM code.

root

function root() internal view returns (uint _key);

Returns the root of the tree, or EMPTY is the tree is empty.


first

function first() internal view returns (uint _key);

Returns the smallest key in the tree.

Return Value Condition
{first key} Tree has at least one key
EMPTY Tree empty

last

function last() internal view returns (uint _key);

Returns the largest key in the tree.

Return Value Condition
{last key} Tree has at least one key
EMPTY Tree empty

next

function next(uint x) internal view returns (uint y);

Returns the next key in the tree with a value larger than x.

Return Value Condition
{next key} There exists a key with a value larger than the x key
EMPTY Tree empty
EMPTY x is not an existing key in the tree
EMPTY x is the only key in the tree
EMPTY x is the last key in the tree

prev

function prev(uint x) internal view returns (uint y);

Returns the previous key in the tree with a value smaller than x.

Return Value Condition
{prev key} There exists a key with a value smaller than the x key
EMPTY Tree empty
EMPTY x is not an existing key in the tree
EMPTY x is the only element in the tree
EMPTY x is the last element in the tree

exists

function exists(uint key) internal view returns (bool _exists);

Returns true if the key exists in the tree, false otherwise.

Return Value Condition
true key is an existing key in the tree
false Tree empty
false key is not an existing key in the tree

isEmpty

function isEmpty(uint key) internal pure returns (bool);

Returns true if the key exists in the tree, false otherwise.

Return Value Condition
true key is an existing key in the tree
false Tree empty
false key is not an existing key in the tree

getEmpty

function getEmpty() internal pure returns (uint);

Returns the value of the EMPTY variable


getNode

function getNode(uint key) internal view returns (uint _returnKey, uint _parent, uint _left, uint _right, bool _red);

Returns the node information if key exists in the tree. All uint values will be set to EMPTY if key does not exist in the tree.


insert

function insert(uint key) internal;

Insert the key key into the tree.

Transaction Condition
success key has been successfully inserted into the tree
failure key already exists in the tree

remove

function remove(uint key) internal;

Remove the key key from the tree.

Transaction Condition
success key has been successfully removed from the tree
failure key does not exist in the tree


Algorithm

The main Red-Black binary search tree algorithm is listed in Algorithms for Red Black Tree Operations (from CLRS text).

Note that this algorithm is designed to work with memory pointers to the node data. The rebalancing process after the removal of an item from the tree may result in a swapping of data values between nodes.

As the nodes are stored as elements in a Solidity mapping data structure, Iterative Algorithm for Red-Black Tree provides an alternative algorithm to perform this swapping. In particular, the function RB-Delete in the main Red-Black algorithm will need the line then key[z] := key[y] replaced with the alternative swapping algorithm.



Testing

  • Test random insertions and deletions of 1, 10, 100, 1000 and 10000 keys
  • Test the insert function, including inserting a duplicate key
  • Test the remove function, including removing a non-existent key
  • Test the view functions, including what happens when a non-existent key is passed
  • Test sequential insertions
  • Test repeated random insertions and deletions


References



Thanks to James Zaki and Solidified for the 3 minor issues they picked up at the Web3 Summit.

And thanks to Rob Hitchens for the suggestions.

Enjoy!

(c) BokkyPooBah / Bok Consulting Pty Ltd - Jan 18 2020. The MIT Licence.

More Repositories

1

BokkyPooBahsDateTimeLibrary

Gas-Efficient Solidity DateTime Library
Solidity
358
star
2

TokenTrader

TokenTrader And TokenSeller Decentralised Trustless Exchange Contract
Shell
146
star
3

WeenusTokenFaucet

An ERC20 token faucet on the Ethereum mainnet, layer 2s and testnets
Solidity
118
star
4

Tokens

Tokens, Tokens, Tokens
Solidity
107
star
5

BokkyPooBahsTokenTeleportationServiceSmartContract

BokkyPooBah's Token Teleportation Service Smart Contract
Shell
78
star
6

MagicalInternetMoney

Magical Internet Money - EVM chain crypto asset manager, with support for ERC-5564 Stealth Addresses and ERC-6538: Stealth Meta-Address Registry (WIP)
JavaScript
55
star
7

SolidityFlattener

A Simple-To-Install Solidity Flattener
Solidity
52
star
8

Nix

Nix - NFT Decentralised Exchange Smart Contracts
Solidity
42
star
9

BokkyPooBahsEthereumWorkshop

BokkyPooBah's Ethereum Workshop Workspace
29
star
10

BokkysCheatsheet

BokkyPooBah's CheatSheet
25
star
11

EthereumFoos

A Curated List Of Costly Ethereum Mistakes To Learn From (WIP)
24
star
12

chadex

Fully on-chain orderbook ERC-20/ERC-20 DEX using Red-Black Trees and Queues (WIP)
Solidity
24
star
13

DecentralisedFutureFundDAO

Decentralised Future Fund DAO
Solidity
23
star
14

umswap

umswap - "Like WETH, but for ERC-721s"
Solidity
15
star
15

MoonCatTools

Tools to manage your MoonCats. Note that there is a vulnerability in the smart contract if sellers accept bids, through front-running to alter the amount the seller receives!
Shell
14
star
16

Index

Index To BokkyPooBah's GitHub Repositories
13
star
17

Blockswap

Swapping of tokens from Waves to Ethereum and back
JavaScript
12
star
18

aenus

aenus advanced ENS and NFT utilities
JavaScript
11
star
19

SecurityToken

Security Token (WIP)
Solidity
11
star
20

ParityMultisigRecoveryReconciliation

Parity Multisig Vulnerability - White Hat Group Rescue Reconciliation
Shell
11
star
21

BeeeefRegistry

Beeeef Registry
Solidity
11
star
22

CryptoPunksData

CryptoPunks Historical Event Browser Dapp @ https://bokkypoobah.github.io/CryptoPunksData/
Solidity
10
star
23

FixedSupplyTokenFactory

Fixed Supply Token 👊 Contract + Factory - A Token Contract Vending Machine
JavaScript
10
star
24

Banananas

Small web3 dapp to browse banananas created by the Boring Banana Co (not associated). Web3 UI at https://bokkypoobah.github.io/Banananas/
JavaScript
10
star
25

NFTAnnuity

Get a loan on your CryptoPunk, ERC-721 & ERC-1177 NFTs
Solidity
9
star
26

DividendPayingTokenContract

Dividend Paying Token Contract - NOTE THAT THIS IS FOR AN EXERCISE!
Solidity
9
star
27

DEXWallet

Decentralised Exchange Wallet
Solidity
9
star
28

TheDAOVoter

Perl script to list and vote on The DAO proposals
Perl
8
star
29

LiveEduCrowdsaleContractAudit

LiveEdu Crowdsale Contract Audit
Shell
7
star
30

BancorCrowdsaleAnalysis

Bancor Crowdsale Analysis
Shell
7
star
31

ClubEth

ClubEth App Smart Contract
Solidity
7
star
32

NFTPostcardApp

BabyZombies ERC-1155 NFT
JavaScript
7
star
33

ZombieBabyOpenEdition

An ERC-1155 Non-Fungible Token contract based on OpenZeppelin v4.0.0
Solidity
7
star
34

EthereumForBunnies

Ethereum For Bunnies
7
star
35

ProxyFactoryTest

ProxyFactory contract for cheaper gas deployment of cloned contracts
Solidity
7
star
36

GetStartedWithDevelopingInEthereum

Getting Started In Ethereum, with an interactive ERC-20, ERC-721 and ERC-1155 token contract explorer dapp
Solidity
7
star
37

BestBastardGANPunks

SMOL WEB3 DAPP FOR LISTING OF BASTARD GAN PUNKS V2 (NOT AFFILIATED WITH THOSE LOSER BASTARDS https://bastardganpunks.club/). Web3 UI at https://bokkypoobah.github.io/BestBastardGANPunks/
JavaScript
6
star
38

ExploringCryptoPunksOnChain

Small Web3 UI to exploring CryptoPunks on-chain data.
JavaScript
5
star
39

NixApp

Nix App - NFT Decentralised Exchange Web3 UI
5
star
40

InvestFeedCrowdsaleAudit

InvestFeed Crowdsale Audit
Shell
5
star
41

TopSecrets

Recipe to build a TopSecrets read-only offline crypto device
HTML
5
star
42

ApprovalTool

Lightweight tool to manage your approvals for ERC-20, ERC-721 and ERC-1155 token contracts
5
star
43

TheDAOETCTokenBalance

Scripts and data to compute the balances of The DAO token holders on the Ethereum Classic chain
Shell
4
star
44

MemeCoinData

Tool to scrape data related to ERC-20 tokens
4
star
45

txs

Txs - Ethereum Transaction Reporter
4
star
46

BokkyPooBahsEth2.0ValidatorNodeRecipe

BokkyPooBahs eth 2.0 validator node cheat sheet
3
star
47

GnosisMultisigCli

Gnosis Multisig Command Line Interface - WIP
Perl
3
star
48

BokkyPooBahsHallOfFameAndBugBounties

BokkyPooBah's Hall Of Fame
3
star
49

MoonCatExplainer

MoonCatExplainer
JavaScript
3
star
50

TheDAOData

Data related to The DAO
Shell
3
star
51

TestToadz

TestToadz - ERC-721 Testnet Faucets
Solidity
3
star
52

OpenANXTokenOld

OpenANX Decentralised Exchange Token Sale Smart Contract - moved to https://github.com/openanx/OpenANXToken
Shell
3
star
53

FindGNTTokenTrader

Find Golem Network Token (GNT) TokenTrader Information
Shell
3
star
54

MoonCatToolsApp

MoonCat Tools App (WIP)
2
star
55

ensutils

ENS Utilities
2
star
56

EthereumWalletMultisigTest

Ethereum Wallet Multisig Test
2
star
57

CryptoPosition4MacExcel

Crypto Position For Excel On The Mac
2
star
58

EthereumNetworkAttackData

Data relating to the Ethereum network attacks between Sep 18 2016 and Oct 20 2016
Perl
2
star
59

MoonCatListing

Shell
2
star
60

RAREPeperiumToken

RARE Peperium Token
Shell
2
star
61

MusteringMoonCats

Mustering MoonCats
2
star
62

EtherVendingMachine

Ethereum Vending Machine
2
star
63

Workshop162

Workshop #162 Buidling - Unstoppable Dapps From 0 To Go - ETH ❤️ ENS ❤️ IPFS #1
JavaScript
2
star
64

TokenCardICOAnalysis

TokenCard ICO Analysis
Shell
2
star
65

LOST

LOST - Your Personal NFT Organiser And Gem Explorer
JavaScript
2
star
66

ProofOfPepesInfo

Some info on the Proof of Pepes NFT Collection (not affiliated)
2
star
67

HashDemons

HashDemons
JavaScript
2
star
68

BokkyPooBahsEtherRefundablePrize

BokkyPooBah's Ether Refundable Prize (BERP)
Shell
2
star
69

VictoriasSecrets

Royalty Class Online/Offline Wallet For EVM Chains (WIP)
2
star
70

ConsenSysMultiSigWalletAudit

ConsenSys/Gnosis MultiSig Wallet Audit (WIP, Bug Bounty Available)
JavaScript
2
star
71

AkropolisSaleContractAudit

Audit of https://github.com/akropolisio/akropolis-sale (fork link now broken)
JavaScript
2
star
72

TokenExplorer

ERC-20, ERC-721 and ERC-1155 Token Explorer
2
star
73

BestENSNames

ENS Portfolio Manager (WIP)
2
star
74

SentinelChainTokenContractAudit

Sentinel Chain Token Contract Audit
JavaScript
1
star
75

BATICOAnalysis

BAT ICO Analysis
Shell
1
star
76

CryptoDickButtsOnChain

CryptoDickButtsOnChain
Solidity
1
star
77

TheDAOETCDrains

Scripts and data related to the draining of The DAO on the Ethereum ETC chain
Shell
1
star
78

TheDAORefundsCalcs

Some calculations relating to The DAO Refunds
Shell
1
star
79

OAXSwimGatewayStableCoinContractAudit

JavaScript
1
star
80

MobileGoToken

MobileGo Token
1
star
81

FunFairCrowdsaleContractAudit

FunFair Crowdsale Contract Audit
Shell
1
star
82

PrivatixCrowdsaleContractAudit

Privatix Crowdsale Contract Audit
JavaScript
1
star
83

DaoCasinoTokenSaleContractAudit

Dao.Casino Crowdsale Contract
Shell
1
star
84

Dexy

Decentralised Exchange (Work in progress)
JavaScript
1
star
85

TokenToolz

Token Toolz
Solidity
1
star
86

AuctionFactory

Auction Factory
Solidity
1
star
87

Registry

Registry
Solidity
1
star
88

MyFinalFormInfo

My Final Form (not associated) Data
Solidity
1
star
89

AHistoryOfPunksInScreenshots

A History Of Punks In Screenshots
1
star
90

ENSAuctionToken

ENS Auction Token
1
star
91

GlicPixxxSurfer

GLICPIXXXVER002 Surfer
1
star
92

BestLunarToken

ZOMBIE BGANPunks LunarToken Advanced Occupation Base 135. Not affiliated.
Solidity
1
star
93

onchainmyheart

onchainmy❤
Solidity
1
star
94

FxxxLandRush

Fxxx Land Rush
Solidity
1
star
95

HoprTokenAudit

HOPR ERC-777 Token Contract Audit
Solidity
1
star
96

NFTSpreads

NFT Spreads
1
star
97

BGANPUNKToolsApp

Bastard GAN Punks Tools App
JavaScript
1
star
98

chadmode

chadmode
1
star