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

Add forking detection to TBC #101

Merged
merged 84 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
93f1f15
Add testing framework
marcopeereboom Apr 23, 2024
fecd8f5
Somewhat working chain
marcopeereboom Apr 23, 2024
bfc89ee
Code is not ready to remove threading
marcopeereboom Apr 23, 2024
0f08366
Implent get data
marcopeereboom Apr 23, 2024
a9f963b
be a bit less verbose
marcopeereboom Apr 23, 2024
1f21191
Use normal cache element count
marcopeereboom Apr 23, 2024
4b0a19f
And have a pass condition
marcopeereboom Apr 23, 2024
9be6fc4
check balance
marcopeereboom Apr 23, 2024
9699f9e
go vet
marcopeereboom Apr 23, 2024
377d5ed
go mod tidy
marcopeereboom Apr 23, 2024
b536fc7
no ulimit check during tests
ClaytonNorthey92 Apr 26, 2024
d348a53
Push before rebase
marcopeereboom May 1, 2024
6bef442
Fix possible race conditions in tbcfork_test
joshuasing May 1, 2024
89fc056
Tidy up parts of tbcfork_test
joshuasing May 1, 2024
cfc18d1
Add forking support fake btc server
marcopeereboom May 3, 2024
d300762
create for and advance both heads
marcopeereboom May 6, 2024
e903040
We need to start panicing on fork situations
marcopeereboom May 6, 2024
24f29fe
add some comments to mark special spots
marcopeereboom May 6, 2024
8c6491c
added test case configuration for bitcoind inclusion in tests
ClaytonNorthey92 May 1, 2024
64387de
add comment
ClaytonNorthey92 May 6, 2024
60487af
removed unused val
ClaytonNorthey92 May 6, 2024
10be788
Encode/decode difficulty in blockheader
marcopeereboom May 7, 2024
9df26a8
imperitive forking in tests
ClaytonNorthey92 May 7, 2024
571cecb
no syncBlocks anymore since we generate them with current timestamps
ClaytonNorthey92 May 7, 2024
7b7a62f
comment out likely unused test
ClaytonNorthey92 May 8, 2024
c3be11c
tbc: fix loop unconditionally exited after one interation (SA4004)
joshuasing May 8, 2024
8e8ff89
Add panic to catch unsupported fork
joshuasing May 8, 2024
a14386b
removed unused test data
ClaytonNorthey92 May 8, 2024
21e3b2e
fixup rebase drama, need to reenable TestLevelDB
marcopeereboom May 9, 2024
681b4f5
tbc: use time.Since instead of time.Now().Sub (S1012)
joshuasing May 9, 2024
9ea88cd
finish fork scenario 1
ClaytonNorthey92 May 9, 2024
0123e74
added more test cases
ClaytonNorthey92 May 9, 2024
85b2b52
NewBuffer works in surprising ways
marcopeereboom May 10, 2024
59e2387
Detect forks when downloading block headers
marcopeereboom May 10, 2024
7692bfe
XXX
marcopeereboom May 10, 2024
13bed9a
deal with extending forks
marcopeereboom May 13, 2024
98fec1a
First attempt at making BlockHeadersBest singular
marcopeereboom May 13, 2024
132bee3
tbcapi: update for BlockHeadersBest -> BlockHeaderBest
joshuasing May 13, 2024
d453a3e
Add type to detect how block headers were inserted
marcopeereboom May 14, 2024
8b06c20
Reap peers if not synced or sending crap block headers
marcopeereboom May 14, 2024
02b10d1
Simplify and return hint to caller how to handle forks; caller now al…
marcopeereboom May 15, 2024
03e641c
Remove debug panic and annotate code
marcopeereboom May 16, 2024
49a9eaf
Moar testing
marcopeereboom May 16, 2024
3d95477
tbcd: fix unnecessary use of fmt.Sprintf (S1039)
joshuasing May 17, 2024
b6cfd75
Yay working forks
marcopeereboom May 27, 2024
577b087
tbcd: fix only first constant having explicit type (SA9004)
joshuasing May 29, 2024
526196f
tbcd/level: use element from range, fix empty if statement
joshuasing May 29, 2024
ddadb52
lower limits because latest ubuntu update
marcopeereboom May 31, 2024
5ab84cb
be less loud
marcopeereboom May 31, 2024
1b1666c
skip test that causes an issue due to port bindings
marcopeereboom May 31, 2024
3905bf9
Remove cached last block header
marcopeereboom May 31, 2024
b9fc457
skipping balance tests for forking
ClaytonNorthey92 Jun 3, 2024
4b1730a
tbc: BlockHeadersBest -> BlockHeaderBest in rpc_test
joshuasing Jun 3, 2024
e8fb55f
tbcapi: best block headers -> best block header
joshuasing Jun 3, 2024
3572f89
Work around most fork situations
marcopeereboom Jun 4, 2024
2f91da5
mostly working but ugly interleaved start/stop downloading/indexing
marcopeereboom Jun 5, 2024
3de9272
Make peers wanted a setting and abort indexing a bit earlier
marcopeereboom Jun 10, 2024
bcf8d7c
Ok this seems to work
marcopeereboom Jun 11, 2024
4a85ab2
remove clipped for now and only index if enabled
marcopeereboom Jun 11, 2024
1e851c3
Fix broken test
marcopeereboom Jun 12, 2024
c04cde3
Make fork choices more explicit and rename BlockHeaderInsert -> Block…
marcopeereboom Jun 12, 2024
8ea7128
make PeersWanted a runtime setting
marcopeereboom Jun 12, 2024
7238909
Return canonical and last inserted block header in BlockHeaderInsert …
marcopeereboom Jun 12, 2024
04a0de2
Rename 'last' to canonical/best
marcopeereboom Jun 12, 2024
8dc8c0f
remove unused h2b80 function
marcopeereboom Jun 13, 2024
ae07d3f
Remove unused headerTime headerHash functions
marcopeereboom Jun 13, 2024
98d42e1
Remove unsued structure blockPeer
marcopeereboom Jun 13, 2024
e99ed83
Test err and use Error instead of Fatal
marcopeereboom Jun 13, 2024
24654a4
Remove unused function getEndpointWithRetries
marcopeereboom Jun 13, 2024
9331e3f
Remove unused function submitBlock
marcopeereboom Jun 13, 2024
a3ee96e
Unexport map with fork type names
marcopeereboom Jun 13, 2024
78e9040
deleted unused test variable, increased for loop time sleep
ClaytonNorthey92 Jun 13, 2024
c63ba97
Update database/tbcd/database.go
marcopeereboom Jun 14, 2024
49a08ca
Update database/tbcd/database.go
marcopeereboom Jun 14, 2024
a4b70c2
Make Infof into debugf
marcopeereboom Jun 14, 2024
6e80922
Remove loud infof
marcopeereboom Jun 14, 2024
d0260f9
Move loud fork proclamation to debugf
marcopeereboom Jun 14, 2024
55209f4
Remove leftover debug
marcopeereboom Jun 14, 2024
c2e4473
Update service/tbc/tbc_test.go
marcopeereboom Jun 14, 2024
afd78ca
tbc: nest short err assignments
joshuasing Jun 14, 2024
9af7117
tbcd/level: nest short err assignments
joshuasing Jun 14, 2024
72200d9
tbc: use errors.Is for error comparison
joshuasing Jun 14, 2024
b65b8d3
tbc/crawler: nest short err assignments
joshuasing Jun 14, 2024
16b1ade
tbcd/level: deduplicate cbh/lbh assignment
joshuasing Jun 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 25 additions & 29 deletions api/tbcapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ This document provides details on the RPC protocol and available commands for th
* [📥 Response](#-response-1)
* [Payload](#payload-3)
* [Example Response](#example-response-1)
* [👉 Best Block Headers](#-best-block-headers)
* [👉 Best Block Header](#-best-block-header)
* [🗂 Raw Data](#-raw-data-1)
* [📤 Request](#-request-2)
* [Example Request](#example-request-2)
Expand Down Expand Up @@ -330,16 +330,16 @@ Response for a request with **id** `68656d69` and **height** `43111`:

---

## 👉 Best Block Headers
## 👉 Best Block Header

Retrieve the best block headers.

### 🗂 Raw Data

| Type | `command` value |
|----------|------------------------------------------|
| Request | `tbcapi-block-headers-best-raw-request` |
| Response | `tbcapi-block-headers-best-raw-response` |
| Type | `command` value |
|----------|-----------------------------------------|
| Request | `tbcapi-block-header-best-raw-request` |
| Response | `tbcapi-block-header-best-raw-response` |

#### 📤 Request

Expand All @@ -350,7 +350,7 @@ Retrieve the best block headers:
```json
{
"header": {
"command": "tbcapi-block-headers-best-raw-request",
"command": "tbcapi-block-header-best-raw-request",
"id": "68656d69"
}
}
Expand All @@ -361,7 +361,7 @@ Retrieve the best block headers:
##### Payload

- **`height`**: The best-known height.
- **`block_headers`**: An array of the best-known block headers encoded as hexadecimal strings.
- **`block_header`**: The best-known block header encoded as a hexadecimal string.

##### Example Response

Expand All @@ -370,24 +370,22 @@ Response for a request with **id** `68656d69` and **best height** `2182000`:
```json
{
"header": {
"command": "tbcapi-block-headers-best-raw-response",
"command": "tbcapi-block-header-best-raw-response",
"id": "68656d69"
},
"payload": {
"height": 2182000,
"block_headers": [
"0420002075089ac1ab1cab70cf6e6b774a86703a8d7127c0ebed1d3dfa2c00000000000086105509ec4a79457a400451290ad2a019fec4c76b47512623f1bb17a0ced76f38d82662bef4001b07d86700"
]
"block_header": "0420002075089ac1ab1cab70cf6e6b774a86703a8d7127c0ebed1d3dfa2c00000000000086105509ec4a79457a400451290ad2a019fec4c76b47512623f1bb17a0ced76f38d82662bef4001b07d86700"
}
}
```

#### 🗂 Serialized Data

| Type | `command` value |
|----------|--------------------------------------|
| Request | `tbcapi-block-headers-best-request` |
| Response | `tbcapi-block-headers-best-response` |
| Type | `command` value |
|----------|-------------------------------------|
| Request | `tbcapi-block-header-best-request` |
| Response | `tbcapi-block-header-best-response` |

#### 📤 Request

Expand All @@ -398,7 +396,7 @@ Retrieve the best block headers:
```json
{
"header": {
"command": "tbcapi-block-headers-best-request",
"command": "tbcapi-block-header-best-request",
"id": "68656d69"
}
}
Expand All @@ -409,7 +407,7 @@ Retrieve the best block headers:
##### Payload

- **`height`**: The best-known height.
- **`block_headers`**: An array of best-known [block headers](#block-header).
- **`block_header`**: The best-known [block header](#block-header).

##### Example Response

Expand All @@ -418,21 +416,19 @@ Response for a request with **id** `68656d69` and **height** `2587400`:
```json
{
"header": {
"command": "tbcapi-block-headers-best-response",
"command": "tbcapi-block-header-best-response",
"id": "68656d69"
},
"payload": {
"height": 2587400,
"block_headers": [
{
"version": 536887296,
"prev_hash": "000000000000002bbbbec8f126dc76a82109d898383bca5013a2386c8675ce34",
"merkle_root": "b9d74efdafb5436330b47478b2df28251057da5a9bc11c5509410950253d4f0e",
"timestamp": 1713461092,
"bits": "192e17d5",
"nonce": 3365605040
}
]
"block_header": {
"version": 536887296,
"prev_hash": "000000000000002bbbbec8f126dc76a82109d898383bca5013a2386c8675ce34",
"merkle_root": "b9d74efdafb5436330b47478b2df28251057da5a9bc11c5509410950253d4f0e",
"timestamp": 1713461092,
"bits": "192e17d5",
"nonce": 3365605040
}
}
}
```
Expand Down
36 changes: 18 additions & 18 deletions api/tbcapi/tbcapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ const (
CmdBlockHeadersByHeightRequest = "tbcapi-block-headers-by-height-request"
CmdBlockHeadersByHeightResponse = "tbcapi-block-headers-by-height-response"

CmdBlockHeadersBestRawRequest = "tbcapi-block-headers-best-raw-request"
CmdBlockHeadersBestRawResponse = "tbcapi-block-headers-best-raw-response"
CmdBlockHeaderBestRawRequest = "tbcapi-block-header-best-raw-request"
CmdBlockHeaderBestRawResponse = "tbcapi-block-header-best-raw-response"

CmdBlockHeadersBestRequest = "tbcapi-block-headers-best-request"
CmdBlockHeadersBestResponse = "tbcapi-block-headers-best-response"
CmdBlockHeaderBestRequest = "tbcapi-block-header-best-request"
CmdBlockHeaderBestResponse = "tbcapi-block-header-best-response"

CmdBalanceByAddressRequest = "tbcapi-balance-by-address-request"
CmdBalanceByAddressResponse = "tbcapi-balance-by-address-response"
Expand Down Expand Up @@ -88,20 +88,20 @@ type BlockHeadersByHeightResponse struct {
Error *protocol.Error `json:"error,omitempty"`
}

type BlockHeadersBestRawRequest struct{}
type BlockHeaderBestRawRequest struct{}

type BlockHeadersBestRawResponse struct {
Height uint64 `json:"height"`
BlockHeaders []api.ByteSlice `json:"block_headers"`
Error *protocol.Error `json:"error,omitempty"`
type BlockHeaderBestRawResponse struct {
Height uint64 `json:"height"`
BlockHeader api.ByteSlice `json:"block_header"`
Error *protocol.Error `json:"error,omitempty"`
}

type BlockHeadersBestRequest struct{}
type BlockHeaderBestRequest struct{}

type BlockHeadersBestResponse struct {
Height uint64 `json:"height"`
BlockHeaders []*BlockHeader `json:"block_headers"`
Error *protocol.Error `json:"error,omitempty"`
type BlockHeaderBestResponse struct {
Height uint64 `json:"height"`
BlockHeader *BlockHeader `json:"block_header"`
Error *protocol.Error `json:"error,omitempty"`
}

type BalanceByAddressRequest struct {
Expand Down Expand Up @@ -192,10 +192,10 @@ var commands = map[protocol.Command]reflect.Type{
CmdBlockHeadersByHeightRawResponse: reflect.TypeOf(BlockHeadersByHeightRawResponse{}),
CmdBlockHeadersByHeightRequest: reflect.TypeOf(BlockHeadersByHeightRequest{}),
CmdBlockHeadersByHeightResponse: reflect.TypeOf(BlockHeadersByHeightResponse{}),
CmdBlockHeadersBestRawRequest: reflect.TypeOf(BlockHeadersBestRawRequest{}),
CmdBlockHeadersBestRawResponse: reflect.TypeOf(BlockHeadersBestRawResponse{}),
CmdBlockHeadersBestRequest: reflect.TypeOf(BlockHeadersBestRequest{}),
CmdBlockHeadersBestResponse: reflect.TypeOf(BlockHeadersBestResponse{}),
CmdBlockHeaderBestRawRequest: reflect.TypeOf(BlockHeaderBestRawRequest{}),
CmdBlockHeaderBestRawResponse: reflect.TypeOf(BlockHeaderBestRawResponse{}),
CmdBlockHeaderBestRequest: reflect.TypeOf(BlockHeaderBestRequest{}),
CmdBlockHeaderBestResponse: reflect.TypeOf(BlockHeaderBestResponse{}),
CmdBalanceByAddressRequest: reflect.TypeOf(BalanceByAddressRequest{}),
CmdBalanceByAddressResponse: reflect.TypeOf(BalanceByAddressResponse{}),
CmdUtxosByAddressRawRequest: reflect.TypeOf(UtxosByAddressRawRequest{}),
Expand Down
10 changes: 6 additions & 4 deletions cmd/hemictl/hemictl.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,16 @@ func tbcdb() error {
fmt.Printf("height: %v\n", bh.Height)

case "blockheadersbest":
bhs, err := s.DB().BlockHeadersBest(ctx)
bhb, err := s.DB().BlockHeaderBest(ctx)
if err != nil {
return fmt.Errorf("block headers best: %w", err)
}
for k := range bhs {
fmt.Printf("hash (%v): %v\n", k, bhs[k])
fmt.Printf("height (%v): %v\n", k, bhs[k].Height)
hash, err := chainhash.NewHash(bhb.Hash)
if err != nil {
return fmt.Errorf("block headers best chainhash: %w", err)
}
fmt.Printf("hash : %v\n", hash)
fmt.Printf("height: %v\n", bhb.Height)

case "blockheadersbyheight":
height := args["height"]
Expand Down
6 changes: 6 additions & 0 deletions cmd/tbcd/tbcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ var (
Help: "bitcoin network; mainnet or testnet3",
Print: config.PrintAll,
},
"TBC_PEERS_WANTED": config.Config{
Value: &cfg.PeersWanted,
DefaultValue: 64,
Help: "number of wanted p2p peers",
Print: config.PrintAll,
},
"TBC_PROMETHEUS_ADDRESS": config.Config{
Value: &cfg.PrometheusListenAddress,
DefaultValue: "",
Expand Down
39 changes: 32 additions & 7 deletions database/tbcd/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"math/big"
"time"

"github.com/btcsuite/btcd/chaincfg/chainhash"
Expand All @@ -19,6 +20,26 @@ import (
"github.com/hemilabs/heminetwork/database"
)

type InsertType int

const (
ITInvalid InsertType = 0 // Invalid insert
ITChainExtend InsertType = 1 // Normal insert, does not require further action.
ITChainFork InsertType = 2 // Chain forked, unwind and rewind indexes.
ITForkExtend InsertType = 3 // Extended a fork, does not require further action.
)

var itStrings = map[InsertType]string{
ITInvalid: "invalid",
ITChainExtend: "chain extended",
ITChainFork: "chain forked",
ITForkExtend: "fork extended",
}

func (it InsertType) String() string {
return itStrings[it]
}

type Database interface {
database.Database

Expand All @@ -28,10 +49,13 @@ type Database interface {
MetadataPut(ctx context.Context, key, value []byte) error

// Block header
BlockHeaderBest(ctx context.Context) (*BlockHeader, error) // return canonical
BlockHeaderByHash(ctx context.Context, hash []byte) (*BlockHeader, error)
BlockHeadersBest(ctx context.Context) ([]BlockHeader, error)
BlockHeaderGenesisInsert(ctx context.Context, bh [80]byte) error

// Block headers
BlockHeadersByHeight(ctx context.Context, height uint64) ([]BlockHeader, error)
BlockHeadersInsert(ctx context.Context, bhs []BlockHeader) error
BlockHeadersInsert(ctx context.Context, bhs [][80]byte) (InsertType, *BlockHeader, *BlockHeader, error)

// Block
BlocksMissing(ctx context.Context, count int) ([]BlockIdentifier, error)
Expand All @@ -58,12 +82,13 @@ type Database interface {
UtxosByScriptHash(ctx context.Context, sh ScriptHash, start uint64, count uint64) ([]Utxo, error)
}

// BlockHeader contains the first 80 raw bytes of a bitcoin block and its
// location information (hash+height).
// BlockHeader contains the first 80 raw bytes of a bitcoin block plus its
// location information (hash+height) and the cumulative difficulty.
type BlockHeader struct {
Hash database.ByteArray
Height uint64
Header database.ByteArray
Hash database.ByteArray
Height uint64
Header database.ByteArray
Difficulty big.Int
}

func (bh BlockHeader) String() string {
Expand Down
Loading
Loading