mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-09-14 21:40:11 +00:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6db296b98b | ||
![]() |
05d1671f3a | ||
![]() |
ce2758e825 | ||
![]() |
09545b94b7 |
4
.github/workflows/SetPageFileSize.ps1
vendored
4
.github/workflows/SetPageFileSize.ps1
vendored
@ -11,8 +11,8 @@
|
|||||||
#>
|
#>
|
||||||
|
|
||||||
param(
|
param(
|
||||||
[System.UInt64] $MinimumSize = 16gb ,
|
[System.UInt64] $MinimumSize = 8gb ,
|
||||||
[System.UInt64] $MaximumSize = 16gb ,
|
[System.UInt64] $MaximumSize = 8gb ,
|
||||||
[System.String] $DiskRoot = "D:"
|
[System.String] $DiskRoot = "D:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
69
.github/workflows/deploy.yaml
vendored
69
.github/workflows/deploy.yaml
vendored
@ -1,69 +0,0 @@
|
|||||||
name: Build and upload assets
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
||||||
name: Building, ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Fix CRLF on Windows
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: git config --global core.autocrlf false
|
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: 1.21
|
|
||||||
|
|
||||||
- name: Build on Linux
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
# `-extldflags=-static` - means static link everything,
|
|
||||||
# `-tags netgo,osusergo` means use pure go replacements for "os/user" and "net"
|
|
||||||
# `-s -w` strips the binary to produce smaller size binaries
|
|
||||||
run: |
|
|
||||||
go build -v -ldflags="-s -w -extldflags=-static" -tags netgo,osusergo -o ./bin/ ./cmd/...
|
|
||||||
archive="bin/kaspad-${{ github.event.release.tag_name }}-linux.zip"
|
|
||||||
asset_name="kaspad-${{ github.event.release.tag_name }}-linux.zip"
|
|
||||||
zip -r "${archive}" ./bin/*
|
|
||||||
echo "archive=${archive}" >> $GITHUB_ENV
|
|
||||||
echo "asset_name=${asset_name}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Build on Windows
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
go build -v -ldflags="-s -w" -o bin/ ./cmd/...
|
|
||||||
archive="bin/kaspad-${{ github.event.release.tag_name }}-win64.zip"
|
|
||||||
asset_name="kaspad-${{ github.event.release.tag_name }}-win64.zip"
|
|
||||||
powershell "Compress-Archive bin/* \"${archive}\""
|
|
||||||
echo "archive=${archive}" >> $GITHUB_ENV
|
|
||||||
echo "asset_name=${asset_name}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Build on MacOS
|
|
||||||
if: runner.os == 'macOS'
|
|
||||||
run: |
|
|
||||||
go build -v -ldflags="-s -w" -o ./bin/ ./cmd/...
|
|
||||||
archive="bin/kaspad-${{ github.event.release.tag_name }}-osx.zip"
|
|
||||||
asset_name="kaspad-${{ github.event.release.tag_name }}-osx.zip"
|
|
||||||
zip -r "${archive}" ./bin/*
|
|
||||||
echo "archive=${archive}" >> $GITHUB_ENV
|
|
||||||
echo "asset_name=${asset_name}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Upload release asset
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: "./${{ env.archive }}"
|
|
||||||
asset_name: "${{ env.asset_name }}"
|
|
||||||
asset_content_type: application/zip
|
|
69
.github/workflows/go.yml
vendored
Normal file
69
.github/workflows/go.yml
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
name: Go
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
# edtited - "title, body, or the base branch of the PR is modified"
|
||||||
|
# synchronize - "commit(s) pushed to the pull request"
|
||||||
|
types: [opened, synchronize, edited, reopened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-16.04, macos-10.15 ]
|
||||||
|
name: Testing on on ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Fix windows CRLF
|
||||||
|
run: git config --global core.autocrlf false
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# We need to increase the page size because the tests run out of memory on github CI windows.
|
||||||
|
# Use the powershell script from this github action: https://github.com/al-cheb/configure-pagefile-action/blob/master/scripts/SetPageFileSize.ps1
|
||||||
|
# MIT License (MIT) Copyright (c) 2020 Maxim Lobanov and contributors
|
||||||
|
- name: Increase page size on windows
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
shell: powershell
|
||||||
|
run: powershell -command .\.github\workflows\SetPageFileSize.ps1
|
||||||
|
|
||||||
|
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.15
|
||||||
|
|
||||||
|
|
||||||
|
# Source: https://github.com/actions/cache/blob/main/examples.md#go---modules
|
||||||
|
- name: Go Cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
shell: bash
|
||||||
|
run: ./build_and_test.sh
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
name: Produce code coverage
|
||||||
|
steps:
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.15
|
||||||
|
|
||||||
|
- name: Create coverage file
|
||||||
|
run: go test -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./...
|
||||||
|
|
||||||
|
- name: Upload coverage file
|
||||||
|
run: bash <(curl -s https://codecov.io/bash)
|
49
.github/workflows/race.yaml
vendored
49
.github/workflows/race.yaml
vendored
@ -1,49 +0,0 @@
|
|||||||
name: Race
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
race_test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
branch: [master, latest]
|
|
||||||
name: Race detection on ${{ matrix.branch }}
|
|
||||||
steps:
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: 1.23
|
|
||||||
|
|
||||||
- name: Set scheduled branch name
|
|
||||||
shell: bash
|
|
||||||
if: github.event_name == 'schedule'
|
|
||||||
run: |
|
|
||||||
if [ "${{ matrix.branch }}" == "master" ]; then
|
|
||||||
echo "run_on=master" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
if [ "${{ matrix.branch }}" == "latest" ]; then
|
|
||||||
branch=$(git branch -r | grep 'v\([0-9]\+\.\)\([0-9]\+\.\)\([0-9]\+\)-dev' | sort -Vr | head -1 | xargs)
|
|
||||||
echo "run_on=${branch}" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Set manual branch name
|
|
||||||
shell: bash
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: echo "run_on=${{ github.ref }}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Test with race detector
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
git checkout "${{ env.run_on }}"
|
|
||||||
git status
|
|
||||||
go test -timeout 20m -race ./...
|
|
92
.github/workflows/tests.yaml
vendored
92
.github/workflows/tests.yaml
vendored
@ -1,92 +0,0 @@
|
|||||||
name: Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
# edtited - because base branch can be modified
|
|
||||||
# synchronize - update commits on PR
|
|
||||||
types: [opened, synchronize, edited]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, macos-latest]
|
|
||||||
name: Tests, ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Fix CRLF on Windows
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: git config --global core.autocrlf false
|
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# Increase the pagefile size on Windows to aviod running out of memory
|
|
||||||
- name: Increase pagefile size on Windows
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: powershell -command .github\workflows\SetPageFileSize.ps1
|
|
||||||
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: 1.23
|
|
||||||
|
|
||||||
# Source: https://github.com/actions/cache/blob/main/examples.md#go---modules
|
|
||||||
- name: Go Cache
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/go/pkg/mod
|
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-go-
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
shell: bash
|
|
||||||
run: ./build_and_test.sh -v
|
|
||||||
|
|
||||||
stability-test-fast:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Fast stability tests, ${{ github.head_ref }}
|
|
||||||
steps:
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: 1.23
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Install kaspad
|
|
||||||
run: go install ./...
|
|
||||||
|
|
||||||
- name: Install golint
|
|
||||||
run: go get -u golang.org/x/lint/golint
|
|
||||||
|
|
||||||
- name: Run fast stability tests
|
|
||||||
working-directory: stability-tests
|
|
||||||
run: ./install_and_test.sh
|
|
||||||
|
|
||||||
coverage:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Produce code coverage
|
|
||||||
steps:
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: 1.23
|
|
||||||
|
|
||||||
- name: Delete the stability tests from coverage
|
|
||||||
run: rm -r stability-tests
|
|
||||||
|
|
||||||
- name: Create coverage file
|
|
||||||
run: go test -v -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./...
|
|
||||||
|
|
||||||
- name: Upload coverage file
|
|
||||||
run: bash <(curl -s https://codecov.io/bash)
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -53,7 +53,6 @@ _testmain.go
|
|||||||
debug
|
debug
|
||||||
debug.test
|
debug.test
|
||||||
__debug_bin
|
__debug_bin
|
||||||
*__debug_*
|
|
||||||
|
|
||||||
# CI
|
# CI
|
||||||
version.txt
|
version.txt
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment include:
|
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
|
||||||
* Being respectful of differing viewpoints and experiences
|
|
||||||
* Gracefully accepting constructive criticism
|
|
||||||
* Focusing on what is best for the community
|
|
||||||
* Showing empathy towards other community members
|
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
||||||
|
|
||||||
## Our Responsibilities
|
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainers on this [Google form][gform]. The project maintainers will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
|
||||||
|
|
||||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
|
||||||
|
|
||||||
[gform]: https://forms.gle/dnKXMJL7VxdUjt3x5
|
|
||||||
[homepage]: http://contributor-covenant.org
|
|
||||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -12,7 +12,8 @@ If you want to make a big change it's better to discuss it first by opening an i
|
|||||||
|
|
||||||
## Pull Request process
|
## Pull Request process
|
||||||
|
|
||||||
Any pull request should be opened against the development branch `dev`.
|
Any pull request should be opened against the development branch of the target version. The development branch format is
|
||||||
|
as follows: `vx.y.z-dev`, for example: `v0.8.5-dev`.
|
||||||
|
|
||||||
All pull requests should pass the checks written in `build_and_test.sh`, so it's recommended to run this script before
|
All pull requests should pass the checks written in `build_and_test.sh`, so it's recommended to run this script before
|
||||||
submitting your PR.
|
submitting your PR.
|
23
README.md
23
README.md
@ -1,15 +1,16 @@
|
|||||||
# DEPRECATED
|
|
||||||
|
|
||||||
The full node reference implementation was [rewritten in Rust](https://github.com/kaspanet/rusty-kaspa), as a result, the Go implementation is now deprecated.
|
Kaspad
|
||||||
|
====
|
||||||
PLEASE NOTE: Any pull requests or issues that will be opened in this repository will be closed without treatment, except for issues or pull requests related to the kaspawallet, which remains maintained. In any other case, please use the [Rust implementation](https://github.com/kaspanet/rusty-kaspa) instead.
|
Warning: This is pre-alpha software. There's no guarantee anything works.
|
||||||
|
====
|
||||||
# Kaspad
|
|
||||||
|
|
||||||
[](https://choosealicense.com/licenses/isc/)
|
[](https://choosealicense.com/licenses/isc/)
|
||||||
[](http://godoc.org/github.com/kaspanet/kaspad)
|
[](http://godoc.org/github.com/kaspanet/kaspad)
|
||||||
|
|
||||||
Kaspad was the reference full node Kaspa implementation written in Go (golang).
|
Kaspad is the reference full node Kaspa implementation written in Go (golang).
|
||||||
|
|
||||||
|
This project is currently under active development and is in a pre-Alpha state.
|
||||||
|
Some things still don't work and APIs are far from finalized. The code is provided for reference only.
|
||||||
|
|
||||||
## What is kaspa
|
## What is kaspa
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ Kaspa is an attempt at a proof-of-work cryptocurrency with instant confirmations
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
Go 1.23 or later.
|
Go 1.15 or later.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ $ go install . ./cmd/...
|
|||||||
not already add the bin directory to your system path during Go installation,
|
not already add the bin directory to your system path during Go installation,
|
||||||
you are encouraged to do so now.
|
you are encouraged to do so now.
|
||||||
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
Kaspad has several configuration options available to tweak how it runs, but all
|
Kaspad has several configuration options available to tweak how it runs, but all
|
||||||
@ -54,16 +56,13 @@ $ kaspad
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Discord
|
## Discord
|
||||||
|
Join our discord server using the following link: https://discord.gg/WmGhhzk
|
||||||
Join our discord server using the following link: https://discord.gg/YNYnNN5Pf2
|
|
||||||
|
|
||||||
## Issue Tracker
|
## Issue Tracker
|
||||||
|
|
||||||
The [integrated github issue tracker](https://github.com/kaspanet/kaspad/issues)
|
The [integrated github issue tracker](https://github.com/kaspanet/kaspad/issues)
|
||||||
is used for this project.
|
is used for this project.
|
||||||
|
|
||||||
Issue priorities may be seen at https://github.com/orgs/kaspanet/projects/4
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The [documentation](https://github.com/kaspanet/docs) is a work-in-progress
|
The [documentation](https://github.com/kaspanet/docs) is a work-in-progress
|
||||||
|
50
app/app.go
50
app/app.go
@ -7,23 +7,22 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
|
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/os/execenv"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/os/limits"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/os/signal"
|
"github.com/kaspanet/kaspad/infrastructure/os/signal"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/os/winservice"
|
|
||||||
"github.com/kaspanet/kaspad/util/panics"
|
|
||||||
"github.com/kaspanet/kaspad/util/profiling"
|
"github.com/kaspanet/kaspad/util/profiling"
|
||||||
"github.com/kaspanet/kaspad/version"
|
"github.com/kaspanet/kaspad/version"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/os/execenv"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/os/limits"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/os/winservice"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const leveldbCacheSizeMiB = 256
|
||||||
leveldbCacheSizeMiB = 256
|
|
||||||
defaultDataDirname = "datadir2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var desiredLimits = &limits.DesiredLimits{
|
var desiredLimits = &limits.DesiredLimits{
|
||||||
FileLimitWant: 2048,
|
FileLimitWant: 2048,
|
||||||
@ -52,7 +51,6 @@ func StartApp() error {
|
|||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer logger.BackendLog.Close()
|
|
||||||
defer panics.HandlePanic(log, "MAIN", nil)
|
defer panics.HandlePanic(log, "MAIN", nil)
|
||||||
|
|
||||||
app := &kaspadApp{cfg: cfg}
|
app := &kaspadApp{cfg: cfg}
|
||||||
@ -87,7 +85,12 @@ func (app *kaspadApp) main(startedChan chan<- struct{}) error {
|
|||||||
if app.cfg.Profile != "" {
|
if app.cfg.Profile != "" {
|
||||||
profiling.Start(app.cfg.Profile, log)
|
profiling.Start(app.cfg.Profile, log)
|
||||||
}
|
}
|
||||||
profiling.TrackHeap(app.cfg.AppDir, log)
|
|
||||||
|
// Perform upgrades to kaspad as new versions require it.
|
||||||
|
if err := doUpgrades(); err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Return now if an interrupt signal was triggered.
|
// Return now if an interrupt signal was triggered.
|
||||||
if signal.InterruptRequested(interrupt) {
|
if signal.InterruptRequested(interrupt) {
|
||||||
@ -105,7 +108,7 @@ func (app *kaspadApp) main(startedChan chan<- struct{}) error {
|
|||||||
// Open the database
|
// Open the database
|
||||||
databaseContext, err := openDB(app.cfg)
|
databaseContext, err := openDB(app.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Loading database failed: %+v", err)
|
log.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,9 +164,15 @@ func (app *kaspadApp) main(startedChan chan<- struct{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// doUpgrades performs upgrades to kaspad as new versions require it.
|
||||||
|
// currently it's a placeholder we got from kaspad upstream, that does nothing
|
||||||
|
func doUpgrades() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// dbPath returns the path to the block database given a database type.
|
// dbPath returns the path to the block database given a database type.
|
||||||
func databasePath(cfg *config.Config) string {
|
func databasePath(cfg *config.Config) string {
|
||||||
return filepath.Join(cfg.AppDir, defaultDataDirname)
|
return filepath.Join(cfg.DataDir, "db")
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeDatabase(cfg *config.Config) error {
|
func removeDatabase(cfg *config.Config) error {
|
||||||
@ -173,17 +182,6 @@ func removeDatabase(cfg *config.Config) error {
|
|||||||
|
|
||||||
func openDB(cfg *config.Config) (database.Database, error) {
|
func openDB(cfg *config.Config) (database.Database, error) {
|
||||||
dbPath := databasePath(cfg)
|
dbPath := databasePath(cfg)
|
||||||
|
|
||||||
err := checkDatabaseVersion(dbPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Loading database from '%s'", dbPath)
|
log.Infof("Loading database from '%s'", dbPath)
|
||||||
db, err := ldb.NewLevelDB(dbPath, leveldbCacheSizeMiB)
|
return ldb.NewLevelDB(dbPath, leveldbCacheSizeMiB)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return db, nil
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ supported kaspa messages to and from the appmessage. This package does not deal
|
|||||||
with the specifics of message handling such as what to do when a message is
|
with the specifics of message handling such as what to do when a message is
|
||||||
received. This provides the caller with a high level of flexibility.
|
received. This provides the caller with a high level of flexibility.
|
||||||
|
|
||||||
# Kaspa Message Overview
|
Kaspa Message Overview
|
||||||
|
|
||||||
The kaspa protocol consists of exchanging messages between peers. Each
|
The kaspa protocol consists of exchanging messages between peers. Each
|
||||||
message is preceded by a header which identifies information about it such as
|
message is preceded by a header which identifies information about it such as
|
||||||
@ -22,7 +22,7 @@ messages, all of the details of marshalling and unmarshalling to and from the
|
|||||||
appmessage using kaspa encoding are handled so the caller doesn't have to concern
|
appmessage using kaspa encoding are handled so the caller doesn't have to concern
|
||||||
themselves with the specifics.
|
themselves with the specifics.
|
||||||
|
|
||||||
# Message Interaction
|
Message Interaction
|
||||||
|
|
||||||
The following provides a quick summary of how the kaspa messages are intended
|
The following provides a quick summary of how the kaspa messages are intended
|
||||||
to interact with one another. As stated above, these interactions are not
|
to interact with one another. As stated above, these interactions are not
|
||||||
@ -45,13 +45,13 @@ interactions in no particular order.
|
|||||||
notfound message (MsgNotFound)
|
notfound message (MsgNotFound)
|
||||||
ping message (MsgPing) pong message (MsgPong)
|
ping message (MsgPing) pong message (MsgPong)
|
||||||
|
|
||||||
# Common Parameters
|
Common Parameters
|
||||||
|
|
||||||
There are several common parameters that arise when using this package to read
|
There are several common parameters that arise when using this package to read
|
||||||
and write kaspa messages. The following sections provide a quick overview of
|
and write kaspa messages. The following sections provide a quick overview of
|
||||||
these parameters so the next sections can build on them.
|
these parameters so the next sections can build on them.
|
||||||
|
|
||||||
# Protocol Version
|
Protocol Version
|
||||||
|
|
||||||
The protocol version should be negotiated with the remote peer at a higher
|
The protocol version should be negotiated with the remote peer at a higher
|
||||||
level than this package via the version (MsgVersion) message exchange, however,
|
level than this package via the version (MsgVersion) message exchange, however,
|
||||||
@ -60,7 +60,7 @@ latest protocol version this package supports and is typically the value to use
|
|||||||
for all outbound connections before a potentially lower protocol version is
|
for all outbound connections before a potentially lower protocol version is
|
||||||
negotiated.
|
negotiated.
|
||||||
|
|
||||||
# Kaspa Network
|
Kaspa Network
|
||||||
|
|
||||||
The kaspa network is a magic number which is used to identify the start of a
|
The kaspa network is a magic number which is used to identify the start of a
|
||||||
message and which kaspa network the message applies to. This package provides
|
message and which kaspa network the message applies to. This package provides
|
||||||
@ -71,7 +71,7 @@ the following constants:
|
|||||||
appmessage.Simnet (Simulation test network)
|
appmessage.Simnet (Simulation test network)
|
||||||
appmessage.Devnet (Development network)
|
appmessage.Devnet (Development network)
|
||||||
|
|
||||||
# Determining Message Type
|
Determining Message Type
|
||||||
|
|
||||||
As discussed in the kaspa message overview section, this package reads
|
As discussed in the kaspa message overview section, this package reads
|
||||||
and writes kaspa messages using a generic interface named Message. In
|
and writes kaspa messages using a generic interface named Message. In
|
||||||
@ -89,7 +89,7 @@ switch or type assertion. An example of a type switch follows:
|
|||||||
fmt.Printf("Number of tx in block: %d", msg.Header.TxnCount)
|
fmt.Printf("Number of tx in block: %d", msg.Header.TxnCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Reading Messages
|
Reading Messages
|
||||||
|
|
||||||
In order to unmarshall kaspa messages from the appmessage, use the ReadMessage
|
In order to unmarshall kaspa messages from the appmessage, use the ReadMessage
|
||||||
function. It accepts any io.Reader, but typically this will be a net.Conn to
|
function. It accepts any io.Reader, but typically this will be a net.Conn to
|
||||||
@ -104,7 +104,7 @@ a remote node running a kaspa peer. Example syntax is:
|
|||||||
// Log and handle the error
|
// Log and handle the error
|
||||||
}
|
}
|
||||||
|
|
||||||
# Writing Messages
|
Writing Messages
|
||||||
|
|
||||||
In order to marshall kaspa messages to the appmessage, use the WriteMessage
|
In order to marshall kaspa messages to the appmessage, use the WriteMessage
|
||||||
function. It accepts any io.Writer, but typically this will be a net.Conn to
|
function. It accepts any io.Writer, but typically this will be a net.Conn to
|
||||||
@ -122,7 +122,7 @@ from a remote peer is:
|
|||||||
// Log and handle the error
|
// Log and handle the error
|
||||||
}
|
}
|
||||||
|
|
||||||
# Errors
|
Errors
|
||||||
|
|
||||||
Errors returned by this package are either the raw errors provided by underlying
|
Errors returned by this package are either the raw errors provided by underlying
|
||||||
calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and
|
calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and
|
||||||
|
@ -2,12 +2,7 @@ package appmessage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
@ -32,17 +27,13 @@ func DomainBlockToMsgBlock(domainBlock *externalapi.DomainBlock) *MsgBlock {
|
|||||||
func DomainBlockHeaderToBlockHeader(domainBlockHeader externalapi.BlockHeader) *MsgBlockHeader {
|
func DomainBlockHeaderToBlockHeader(domainBlockHeader externalapi.BlockHeader) *MsgBlockHeader {
|
||||||
return &MsgBlockHeader{
|
return &MsgBlockHeader{
|
||||||
Version: domainBlockHeader.Version(),
|
Version: domainBlockHeader.Version(),
|
||||||
Parents: domainBlockHeader.Parents(),
|
ParentHashes: domainBlockHeader.ParentHashes(),
|
||||||
HashMerkleRoot: domainBlockHeader.HashMerkleRoot(),
|
HashMerkleRoot: domainBlockHeader.HashMerkleRoot(),
|
||||||
AcceptedIDMerkleRoot: domainBlockHeader.AcceptedIDMerkleRoot(),
|
AcceptedIDMerkleRoot: domainBlockHeader.AcceptedIDMerkleRoot(),
|
||||||
UTXOCommitment: domainBlockHeader.UTXOCommitment(),
|
UTXOCommitment: domainBlockHeader.UTXOCommitment(),
|
||||||
Timestamp: mstime.UnixMilliseconds(domainBlockHeader.TimeInMilliseconds()),
|
Timestamp: mstime.UnixMilliseconds(domainBlockHeader.TimeInMilliseconds()),
|
||||||
Bits: domainBlockHeader.Bits(),
|
Bits: domainBlockHeader.Bits(),
|
||||||
Nonce: domainBlockHeader.Nonce(),
|
Nonce: domainBlockHeader.Nonce(),
|
||||||
BlueScore: domainBlockHeader.BlueScore(),
|
|
||||||
DAAScore: domainBlockHeader.DAAScore(),
|
|
||||||
BlueWork: domainBlockHeader.BlueWork(),
|
|
||||||
PruningPoint: domainBlockHeader.PruningPoint(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,17 +54,13 @@ func MsgBlockToDomainBlock(msgBlock *MsgBlock) *externalapi.DomainBlock {
|
|||||||
func BlockHeaderToDomainBlockHeader(blockHeader *MsgBlockHeader) externalapi.BlockHeader {
|
func BlockHeaderToDomainBlockHeader(blockHeader *MsgBlockHeader) externalapi.BlockHeader {
|
||||||
return blockheader.NewImmutableBlockHeader(
|
return blockheader.NewImmutableBlockHeader(
|
||||||
blockHeader.Version,
|
blockHeader.Version,
|
||||||
blockHeader.Parents,
|
blockHeader.ParentHashes,
|
||||||
blockHeader.HashMerkleRoot,
|
blockHeader.HashMerkleRoot,
|
||||||
blockHeader.AcceptedIDMerkleRoot,
|
blockHeader.AcceptedIDMerkleRoot,
|
||||||
blockHeader.UTXOCommitment,
|
blockHeader.UTXOCommitment,
|
||||||
blockHeader.Timestamp.UnixMilliseconds(),
|
blockHeader.Timestamp.UnixMilliseconds(),
|
||||||
blockHeader.Bits,
|
blockHeader.Bits,
|
||||||
blockHeader.Nonce,
|
blockHeader.Nonce,
|
||||||
blockHeader.DAAScore,
|
|
||||||
blockHeader.BlueScore,
|
|
||||||
blockHeader.BlueWork,
|
|
||||||
blockHeader.PruningPoint,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +83,7 @@ func DomainTransactionToMsgTx(domainTransaction *externalapi.DomainTransaction)
|
|||||||
LockTime: domainTransaction.LockTime,
|
LockTime: domainTransaction.LockTime,
|
||||||
SubnetworkID: domainTransaction.SubnetworkID,
|
SubnetworkID: domainTransaction.SubnetworkID,
|
||||||
Gas: domainTransaction.Gas,
|
Gas: domainTransaction.Gas,
|
||||||
|
PayloadHash: domainTransaction.PayloadHash,
|
||||||
Payload: domainTransaction.Payload,
|
Payload: domainTransaction.Payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +100,6 @@ func domainTransactionInputToTxIn(domainTransactionInput *externalapi.DomainTran
|
|||||||
PreviousOutpoint: *domainOutpointToOutpoint(domainTransactionInput.PreviousOutpoint),
|
PreviousOutpoint: *domainOutpointToOutpoint(domainTransactionInput.PreviousOutpoint),
|
||||||
SignatureScript: domainTransactionInput.SignatureScript,
|
SignatureScript: domainTransactionInput.SignatureScript,
|
||||||
Sequence: domainTransactionInput.Sequence,
|
Sequence: domainTransactionInput.Sequence,
|
||||||
SigOpCount: domainTransactionInput.SigOpCount,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +133,7 @@ func MsgTxToDomainTransaction(msgTx *MsgTx) *externalapi.DomainTransaction {
|
|||||||
LockTime: msgTx.LockTime,
|
LockTime: msgTx.LockTime,
|
||||||
SubnetworkID: msgTx.SubnetworkID,
|
SubnetworkID: msgTx.SubnetworkID,
|
||||||
Gas: msgTx.Gas,
|
Gas: msgTx.Gas,
|
||||||
|
PayloadHash: msgTx.PayloadHash,
|
||||||
Payload: payload,
|
Payload: payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,7 +149,6 @@ func txInToDomainTransactionInput(txIn *TxIn) *externalapi.DomainTransactionInpu
|
|||||||
return &externalapi.DomainTransactionInput{
|
return &externalapi.DomainTransactionInput{
|
||||||
PreviousOutpoint: *outpointToDomainOutpoint(&txIn.PreviousOutpoint), //TODO
|
PreviousOutpoint: *outpointToDomainOutpoint(&txIn.PreviousOutpoint), //TODO
|
||||||
SignatureScript: txIn.SignatureScript,
|
SignatureScript: txIn.SignatureScript,
|
||||||
SigOpCount: txIn.SigOpCount,
|
|
||||||
Sequence: txIn.Sequence,
|
Sequence: txIn.Sequence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,10 +164,18 @@ func outpointToDomainOutpoint(outpoint *Outpoint) *externalapi.DomainOutpoint {
|
|||||||
func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externalapi.DomainTransaction, error) {
|
func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externalapi.DomainTransaction, error) {
|
||||||
inputs := make([]*externalapi.DomainTransactionInput, len(rpcTransaction.Inputs))
|
inputs := make([]*externalapi.DomainTransactionInput, len(rpcTransaction.Inputs))
|
||||||
for i, input := range rpcTransaction.Inputs {
|
for i, input := range rpcTransaction.Inputs {
|
||||||
previousOutpoint, err := RPCOutpointToDomainOutpoint(input.PreviousOutpoint)
|
transactionIDBytes, err := hex.DecodeString(input.PreviousOutpoint.TransactionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
transactionID, err := transactionid.FromBytes(transactionIDBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
previousOutpoint := &externalapi.DomainOutpoint{
|
||||||
|
TransactionID: *transactionID,
|
||||||
|
Index: input.PreviousOutpoint.Index,
|
||||||
|
}
|
||||||
signatureScript, err := hex.DecodeString(input.SignatureScript)
|
signatureScript, err := hex.DecodeString(input.SignatureScript)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -189,7 +184,6 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa
|
|||||||
PreviousOutpoint: *previousOutpoint,
|
PreviousOutpoint: *previousOutpoint,
|
||||||
SignatureScript: signatureScript,
|
SignatureScript: signatureScript,
|
||||||
Sequence: input.Sequence,
|
Sequence: input.Sequence,
|
||||||
SigOpCount: input.SigOpCount,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outputs := make([]*externalapi.DomainTransactionOutput, len(rpcTransaction.Outputs))
|
outputs := make([]*externalapi.DomainTransactionOutput, len(rpcTransaction.Outputs))
|
||||||
@ -204,7 +198,19 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subnetworkID, err := subnetworks.FromString(rpcTransaction.SubnetworkID)
|
subnetworkIDBytes, err := hex.DecodeString(rpcTransaction.SubnetworkID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
subnetworkID, err := subnetworks.FromBytes(subnetworkIDBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
payloadHashBytes, err := hex.DecodeString(rpcTransaction.PayloadHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
payloadHash, err := externalapi.NewDomainHashFromByteSlice(payloadHashBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -219,42 +225,12 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa
|
|||||||
Outputs: outputs,
|
Outputs: outputs,
|
||||||
LockTime: rpcTransaction.LockTime,
|
LockTime: rpcTransaction.LockTime,
|
||||||
SubnetworkID: *subnetworkID,
|
SubnetworkID: *subnetworkID,
|
||||||
Gas: rpcTransaction.Gas,
|
Gas: rpcTransaction.LockTime,
|
||||||
MassCommitment: rpcTransaction.Mass,
|
PayloadHash: *payloadHash,
|
||||||
Payload: payload,
|
Payload: payload,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCOutpointToDomainOutpoint converts RPCOutpoint to DomainOutpoint
|
|
||||||
func RPCOutpointToDomainOutpoint(outpoint *RPCOutpoint) (*externalapi.DomainOutpoint, error) {
|
|
||||||
transactionID, err := transactionid.FromString(outpoint.TransactionID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &externalapi.DomainOutpoint{
|
|
||||||
TransactionID: *transactionID,
|
|
||||||
Index: outpoint.Index,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCUTXOEntryToUTXOEntry converts RPCUTXOEntry to UTXOEntry
|
|
||||||
func RPCUTXOEntryToUTXOEntry(entry *RPCUTXOEntry) (externalapi.UTXOEntry, error) {
|
|
||||||
script, err := hex.DecodeString(entry.ScriptPublicKey.Script)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utxo.NewUTXOEntry(
|
|
||||||
entry.Amount,
|
|
||||||
&externalapi.ScriptPublicKey{
|
|
||||||
Script: script,
|
|
||||||
Version: entry.ScriptPublicKey.Version,
|
|
||||||
},
|
|
||||||
entry.IsCoinbase,
|
|
||||||
entry.BlockDAAScore,
|
|
||||||
), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DomainTransactionToRPCTransaction converts DomainTransactions to RPCTransactions
|
// DomainTransactionToRPCTransaction converts DomainTransactions to RPCTransactions
|
||||||
func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransaction) *RPCTransaction {
|
func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransaction) *RPCTransaction {
|
||||||
inputs := make([]*RPCTransactionInput, len(transaction.Inputs))
|
inputs := make([]*RPCTransactionInput, len(transaction.Inputs))
|
||||||
@ -269,7 +245,6 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio
|
|||||||
PreviousOutpoint: previousOutpoint,
|
PreviousOutpoint: previousOutpoint,
|
||||||
SignatureScript: signatureScript,
|
SignatureScript: signatureScript,
|
||||||
Sequence: input.Sequence,
|
Sequence: input.Sequence,
|
||||||
SigOpCount: input.SigOpCount,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outputs := make([]*RPCTransactionOutput, len(transaction.Outputs))
|
outputs := make([]*RPCTransactionOutput, len(transaction.Outputs))
|
||||||
@ -280,7 +255,8 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio
|
|||||||
ScriptPublicKey: &RPCScriptPublicKey{Script: scriptPublicKey, Version: output.ScriptPublicKey.Version},
|
ScriptPublicKey: &RPCScriptPublicKey{Script: scriptPublicKey, Version: output.ScriptPublicKey.Version},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subnetworkID := transaction.SubnetworkID.String()
|
subnetworkID := hex.EncodeToString(transaction.SubnetworkID[:])
|
||||||
|
payloadHash := transaction.PayloadHash.String()
|
||||||
payload := hex.EncodeToString(transaction.Payload)
|
payload := hex.EncodeToString(transaction.Payload)
|
||||||
return &RPCTransaction{
|
return &RPCTransaction{
|
||||||
Version: transaction.Version,
|
Version: transaction.Version,
|
||||||
@ -288,8 +264,8 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio
|
|||||||
Outputs: outputs,
|
Outputs: outputs,
|
||||||
LockTime: transaction.LockTime,
|
LockTime: transaction.LockTime,
|
||||||
SubnetworkID: subnetworkID,
|
SubnetworkID: subnetworkID,
|
||||||
Gas: transaction.Gas,
|
Gas: transaction.LockTime,
|
||||||
Mass: transaction.MassCommitment,
|
PayloadHash: payloadHash,
|
||||||
Payload: payload,
|
Payload: payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,14 +277,7 @@ func OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs(
|
|||||||
|
|
||||||
domainOutpointAndUTXOEntryPairs := make([]*externalapi.OutpointAndUTXOEntryPair, len(outpointAndUTXOEntryPairs))
|
domainOutpointAndUTXOEntryPairs := make([]*externalapi.OutpointAndUTXOEntryPair, len(outpointAndUTXOEntryPairs))
|
||||||
for i, outpointAndUTXOEntryPair := range outpointAndUTXOEntryPairs {
|
for i, outpointAndUTXOEntryPair := range outpointAndUTXOEntryPairs {
|
||||||
domainOutpointAndUTXOEntryPairs[i] = outpointAndUTXOEntryPairToDomainOutpointAndUTXOEntryPair(outpointAndUTXOEntryPair)
|
domainOutpointAndUTXOEntryPairs[i] = &externalapi.OutpointAndUTXOEntryPair{
|
||||||
}
|
|
||||||
return domainOutpointAndUTXOEntryPairs
|
|
||||||
}
|
|
||||||
|
|
||||||
func outpointAndUTXOEntryPairToDomainOutpointAndUTXOEntryPair(
|
|
||||||
outpointAndUTXOEntryPair *OutpointAndUTXOEntryPair) *externalapi.OutpointAndUTXOEntryPair {
|
|
||||||
return &externalapi.OutpointAndUTXOEntryPair{
|
|
||||||
Outpoint: &externalapi.DomainOutpoint{
|
Outpoint: &externalapi.DomainOutpoint{
|
||||||
TransactionID: outpointAndUTXOEntryPair.Outpoint.TxID,
|
TransactionID: outpointAndUTXOEntryPair.Outpoint.TxID,
|
||||||
Index: outpointAndUTXOEntryPair.Outpoint.Index,
|
Index: outpointAndUTXOEntryPair.Outpoint.Index,
|
||||||
@ -317,10 +286,12 @@ func outpointAndUTXOEntryPairToDomainOutpointAndUTXOEntryPair(
|
|||||||
outpointAndUTXOEntryPair.UTXOEntry.Amount,
|
outpointAndUTXOEntryPair.UTXOEntry.Amount,
|
||||||
outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey,
|
outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey,
|
||||||
outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase,
|
outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase,
|
||||||
outpointAndUTXOEntryPair.UTXOEntry.BlockDAAScore,
|
outpointAndUTXOEntryPair.UTXOEntry.BlockBlueScore,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return domainOutpointAndUTXOEntryPairs
|
||||||
|
}
|
||||||
|
|
||||||
// DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs converts
|
// DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs converts
|
||||||
// domain OutpointAndUTXOEntryPairs to OutpointAndUTXOEntryPairs
|
// domain OutpointAndUTXOEntryPairs to OutpointAndUTXOEntryPairs
|
||||||
@ -338,267 +309,9 @@ func DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(
|
|||||||
Amount: outpointAndUTXOEntryPair.UTXOEntry.Amount(),
|
Amount: outpointAndUTXOEntryPair.UTXOEntry.Amount(),
|
||||||
ScriptPublicKey: outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey(),
|
ScriptPublicKey: outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey(),
|
||||||
IsCoinbase: outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase(),
|
IsCoinbase: outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase(),
|
||||||
BlockDAAScore: outpointAndUTXOEntryPair.UTXOEntry.BlockDAAScore(),
|
BlockBlueScore: outpointAndUTXOEntryPair.UTXOEntry.BlockBlueScore(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return domainOutpointAndUTXOEntryPairs
|
return domainOutpointAndUTXOEntryPairs
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainBlockToRPCBlock converts DomainBlocks to RPCBlocks
|
|
||||||
func DomainBlockToRPCBlock(block *externalapi.DomainBlock) *RPCBlock {
|
|
||||||
parents := make([]*RPCBlockLevelParents, len(block.Header.Parents()))
|
|
||||||
for i, blockLevelParents := range block.Header.Parents() {
|
|
||||||
parents[i] = &RPCBlockLevelParents{
|
|
||||||
ParentHashes: hashes.ToStrings(blockLevelParents),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
header := &RPCBlockHeader{
|
|
||||||
Version: uint32(block.Header.Version()),
|
|
||||||
Parents: parents,
|
|
||||||
HashMerkleRoot: block.Header.HashMerkleRoot().String(),
|
|
||||||
AcceptedIDMerkleRoot: block.Header.AcceptedIDMerkleRoot().String(),
|
|
||||||
UTXOCommitment: block.Header.UTXOCommitment().String(),
|
|
||||||
Timestamp: block.Header.TimeInMilliseconds(),
|
|
||||||
Bits: block.Header.Bits(),
|
|
||||||
Nonce: block.Header.Nonce(),
|
|
||||||
DAAScore: block.Header.DAAScore(),
|
|
||||||
BlueScore: block.Header.BlueScore(),
|
|
||||||
BlueWork: block.Header.BlueWork().Text(16),
|
|
||||||
PruningPoint: block.Header.PruningPoint().String(),
|
|
||||||
}
|
|
||||||
transactions := make([]*RPCTransaction, len(block.Transactions))
|
|
||||||
for i, transaction := range block.Transactions {
|
|
||||||
transactions[i] = DomainTransactionToRPCTransaction(transaction)
|
|
||||||
}
|
|
||||||
return &RPCBlock{
|
|
||||||
Header: header,
|
|
||||||
Transactions: transactions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCBlockToDomainBlock converts `block` into a DomainBlock
|
|
||||||
func RPCBlockToDomainBlock(block *RPCBlock) (*externalapi.DomainBlock, error) {
|
|
||||||
parents := make([]externalapi.BlockLevelParents, len(block.Header.Parents))
|
|
||||||
for i, blockLevelParents := range block.Header.Parents {
|
|
||||||
parents[i] = make(externalapi.BlockLevelParents, len(blockLevelParents.ParentHashes))
|
|
||||||
for j, parentHash := range blockLevelParents.ParentHashes {
|
|
||||||
var err error
|
|
||||||
parents[i][j], err = externalapi.NewDomainHashFromString(parentHash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hashMerkleRoot, err := externalapi.NewDomainHashFromString(block.Header.HashMerkleRoot)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
acceptedIDMerkleRoot, err := externalapi.NewDomainHashFromString(block.Header.AcceptedIDMerkleRoot)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
utxoCommitment, err := externalapi.NewDomainHashFromString(block.Header.UTXOCommitment)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
blueWork, success := new(big.Int).SetString(block.Header.BlueWork, 16)
|
|
||||||
if !success {
|
|
||||||
return nil, errors.Errorf("failed to parse blue work: %s", block.Header.BlueWork)
|
|
||||||
}
|
|
||||||
pruningPoint, err := externalapi.NewDomainHashFromString(block.Header.PruningPoint)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
header := blockheader.NewImmutableBlockHeader(
|
|
||||||
uint16(block.Header.Version),
|
|
||||||
parents,
|
|
||||||
hashMerkleRoot,
|
|
||||||
acceptedIDMerkleRoot,
|
|
||||||
utxoCommitment,
|
|
||||||
block.Header.Timestamp,
|
|
||||||
block.Header.Bits,
|
|
||||||
block.Header.Nonce,
|
|
||||||
block.Header.DAAScore,
|
|
||||||
block.Header.BlueScore,
|
|
||||||
blueWork,
|
|
||||||
pruningPoint)
|
|
||||||
transactions := make([]*externalapi.DomainTransaction, len(block.Transactions))
|
|
||||||
for i, transaction := range block.Transactions {
|
|
||||||
domainTransaction, err := RPCTransactionToDomainTransaction(transaction)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
transactions[i] = domainTransaction
|
|
||||||
}
|
|
||||||
return &externalapi.DomainBlock{
|
|
||||||
Header: header,
|
|
||||||
Transactions: transactions,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockWithTrustedDataToDomainBlockWithTrustedData converts *MsgBlockWithTrustedData to *externalapi.BlockWithTrustedData
|
|
||||||
func BlockWithTrustedDataToDomainBlockWithTrustedData(block *MsgBlockWithTrustedData) *externalapi.BlockWithTrustedData {
|
|
||||||
daaWindow := make([]*externalapi.TrustedDataDataDAAHeader, len(block.DAAWindow))
|
|
||||||
for i, daaBlock := range block.DAAWindow {
|
|
||||||
daaWindow[i] = &externalapi.TrustedDataDataDAAHeader{
|
|
||||||
Header: BlockHeaderToDomainBlockHeader(&daaBlock.Block.Header),
|
|
||||||
GHOSTDAGData: ghostdagDataToDomainGHOSTDAGData(daaBlock.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ghostdagData := make([]*externalapi.BlockGHOSTDAGDataHashPair, len(block.GHOSTDAGData))
|
|
||||||
for i, datum := range block.GHOSTDAGData {
|
|
||||||
ghostdagData[i] = &externalapi.BlockGHOSTDAGDataHashPair{
|
|
||||||
Hash: datum.Hash,
|
|
||||||
GHOSTDAGData: ghostdagDataToDomainGHOSTDAGData(datum.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &externalapi.BlockWithTrustedData{
|
|
||||||
Block: MsgBlockToDomainBlock(block.Block),
|
|
||||||
DAAWindow: daaWindow,
|
|
||||||
GHOSTDAGData: ghostdagData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustedDataDataDAABlockV4ToTrustedDataDataDAAHeader converts *TrustedDataDAAHeader to *externalapi.TrustedDataDataDAAHeader
|
|
||||||
func TrustedDataDataDAABlockV4ToTrustedDataDataDAAHeader(daaBlock *TrustedDataDAAHeader) *externalapi.TrustedDataDataDAAHeader {
|
|
||||||
return &externalapi.TrustedDataDataDAAHeader{
|
|
||||||
Header: BlockHeaderToDomainBlockHeader(daaBlock.Header),
|
|
||||||
GHOSTDAGData: ghostdagDataToDomainGHOSTDAGData(daaBlock.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GHOSTDAGHashPairToDomainGHOSTDAGHashPair converts *BlockGHOSTDAGDataHashPair to *externalapi.BlockGHOSTDAGDataHashPair
|
|
||||||
func GHOSTDAGHashPairToDomainGHOSTDAGHashPair(datum *BlockGHOSTDAGDataHashPair) *externalapi.BlockGHOSTDAGDataHashPair {
|
|
||||||
return &externalapi.BlockGHOSTDAGDataHashPair{
|
|
||||||
Hash: datum.Hash,
|
|
||||||
GHOSTDAGData: ghostdagDataToDomainGHOSTDAGData(datum.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ghostdagDataToDomainGHOSTDAGData(data *BlockGHOSTDAGData) *externalapi.BlockGHOSTDAGData {
|
|
||||||
bluesAnticoneSizes := make(map[externalapi.DomainHash]externalapi.KType, len(data.BluesAnticoneSizes))
|
|
||||||
for _, pair := range data.BluesAnticoneSizes {
|
|
||||||
bluesAnticoneSizes[*pair.BlueHash] = pair.AnticoneSize
|
|
||||||
}
|
|
||||||
return externalapi.NewBlockGHOSTDAGData(
|
|
||||||
data.BlueScore,
|
|
||||||
data.BlueWork,
|
|
||||||
data.SelectedParent,
|
|
||||||
data.MergeSetBlues,
|
|
||||||
data.MergeSetReds,
|
|
||||||
bluesAnticoneSizes,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func domainGHOSTDAGDataGHOSTDAGData(data *externalapi.BlockGHOSTDAGData) *BlockGHOSTDAGData {
|
|
||||||
bluesAnticoneSizes := make([]*BluesAnticoneSizes, 0, len(data.BluesAnticoneSizes()))
|
|
||||||
for blueHash, anticoneSize := range data.BluesAnticoneSizes() {
|
|
||||||
blueHashCopy := blueHash
|
|
||||||
bluesAnticoneSizes = append(bluesAnticoneSizes, &BluesAnticoneSizes{
|
|
||||||
BlueHash: &blueHashCopy,
|
|
||||||
AnticoneSize: anticoneSize,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return &BlockGHOSTDAGData{
|
|
||||||
BlueScore: data.BlueScore(),
|
|
||||||
BlueWork: data.BlueWork(),
|
|
||||||
SelectedParent: data.SelectedParent(),
|
|
||||||
MergeSetBlues: data.MergeSetBlues(),
|
|
||||||
MergeSetReds: data.MergeSetReds(),
|
|
||||||
BluesAnticoneSizes: bluesAnticoneSizes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DomainBlockWithTrustedDataToBlockWithTrustedData converts *externalapi.BlockWithTrustedData to *MsgBlockWithTrustedData
|
|
||||||
func DomainBlockWithTrustedDataToBlockWithTrustedData(block *externalapi.BlockWithTrustedData) *MsgBlockWithTrustedData {
|
|
||||||
daaWindow := make([]*TrustedDataDataDAABlock, len(block.DAAWindow))
|
|
||||||
for i, daaBlock := range block.DAAWindow {
|
|
||||||
daaWindow[i] = &TrustedDataDataDAABlock{
|
|
||||||
Block: &MsgBlock{
|
|
||||||
Header: *DomainBlockHeaderToBlockHeader(daaBlock.Header),
|
|
||||||
},
|
|
||||||
GHOSTDAGData: domainGHOSTDAGDataGHOSTDAGData(daaBlock.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ghostdagData := make([]*BlockGHOSTDAGDataHashPair, len(block.GHOSTDAGData))
|
|
||||||
for i, datum := range block.GHOSTDAGData {
|
|
||||||
ghostdagData[i] = &BlockGHOSTDAGDataHashPair{
|
|
||||||
Hash: datum.Hash,
|
|
||||||
GHOSTDAGData: domainGHOSTDAGDataGHOSTDAGData(datum.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MsgBlockWithTrustedData{
|
|
||||||
Block: DomainBlockToMsgBlock(block.Block),
|
|
||||||
DAAScore: block.Block.Header.DAAScore(),
|
|
||||||
DAAWindow: daaWindow,
|
|
||||||
GHOSTDAGData: ghostdagData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DomainBlockWithTrustedDataToBlockWithTrustedDataV4 converts a set of *externalapi.DomainBlock, daa window indices and ghostdag data indices
|
|
||||||
// to *MsgBlockWithTrustedDataV4
|
|
||||||
func DomainBlockWithTrustedDataToBlockWithTrustedDataV4(block *externalapi.DomainBlock, daaWindowIndices, ghostdagDataIndices []uint64) *MsgBlockWithTrustedDataV4 {
|
|
||||||
return &MsgBlockWithTrustedDataV4{
|
|
||||||
Block: DomainBlockToMsgBlock(block),
|
|
||||||
DAAWindowIndices: daaWindowIndices,
|
|
||||||
GHOSTDAGDataIndices: ghostdagDataIndices,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DomainTrustedDataToTrustedData converts *externalapi.BlockWithTrustedData to *MsgBlockWithTrustedData
|
|
||||||
func DomainTrustedDataToTrustedData(domainDAAWindow []*externalapi.TrustedDataDataDAAHeader, domainGHOSTDAGData []*externalapi.BlockGHOSTDAGDataHashPair) *MsgTrustedData {
|
|
||||||
daaWindow := make([]*TrustedDataDAAHeader, len(domainDAAWindow))
|
|
||||||
for i, daaBlock := range domainDAAWindow {
|
|
||||||
daaWindow[i] = &TrustedDataDAAHeader{
|
|
||||||
Header: DomainBlockHeaderToBlockHeader(daaBlock.Header),
|
|
||||||
GHOSTDAGData: domainGHOSTDAGDataGHOSTDAGData(daaBlock.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ghostdagData := make([]*BlockGHOSTDAGDataHashPair, len(domainGHOSTDAGData))
|
|
||||||
for i, datum := range domainGHOSTDAGData {
|
|
||||||
ghostdagData[i] = &BlockGHOSTDAGDataHashPair{
|
|
||||||
Hash: datum.Hash,
|
|
||||||
GHOSTDAGData: domainGHOSTDAGDataGHOSTDAGData(datum.GHOSTDAGData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MsgTrustedData{
|
|
||||||
DAAWindow: daaWindow,
|
|
||||||
GHOSTDAGData: ghostdagData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MsgPruningPointProofToDomainPruningPointProof converts *MsgPruningPointProof to *externalapi.PruningPointProof
|
|
||||||
func MsgPruningPointProofToDomainPruningPointProof(pruningPointProofMessage *MsgPruningPointProof) *externalapi.PruningPointProof {
|
|
||||||
headers := make([][]externalapi.BlockHeader, len(pruningPointProofMessage.Headers))
|
|
||||||
for blockLevel, blockLevelParents := range pruningPointProofMessage.Headers {
|
|
||||||
headers[blockLevel] = make([]externalapi.BlockHeader, len(blockLevelParents))
|
|
||||||
for i, header := range blockLevelParents {
|
|
||||||
headers[blockLevel][i] = BlockHeaderToDomainBlockHeader(header)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &externalapi.PruningPointProof{
|
|
||||||
Headers: headers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DomainPruningPointProofToMsgPruningPointProof converts *externalapi.PruningPointProof to *MsgPruningPointProof
|
|
||||||
func DomainPruningPointProofToMsgPruningPointProof(pruningPointProof *externalapi.PruningPointProof) *MsgPruningPointProof {
|
|
||||||
headers := make([][]*MsgBlockHeader, len(pruningPointProof.Headers))
|
|
||||||
for blockLevel, blockLevelParents := range pruningPointProof.Headers {
|
|
||||||
headers[blockLevel] = make([]*MsgBlockHeader, len(blockLevelParents))
|
|
||||||
for i, header := range blockLevelParents {
|
|
||||||
headers[blockLevel][i] = DomainBlockHeaderToBlockHeader(header)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &MsgPruningPointProof{
|
|
||||||
Headers: headers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -38,10 +38,6 @@ type RPCError struct {
|
|||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err RPCError) Error() string {
|
|
||||||
return err.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCErrorf formats according to a format specifier and returns the string
|
// RPCErrorf formats according to a format specifier and returns the string
|
||||||
// as an RPCError.
|
// as an RPCError.
|
||||||
func RPCErrorf(format string, args ...interface{}) *RPCError {
|
func RPCErrorf(format string, args ...interface{}) *RPCError {
|
||||||
|
@ -45,34 +45,24 @@ const (
|
|||||||
CmdRequestRelayBlocks
|
CmdRequestRelayBlocks
|
||||||
CmdInvTransaction
|
CmdInvTransaction
|
||||||
CmdRequestTransactions
|
CmdRequestTransactions
|
||||||
|
CmdIBDBlock
|
||||||
CmdDoneHeaders
|
CmdDoneHeaders
|
||||||
CmdTransactionNotFound
|
CmdTransactionNotFound
|
||||||
CmdReject
|
CmdReject
|
||||||
|
CmdHeader
|
||||||
CmdRequestNextHeaders
|
CmdRequestNextHeaders
|
||||||
CmdRequestPruningPointUTXOSet
|
CmdRequestPruningPointUTXOSetAndBlock
|
||||||
CmdPruningPointUTXOSetChunk
|
CmdPruningPointUTXOSetChunk
|
||||||
|
CmdRequestIBDBlocks
|
||||||
CmdUnexpectedPruningPoint
|
CmdUnexpectedPruningPoint
|
||||||
|
CmdRequestPruningPointHash
|
||||||
|
CmdPruningPointHash
|
||||||
CmdIBDBlockLocator
|
CmdIBDBlockLocator
|
||||||
CmdIBDBlockLocatorHighestHash
|
CmdIBDBlockLocatorHighestHash
|
||||||
CmdIBDBlockLocatorHighestHashNotFound
|
CmdIBDBlockLocatorHighestHashNotFound
|
||||||
CmdBlockHeaders
|
CmdBlockHeaders
|
||||||
CmdRequestNextPruningPointUTXOSetChunk
|
CmdRequestNextPruningPointUTXOSetChunk
|
||||||
CmdDonePruningPointUTXOSetChunks
|
CmdDonePruningPointUTXOSetChunks
|
||||||
CmdBlockWithTrustedData
|
|
||||||
CmdDoneBlocksWithTrustedData
|
|
||||||
CmdRequestPruningPointAndItsAnticone
|
|
||||||
CmdIBDBlock
|
|
||||||
CmdRequestIBDBlocks
|
|
||||||
CmdPruningPoints
|
|
||||||
CmdRequestPruningPointProof
|
|
||||||
CmdPruningPointProof
|
|
||||||
CmdReady
|
|
||||||
CmdTrustedData
|
|
||||||
CmdBlockWithTrustedDataV4
|
|
||||||
CmdRequestNextPruningPointAndItsAnticoneBlocks
|
|
||||||
CmdRequestIBDChainBlockLocator
|
|
||||||
CmdIBDChainBlockLocator
|
|
||||||
CmdRequestAnticone
|
|
||||||
|
|
||||||
// rpc
|
// rpc
|
||||||
CmdGetCurrentNetworkRequestMessage
|
CmdGetCurrentNetworkRequestMessage
|
||||||
@ -127,12 +117,8 @@ const (
|
|||||||
CmdNotifyUTXOsChangedRequestMessage
|
CmdNotifyUTXOsChangedRequestMessage
|
||||||
CmdNotifyUTXOsChangedResponseMessage
|
CmdNotifyUTXOsChangedResponseMessage
|
||||||
CmdUTXOsChangedNotificationMessage
|
CmdUTXOsChangedNotificationMessage
|
||||||
CmdStopNotifyingUTXOsChangedRequestMessage
|
|
||||||
CmdStopNotifyingUTXOsChangedResponseMessage
|
|
||||||
CmdGetUTXOsByAddressesRequestMessage
|
CmdGetUTXOsByAddressesRequestMessage
|
||||||
CmdGetUTXOsByAddressesResponseMessage
|
CmdGetUTXOsByAddressesResponseMessage
|
||||||
CmdGetBalanceByAddressRequestMessage
|
|
||||||
CmdGetBalanceByAddressResponseMessage
|
|
||||||
CmdGetVirtualSelectedParentBlueScoreRequestMessage
|
CmdGetVirtualSelectedParentBlueScoreRequestMessage
|
||||||
CmdGetVirtualSelectedParentBlueScoreResponseMessage
|
CmdGetVirtualSelectedParentBlueScoreResponseMessage
|
||||||
CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage
|
CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage
|
||||||
@ -144,29 +130,6 @@ const (
|
|||||||
CmdUnbanResponseMessage
|
CmdUnbanResponseMessage
|
||||||
CmdGetInfoRequestMessage
|
CmdGetInfoRequestMessage
|
||||||
CmdGetInfoResponseMessage
|
CmdGetInfoResponseMessage
|
||||||
CmdNotifyPruningPointUTXOSetOverrideRequestMessage
|
|
||||||
CmdNotifyPruningPointUTXOSetOverrideResponseMessage
|
|
||||||
CmdPruningPointUTXOSetOverrideNotificationMessage
|
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage
|
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideResponseMessage
|
|
||||||
CmdEstimateNetworkHashesPerSecondRequestMessage
|
|
||||||
CmdEstimateNetworkHashesPerSecondResponseMessage
|
|
||||||
CmdNotifyVirtualDaaScoreChangedRequestMessage
|
|
||||||
CmdNotifyVirtualDaaScoreChangedResponseMessage
|
|
||||||
CmdVirtualDaaScoreChangedNotificationMessage
|
|
||||||
CmdGetBalancesByAddressesRequestMessage
|
|
||||||
CmdGetBalancesByAddressesResponseMessage
|
|
||||||
CmdNotifyNewBlockTemplateRequestMessage
|
|
||||||
CmdNotifyNewBlockTemplateResponseMessage
|
|
||||||
CmdNewBlockTemplateNotificationMessage
|
|
||||||
CmdGetMempoolEntriesByAddressesRequestMessage
|
|
||||||
CmdGetMempoolEntriesByAddressesResponseMessage
|
|
||||||
CmdGetCoinSupplyRequestMessage
|
|
||||||
CmdGetCoinSupplyResponseMessage
|
|
||||||
CmdGetFeeEstimateRequestMessage
|
|
||||||
CmdGetFeeEstimateResponseMessage
|
|
||||||
CmdSubmitTransactionReplacementRequestMessage
|
|
||||||
CmdSubmitTransactionReplacementResponseMessage
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
||||||
@ -175,7 +138,7 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{
|
|||||||
CmdVerAck: "VerAck",
|
CmdVerAck: "VerAck",
|
||||||
CmdRequestAddresses: "RequestAddresses",
|
CmdRequestAddresses: "RequestAddresses",
|
||||||
CmdAddresses: "Addresses",
|
CmdAddresses: "Addresses",
|
||||||
CmdRequestHeaders: "CmdRequestHeaders",
|
CmdRequestHeaders: "RequestHeaders",
|
||||||
CmdBlock: "Block",
|
CmdBlock: "Block",
|
||||||
CmdTx: "Tx",
|
CmdTx: "Tx",
|
||||||
CmdPing: "Ping",
|
CmdPing: "Ping",
|
||||||
@ -186,34 +149,24 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{
|
|||||||
CmdRequestRelayBlocks: "RequestRelayBlocks",
|
CmdRequestRelayBlocks: "RequestRelayBlocks",
|
||||||
CmdInvTransaction: "InvTransaction",
|
CmdInvTransaction: "InvTransaction",
|
||||||
CmdRequestTransactions: "RequestTransactions",
|
CmdRequestTransactions: "RequestTransactions",
|
||||||
|
CmdIBDBlock: "IBDBlock",
|
||||||
CmdDoneHeaders: "DoneHeaders",
|
CmdDoneHeaders: "DoneHeaders",
|
||||||
CmdTransactionNotFound: "TransactionNotFound",
|
CmdTransactionNotFound: "TransactionNotFound",
|
||||||
CmdReject: "Reject",
|
CmdReject: "Reject",
|
||||||
|
CmdHeader: "Header",
|
||||||
CmdRequestNextHeaders: "RequestNextHeaders",
|
CmdRequestNextHeaders: "RequestNextHeaders",
|
||||||
CmdRequestPruningPointUTXOSet: "RequestPruningPointUTXOSet",
|
CmdRequestPruningPointUTXOSetAndBlock: "RequestPruningPointUTXOSetAndBlock",
|
||||||
CmdPruningPointUTXOSetChunk: "PruningPointUTXOSetChunk",
|
CmdPruningPointUTXOSetChunk: "PruningPointUTXOSetChunk",
|
||||||
|
CmdRequestIBDBlocks: "RequestIBDBlocks",
|
||||||
CmdUnexpectedPruningPoint: "UnexpectedPruningPoint",
|
CmdUnexpectedPruningPoint: "UnexpectedPruningPoint",
|
||||||
|
CmdRequestPruningPointHash: "RequestPruningPointHashHash",
|
||||||
|
CmdPruningPointHash: "PruningPointHash",
|
||||||
CmdIBDBlockLocator: "IBDBlockLocator",
|
CmdIBDBlockLocator: "IBDBlockLocator",
|
||||||
CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash",
|
CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash",
|
||||||
CmdIBDBlockLocatorHighestHashNotFound: "IBDBlockLocatorHighestHashNotFound",
|
CmdIBDBlockLocatorHighestHashNotFound: "IBDBlockLocatorHighestHashNotFound",
|
||||||
CmdBlockHeaders: "BlockHeaders",
|
CmdBlockHeaders: "BlockHeaders",
|
||||||
CmdRequestNextPruningPointUTXOSetChunk: "RequestNextPruningPointUTXOSetChunk",
|
CmdRequestNextPruningPointUTXOSetChunk: "RequestNextPruningPointUTXOSetChunk",
|
||||||
CmdDonePruningPointUTXOSetChunks: "DonePruningPointUTXOSetChunks",
|
CmdDonePruningPointUTXOSetChunks: "DonePruningPointUTXOSetChunks",
|
||||||
CmdBlockWithTrustedData: "BlockWithTrustedData",
|
|
||||||
CmdDoneBlocksWithTrustedData: "DoneBlocksWithTrustedData",
|
|
||||||
CmdRequestPruningPointAndItsAnticone: "RequestPruningPointAndItsAnticoneHeaders",
|
|
||||||
CmdIBDBlock: "IBDBlock",
|
|
||||||
CmdRequestIBDBlocks: "RequestIBDBlocks",
|
|
||||||
CmdPruningPoints: "PruningPoints",
|
|
||||||
CmdRequestPruningPointProof: "RequestPruningPointProof",
|
|
||||||
CmdPruningPointProof: "PruningPointProof",
|
|
||||||
CmdReady: "Ready",
|
|
||||||
CmdTrustedData: "TrustedData",
|
|
||||||
CmdBlockWithTrustedDataV4: "BlockWithTrustedDataV4",
|
|
||||||
CmdRequestNextPruningPointAndItsAnticoneBlocks: "RequestNextPruningPointAndItsAnticoneBlocks",
|
|
||||||
CmdRequestIBDChainBlockLocator: "RequestIBDChainBlockLocator",
|
|
||||||
CmdIBDChainBlockLocator: "IBDChainBlockLocator",
|
|
||||||
CmdRequestAnticone: "RequestAnticone",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCMessageCommandToString maps all MessageCommands to their string representation
|
// RPCMessageCommandToString maps all MessageCommands to their string representation
|
||||||
@ -268,12 +221,8 @@ var RPCMessageCommandToString = map[MessageCommand]string{
|
|||||||
CmdNotifyUTXOsChangedRequestMessage: "NotifyUTXOsChangedRequest",
|
CmdNotifyUTXOsChangedRequestMessage: "NotifyUTXOsChangedRequest",
|
||||||
CmdNotifyUTXOsChangedResponseMessage: "NotifyUTXOsChangedResponse",
|
CmdNotifyUTXOsChangedResponseMessage: "NotifyUTXOsChangedResponse",
|
||||||
CmdUTXOsChangedNotificationMessage: "UTXOsChangedNotification",
|
CmdUTXOsChangedNotificationMessage: "UTXOsChangedNotification",
|
||||||
CmdStopNotifyingUTXOsChangedRequestMessage: "StopNotifyingUTXOsChangedRequest",
|
|
||||||
CmdStopNotifyingUTXOsChangedResponseMessage: "StopNotifyingUTXOsChangedResponse",
|
|
||||||
CmdGetUTXOsByAddressesRequestMessage: "GetUTXOsByAddressesRequest",
|
CmdGetUTXOsByAddressesRequestMessage: "GetUTXOsByAddressesRequest",
|
||||||
CmdGetUTXOsByAddressesResponseMessage: "GetUTXOsByAddressesResponse",
|
CmdGetUTXOsByAddressesResponseMessage: "GetUTXOsByAddressesResponse",
|
||||||
CmdGetBalanceByAddressRequestMessage: "GetBalanceByAddressRequest",
|
|
||||||
CmdGetBalanceByAddressResponseMessage: "GetBalancesByAddressResponse",
|
|
||||||
CmdGetVirtualSelectedParentBlueScoreRequestMessage: "GetVirtualSelectedParentBlueScoreRequest",
|
CmdGetVirtualSelectedParentBlueScoreRequestMessage: "GetVirtualSelectedParentBlueScoreRequest",
|
||||||
CmdGetVirtualSelectedParentBlueScoreResponseMessage: "GetVirtualSelectedParentBlueScoreResponse",
|
CmdGetVirtualSelectedParentBlueScoreResponseMessage: "GetVirtualSelectedParentBlueScoreResponse",
|
||||||
CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: "NotifyVirtualSelectedParentBlueScoreChangedRequest",
|
CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: "NotifyVirtualSelectedParentBlueScoreChangedRequest",
|
||||||
@ -283,31 +232,8 @@ var RPCMessageCommandToString = map[MessageCommand]string{
|
|||||||
CmdBanResponseMessage: "BanResponse",
|
CmdBanResponseMessage: "BanResponse",
|
||||||
CmdUnbanRequestMessage: "UnbanRequest",
|
CmdUnbanRequestMessage: "UnbanRequest",
|
||||||
CmdUnbanResponseMessage: "UnbanResponse",
|
CmdUnbanResponseMessage: "UnbanResponse",
|
||||||
CmdGetInfoRequestMessage: "GetInfoRequest",
|
CmdGetInfoRequestMessage: "GetInfoRequestMessage",
|
||||||
CmdGetInfoResponseMessage: "GeInfoResponse",
|
CmdGetInfoResponseMessage: "GeInfoResponseMessage",
|
||||||
CmdNotifyPruningPointUTXOSetOverrideRequestMessage: "NotifyPruningPointUTXOSetOverrideRequest",
|
|
||||||
CmdNotifyPruningPointUTXOSetOverrideResponseMessage: "NotifyPruningPointUTXOSetOverrideResponse",
|
|
||||||
CmdPruningPointUTXOSetOverrideNotificationMessage: "PruningPointUTXOSetOverrideNotification",
|
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage: "StopNotifyingPruningPointUTXOSetOverrideRequest",
|
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideResponseMessage: "StopNotifyingPruningPointUTXOSetOverrideResponse",
|
|
||||||
CmdEstimateNetworkHashesPerSecondRequestMessage: "EstimateNetworkHashesPerSecondRequest",
|
|
||||||
CmdEstimateNetworkHashesPerSecondResponseMessage: "EstimateNetworkHashesPerSecondResponse",
|
|
||||||
CmdNotifyVirtualDaaScoreChangedRequestMessage: "NotifyVirtualDaaScoreChangedRequest",
|
|
||||||
CmdNotifyVirtualDaaScoreChangedResponseMessage: "NotifyVirtualDaaScoreChangedResponse",
|
|
||||||
CmdVirtualDaaScoreChangedNotificationMessage: "VirtualDaaScoreChangedNotification",
|
|
||||||
CmdGetBalancesByAddressesRequestMessage: "GetBalancesByAddressesRequest",
|
|
||||||
CmdGetBalancesByAddressesResponseMessage: "GetBalancesByAddressesResponse",
|
|
||||||
CmdNotifyNewBlockTemplateRequestMessage: "NotifyNewBlockTemplateRequest",
|
|
||||||
CmdNotifyNewBlockTemplateResponseMessage: "NotifyNewBlockTemplateResponse",
|
|
||||||
CmdNewBlockTemplateNotificationMessage: "NewBlockTemplateNotification",
|
|
||||||
CmdGetMempoolEntriesByAddressesRequestMessage: "GetMempoolEntriesByAddressesRequest",
|
|
||||||
CmdGetMempoolEntriesByAddressesResponseMessage: "GetMempoolEntriesByAddressesResponse",
|
|
||||||
CmdGetCoinSupplyRequestMessage: "GetCoinSupplyRequest",
|
|
||||||
CmdGetCoinSupplyResponseMessage: "GetCoinSupplyResponse",
|
|
||||||
CmdGetFeeEstimateRequestMessage: "GetFeeEstimateRequest",
|
|
||||||
CmdGetFeeEstimateResponseMessage: "GetFeeEstimateResponse",
|
|
||||||
CmdSubmitTransactionReplacementRequestMessage: "SubmitTransactionReplacementRequest",
|
|
||||||
CmdSubmitTransactionReplacementResponseMessage: "SubmitTransactionReplacementResponse",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is an interface that describes a kaspa message. A type that
|
// Message is an interface that describes a kaspa message. A type that
|
||||||
|
@ -15,6 +15,19 @@ import (
|
|||||||
// backing array multiple times.
|
// backing array multiple times.
|
||||||
const defaultTransactionAlloc = 2048
|
const defaultTransactionAlloc = 2048
|
||||||
|
|
||||||
|
// MaxMassAcceptedByBlock is the maximum total transaction mass a block may accept.
|
||||||
|
const MaxMassAcceptedByBlock = 10000000
|
||||||
|
|
||||||
|
// MaxMassPerTx is the maximum total mass a transaction may have.
|
||||||
|
const MaxMassPerTx = MaxMassAcceptedByBlock / 2
|
||||||
|
|
||||||
|
// MaxTxPerBlock is the maximum number of transactions that could
|
||||||
|
// possibly fit into a block.
|
||||||
|
const MaxTxPerBlock = (MaxMassAcceptedByBlock / minTxPayload) + 1
|
||||||
|
|
||||||
|
// MaxBlockParents is the maximum allowed number of parents for block.
|
||||||
|
const MaxBlockParents = 10
|
||||||
|
|
||||||
// TxLoc holds locator data for the offset and length of where a transaction is
|
// TxLoc holds locator data for the offset and length of where a transaction is
|
||||||
// located within a MsgBlock data buffer.
|
// located within a MsgBlock data buffer.
|
||||||
type TxLoc struct {
|
type TxLoc struct {
|
||||||
|
@ -18,21 +18,16 @@ import (
|
|||||||
|
|
||||||
// TestBlock tests the MsgBlock API.
|
// TestBlock tests the MsgBlock API.
|
||||||
func TestBlock(t *testing.T) {
|
func TestBlock(t *testing.T) {
|
||||||
pver := uint32(4)
|
pver := ProtocolVersion
|
||||||
|
|
||||||
// Block 1 header.
|
// Block 1 header.
|
||||||
parents := blockOne.Header.Parents
|
parentHashes := blockOne.Header.ParentHashes
|
||||||
hashMerkleRoot := blockOne.Header.HashMerkleRoot
|
hashMerkleRoot := blockOne.Header.HashMerkleRoot
|
||||||
acceptedIDMerkleRoot := blockOne.Header.AcceptedIDMerkleRoot
|
acceptedIDMerkleRoot := blockOne.Header.AcceptedIDMerkleRoot
|
||||||
utxoCommitment := blockOne.Header.UTXOCommitment
|
utxoCommitment := blockOne.Header.UTXOCommitment
|
||||||
bits := blockOne.Header.Bits
|
bits := blockOne.Header.Bits
|
||||||
nonce := blockOne.Header.Nonce
|
nonce := blockOne.Header.Nonce
|
||||||
daaScore := blockOne.Header.DAAScore
|
bh := NewBlockHeader(1, parentHashes, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce)
|
||||||
blueScore := blockOne.Header.BlueScore
|
|
||||||
blueWork := blockOne.Header.BlueWork
|
|
||||||
pruningPoint := blockOne.Header.PruningPoint
|
|
||||||
bh := NewBlockHeader(1, parents, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce,
|
|
||||||
daaScore, blueScore, blueWork, pruningPoint)
|
|
||||||
|
|
||||||
// Ensure the command is expected value.
|
// Ensure the command is expected value.
|
||||||
wantCmd := MessageCommand(5)
|
wantCmd := MessageCommand(5)
|
||||||
@ -136,7 +131,7 @@ func TestConvertToPartial(t *testing.T) {
|
|||||||
var blockOne = MsgBlock{
|
var blockOne = MsgBlock{
|
||||||
Header: MsgBlockHeader{
|
Header: MsgBlockHeader{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
Parents: []externalapi.BlockLevelParents{[]*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}},
|
ParentHashes: []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash},
|
||||||
HashMerkleRoot: mainnetGenesisMerkleRoot,
|
HashMerkleRoot: mainnetGenesisMerkleRoot,
|
||||||
AcceptedIDMerkleRoot: exampleAcceptedIDMerkleRoot,
|
AcceptedIDMerkleRoot: exampleAcceptedIDMerkleRoot,
|
||||||
UTXOCommitment: exampleUTXOCommitment,
|
UTXOCommitment: exampleUTXOCommitment,
|
||||||
|
@ -5,12 +5,13 @@
|
|||||||
package appmessage
|
package appmessage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
"github.com/kaspanet/kaspad/util/mstime"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseBlockHeaderPayload is the base number of bytes a block header can be,
|
// BaseBlockHeaderPayload is the base number of bytes a block header can be,
|
||||||
@ -38,8 +39,8 @@ type MsgBlockHeader struct {
|
|||||||
// Version of the block. This is not the same as the protocol version.
|
// Version of the block. This is not the same as the protocol version.
|
||||||
Version uint16
|
Version uint16
|
||||||
|
|
||||||
// Parents are the parent block hashes of the block in the DAG per superblock level.
|
// Hashes of the parent block headers in the blockDAG.
|
||||||
Parents []externalapi.BlockLevelParents
|
ParentHashes []*externalapi.DomainHash
|
||||||
|
|
||||||
// HashMerkleRoot is the merkle tree reference to hash of all transactions for the block.
|
// HashMerkleRoot is the merkle tree reference to hash of all transactions for the block.
|
||||||
HashMerkleRoot *externalapi.DomainHash
|
HashMerkleRoot *externalapi.DomainHash
|
||||||
@ -59,16 +60,15 @@ type MsgBlockHeader struct {
|
|||||||
|
|
||||||
// Nonce used to generate the block.
|
// Nonce used to generate the block.
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
|
}
|
||||||
|
|
||||||
// DAASCore is the DAA score of the block.
|
// NumParentBlocks return the number of entries in ParentHashes
|
||||||
DAAScore uint64
|
func (h *MsgBlockHeader) NumParentBlocks() byte {
|
||||||
|
numParents := len(h.ParentHashes)
|
||||||
BlueScore uint64
|
if numParents > math.MaxUint8 {
|
||||||
|
panic(errors.Errorf("number of parents is %d, which is more than one byte can fit", numParents))
|
||||||
// BlueWork is the blue work of the block.
|
}
|
||||||
BlueWork *big.Int
|
return byte(numParents)
|
||||||
|
|
||||||
PruningPoint *externalapi.DomainHash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockHash computes the block identifier hash for the given block header.
|
// BlockHash computes the block identifier hash for the given block header.
|
||||||
@ -76,27 +76,33 @@ func (h *MsgBlockHeader) BlockHash() *externalapi.DomainHash {
|
|||||||
return consensushashing.HeaderHash(BlockHeaderToDomainBlockHeader(h))
|
return consensushashing.HeaderHash(BlockHeaderToDomainBlockHeader(h))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsGenesis returns true iff this block is a genesis block
|
||||||
|
func (h *MsgBlockHeader) IsGenesis() bool {
|
||||||
|
return h.NumParentBlocks() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the protocol command string for the message. This is part
|
||||||
|
// of the Message interface implementation.
|
||||||
|
func (h *MsgBlockHeader) Command() MessageCommand {
|
||||||
|
return CmdHeader
|
||||||
|
}
|
||||||
|
|
||||||
// NewBlockHeader returns a new MsgBlockHeader using the provided version, previous
|
// NewBlockHeader returns a new MsgBlockHeader using the provided version, previous
|
||||||
// block hash, hash merkle root, accepted ID merkle root, difficulty bits, and nonce used to generate the
|
// block hash, hash merkle root, accepted ID merkle root, difficulty bits, and nonce used to generate the
|
||||||
// block with defaults or calclulated values for the remaining fields.
|
// block with defaults or calclulated values for the remaining fields.
|
||||||
func NewBlockHeader(version uint16, parents []externalapi.BlockLevelParents, hashMerkleRoot *externalapi.DomainHash,
|
func NewBlockHeader(version uint16, parentHashes []*externalapi.DomainHash, hashMerkleRoot *externalapi.DomainHash,
|
||||||
acceptedIDMerkleRoot *externalapi.DomainHash, utxoCommitment *externalapi.DomainHash, bits uint32, nonce,
|
acceptedIDMerkleRoot *externalapi.DomainHash, utxoCommitment *externalapi.DomainHash, bits uint32, nonce uint64) *MsgBlockHeader {
|
||||||
daaScore, blueScore uint64, blueWork *big.Int, pruningPoint *externalapi.DomainHash) *MsgBlockHeader {
|
|
||||||
|
|
||||||
// Limit the timestamp to one millisecond precision since the protocol
|
// Limit the timestamp to one millisecond precision since the protocol
|
||||||
// doesn't support better.
|
// doesn't support better.
|
||||||
return &MsgBlockHeader{
|
return &MsgBlockHeader{
|
||||||
Version: version,
|
Version: version,
|
||||||
Parents: parents,
|
ParentHashes: parentHashes,
|
||||||
HashMerkleRoot: hashMerkleRoot,
|
HashMerkleRoot: hashMerkleRoot,
|
||||||
AcceptedIDMerkleRoot: acceptedIDMerkleRoot,
|
AcceptedIDMerkleRoot: acceptedIDMerkleRoot,
|
||||||
UTXOCommitment: utxoCommitment,
|
UTXOCommitment: utxoCommitment,
|
||||||
Timestamp: mstime.Now(),
|
Timestamp: mstime.Now(),
|
||||||
Bits: bits,
|
Bits: bits,
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
DAAScore: daaScore,
|
|
||||||
BlueScore: blueScore,
|
|
||||||
BlueWork: blueWork,
|
|
||||||
PruningPoint: pruningPoint,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,34 +5,33 @@
|
|||||||
package appmessage
|
package appmessage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/util/mstime"
|
||||||
|
"github.com/kaspanet/kaspad/util/random"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestBlockHeader tests the MsgBlockHeader API.
|
// TestBlockHeader tests the MsgBlockHeader API.
|
||||||
func TestBlockHeader(t *testing.T) {
|
func TestBlockHeader(t *testing.T) {
|
||||||
nonce := uint64(0xba4d87a69924a93d)
|
nonce, err := random.Uint64()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("random.Uint64: Error generating nonce: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
parents := []externalapi.BlockLevelParents{[]*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}}
|
hashes := []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}
|
||||||
|
|
||||||
merkleHash := mainnetGenesisMerkleRoot
|
merkleHash := mainnetGenesisMerkleRoot
|
||||||
acceptedIDMerkleRoot := exampleAcceptedIDMerkleRoot
|
acceptedIDMerkleRoot := exampleAcceptedIDMerkleRoot
|
||||||
bits := uint32(0x1d00ffff)
|
bits := uint32(0x1d00ffff)
|
||||||
daaScore := uint64(123)
|
bh := NewBlockHeader(1, hashes, merkleHash, acceptedIDMerkleRoot, exampleUTXOCommitment, bits, nonce)
|
||||||
blueScore := uint64(456)
|
|
||||||
blueWork := big.NewInt(789)
|
|
||||||
pruningPoint := simnetGenesisHash
|
|
||||||
bh := NewBlockHeader(1, parents, merkleHash, acceptedIDMerkleRoot, exampleUTXOCommitment, bits, nonce,
|
|
||||||
daaScore, blueScore, blueWork, pruningPoint)
|
|
||||||
|
|
||||||
// Ensure we get the same data back out.
|
// Ensure we get the same data back out.
|
||||||
if !reflect.DeepEqual(bh.Parents, parents) {
|
if !reflect.DeepEqual(bh.ParentHashes, hashes) {
|
||||||
t.Errorf("NewBlockHeader: wrong parents - got %v, want %v",
|
t.Errorf("NewBlockHeader: wrong prev hashes - got %v, want %v",
|
||||||
spew.Sprint(bh.Parents), spew.Sprint(parents))
|
spew.Sprint(bh.ParentHashes), spew.Sprint(hashes))
|
||||||
}
|
}
|
||||||
if bh.HashMerkleRoot != merkleHash {
|
if bh.HashMerkleRoot != merkleHash {
|
||||||
t.Errorf("NewBlockHeader: wrong merkle root - got %v, want %v",
|
t.Errorf("NewBlockHeader: wrong merkle root - got %v, want %v",
|
||||||
@ -46,20 +45,44 @@ func TestBlockHeader(t *testing.T) {
|
|||||||
t.Errorf("NewBlockHeader: wrong nonce - got %v, want %v",
|
t.Errorf("NewBlockHeader: wrong nonce - got %v, want %v",
|
||||||
bh.Nonce, nonce)
|
bh.Nonce, nonce)
|
||||||
}
|
}
|
||||||
if bh.DAAScore != daaScore {
|
|
||||||
t.Errorf("NewBlockHeader: wrong daaScore - got %v, want %v",
|
|
||||||
bh.DAAScore, daaScore)
|
|
||||||
}
|
}
|
||||||
if bh.BlueScore != blueScore {
|
|
||||||
t.Errorf("NewBlockHeader: wrong blueScore - got %v, want %v",
|
func TestIsGenesis(t *testing.T) {
|
||||||
bh.BlueScore, blueScore)
|
nonce := uint64(123123) // 0x1e0f3
|
||||||
|
bits := uint32(0x1d00ffff)
|
||||||
|
timestamp := mstime.UnixMilliseconds(0x495fab29000)
|
||||||
|
|
||||||
|
baseBlockHdr := &MsgBlockHeader{
|
||||||
|
Version: 1,
|
||||||
|
ParentHashes: []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash},
|
||||||
|
HashMerkleRoot: mainnetGenesisMerkleRoot,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Bits: bits,
|
||||||
|
Nonce: nonce,
|
||||||
}
|
}
|
||||||
if bh.BlueWork != blueWork {
|
genesisBlockHdr := &MsgBlockHeader{
|
||||||
t.Errorf("NewBlockHeader: wrong blueWork - got %v, want %v",
|
Version: 1,
|
||||||
bh.BlueWork, blueWork)
|
ParentHashes: []*externalapi.DomainHash{},
|
||||||
|
HashMerkleRoot: mainnetGenesisMerkleRoot,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Bits: bits,
|
||||||
|
Nonce: nonce,
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
in *MsgBlockHeader // Block header to encode
|
||||||
|
isGenesis bool // Expected result for call of .IsGenesis
|
||||||
|
}{
|
||||||
|
{genesisBlockHdr, true},
|
||||||
|
{baseBlockHdr, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Running %d tests", len(tests))
|
||||||
|
for i, test := range tests {
|
||||||
|
isGenesis := test.in.IsGenesis()
|
||||||
|
if isGenesis != test.isGenesis {
|
||||||
|
t.Errorf("MsgBlockHeader.IsGenesis: #%d got: %t, want: %t",
|
||||||
|
i, isGenesis, test.isGenesis)
|
||||||
}
|
}
|
||||||
if !bh.PruningPoint.Equal(pruningPoint) {
|
|
||||||
t.Errorf("NewBlockHeader: wrong pruningPoint - got %v, want %v",
|
|
||||||
bh.PruningPoint, pruningPoint)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MsgBlockWithTrustedData represents a kaspa BlockWithTrustedData message
|
|
||||||
type MsgBlockWithTrustedData struct {
|
|
||||||
baseMessage
|
|
||||||
|
|
||||||
Block *MsgBlock
|
|
||||||
DAAScore uint64
|
|
||||||
DAAWindow []*TrustedDataDataDAABlock
|
|
||||||
GHOSTDAGData []*BlockGHOSTDAGDataHashPair
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *MsgBlockWithTrustedData) Command() MessageCommand {
|
|
||||||
return CmdBlockWithTrustedData
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgBlockWithTrustedData returns a new MsgBlockWithTrustedData.
|
|
||||||
func NewMsgBlockWithTrustedData() *MsgBlockWithTrustedData {
|
|
||||||
return &MsgBlockWithTrustedData{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustedDataDataDAABlock is an appmessage representation of externalapi.TrustedDataDataDAABlock
|
|
||||||
type TrustedDataDataDAABlock struct {
|
|
||||||
Block *MsgBlock
|
|
||||||
GHOSTDAGData *BlockGHOSTDAGData
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockGHOSTDAGData is an appmessage representation of externalapi.BlockGHOSTDAGData
|
|
||||||
type BlockGHOSTDAGData struct {
|
|
||||||
BlueScore uint64
|
|
||||||
BlueWork *big.Int
|
|
||||||
SelectedParent *externalapi.DomainHash
|
|
||||||
MergeSetBlues []*externalapi.DomainHash
|
|
||||||
MergeSetReds []*externalapi.DomainHash
|
|
||||||
BluesAnticoneSizes []*BluesAnticoneSizes
|
|
||||||
}
|
|
||||||
|
|
||||||
// BluesAnticoneSizes is an appmessage representation of the BluesAnticoneSizes part of GHOSTDAG data.
|
|
||||||
type BluesAnticoneSizes struct {
|
|
||||||
BlueHash *externalapi.DomainHash
|
|
||||||
AnticoneSize externalapi.KType
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockGHOSTDAGDataHashPair is an appmessage representation of externalapi.BlockGHOSTDAGDataHashPair
|
|
||||||
type BlockGHOSTDAGDataHashPair struct {
|
|
||||||
Hash *externalapi.DomainHash
|
|
||||||
GHOSTDAGData *BlockGHOSTDAGData
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgBlockWithTrustedDataV4 represents a kaspa BlockWithTrustedDataV4 message
|
|
||||||
type MsgBlockWithTrustedDataV4 struct {
|
|
||||||
baseMessage
|
|
||||||
|
|
||||||
Block *MsgBlock
|
|
||||||
DAAWindowIndices []uint64
|
|
||||||
GHOSTDAGDataIndices []uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *MsgBlockWithTrustedDataV4) Command() MessageCommand {
|
|
||||||
return CmdBlockWithTrustedDataV4
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgBlockWithTrustedDataV4 returns a new MsgBlockWithTrustedDataV4.
|
|
||||||
func NewMsgBlockWithTrustedDataV4() *MsgBlockWithTrustedDataV4 {
|
|
||||||
return &MsgBlockWithTrustedDataV4{}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgDoneBlocksWithTrustedData implements the Message interface and represents a kaspa
|
|
||||||
// DoneBlocksWithTrustedData message
|
|
||||||
//
|
|
||||||
// This message has no payload.
|
|
||||||
type MsgDoneBlocksWithTrustedData struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message. This is part
|
|
||||||
// of the Message interface implementation.
|
|
||||||
func (msg *MsgDoneBlocksWithTrustedData) Command() MessageCommand {
|
|
||||||
return CmdDoneBlocksWithTrustedData
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgDoneBlocksWithTrustedData returns a new kaspa DoneBlocksWithTrustedData message that conforms to the
|
|
||||||
// Message interface.
|
|
||||||
func NewMsgDoneBlocksWithTrustedData() *MsgDoneBlocksWithTrustedData {
|
|
||||||
return &MsgDoneBlocksWithTrustedData{}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgRequestPruningPointAndItsAnticone represents a kaspa RequestPruningPointAndItsAnticone message
|
|
||||||
type MsgRequestPruningPointAndItsAnticone struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *MsgRequestPruningPointAndItsAnticone) Command() MessageCommand {
|
|
||||||
return CmdRequestPruningPointAndItsAnticone
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgRequestPruningPointAndItsAnticone returns a new MsgRequestPruningPointAndItsAnticone.
|
|
||||||
func NewMsgRequestPruningPointAndItsAnticone() *MsgRequestPruningPointAndItsAnticone {
|
|
||||||
return &MsgRequestPruningPointAndItsAnticone{}
|
|
||||||
}
|
|
65
app/appmessage/p2p_msgibdblock_test.go
Normal file
65
app/appmessage/p2p_msgibdblock_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) 2013-2016 The btcsuite developers
|
||||||
|
// Use of this source code is governed by an ISC
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package appmessage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestIBDBlock tests the MsgIBDBlock API.
|
||||||
|
func TestIBDBlock(t *testing.T) {
|
||||||
|
pver := ProtocolVersion
|
||||||
|
|
||||||
|
// Block 1 header.
|
||||||
|
parentHashes := blockOne.Header.ParentHashes
|
||||||
|
hashMerkleRoot := blockOne.Header.HashMerkleRoot
|
||||||
|
acceptedIDMerkleRoot := blockOne.Header.AcceptedIDMerkleRoot
|
||||||
|
utxoCommitment := blockOne.Header.UTXOCommitment
|
||||||
|
bits := blockOne.Header.Bits
|
||||||
|
nonce := blockOne.Header.Nonce
|
||||||
|
bh := NewBlockHeader(1, parentHashes, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce)
|
||||||
|
|
||||||
|
// Ensure the command is expected value.
|
||||||
|
wantCmd := MessageCommand(15)
|
||||||
|
msg := NewMsgIBDBlock(NewMsgBlock(bh))
|
||||||
|
if cmd := msg.Command(); cmd != wantCmd {
|
||||||
|
t.Errorf("NewMsgIBDBlock: wrong command - got %v want %v",
|
||||||
|
cmd, wantCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure max payload is expected value for latest protocol version.
|
||||||
|
wantPayload := uint32(1024 * 1024 * 32)
|
||||||
|
maxPayload := msg.MaxPayloadLength(pver)
|
||||||
|
if maxPayload != wantPayload {
|
||||||
|
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
||||||
|
"protocol version %d - got %v, want %v", pver,
|
||||||
|
maxPayload, wantPayload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we get the same block header data back out.
|
||||||
|
if !reflect.DeepEqual(&msg.Header, bh) {
|
||||||
|
t.Errorf("NewMsgIBDBlock: wrong block header - got %v, want %v",
|
||||||
|
spew.Sdump(&msg.Header), spew.Sdump(bh))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure transactions are added properly.
|
||||||
|
tx := blockOne.Transactions[0].Copy()
|
||||||
|
msg.AddTransaction(tx)
|
||||||
|
if !reflect.DeepEqual(msg.Transactions, blockOne.Transactions) {
|
||||||
|
t.Errorf("AddTransaction: wrong transactions - got %v, want %v",
|
||||||
|
spew.Sdump(msg.Transactions),
|
||||||
|
spew.Sdump(blockOne.Transactions))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure transactions are properly cleared.
|
||||||
|
msg.ClearTransactions()
|
||||||
|
if len(msg.Transactions) != 0 {
|
||||||
|
t.Errorf("ClearTransactions: wrong transactions - got %v, want %v",
|
||||||
|
len(msg.Transactions), 0)
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MsgIBDChainBlockLocator implements the Message interface and represents a kaspa
|
|
||||||
// locator message. It is used to find the blockLocator of a peer that is
|
|
||||||
// syncing with you.
|
|
||||||
type MsgIBDChainBlockLocator struct {
|
|
||||||
baseMessage
|
|
||||||
BlockLocatorHashes []*externalapi.DomainHash
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message. This is part
|
|
||||||
// of the Message interface implementation.
|
|
||||||
func (msg *MsgIBDChainBlockLocator) Command() MessageCommand {
|
|
||||||
return CmdIBDChainBlockLocator
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgIBDChainBlockLocator returns a new kaspa locator message that conforms to
|
|
||||||
// the Message interface. See MsgBlockLocator for details.
|
|
||||||
func NewMsgIBDChainBlockLocator(locatorHashes []*externalapi.DomainHash) *MsgIBDChainBlockLocator {
|
|
||||||
return &MsgIBDChainBlockLocator{
|
|
||||||
BlockLocatorHashes: locatorHashes,
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,12 +6,17 @@ package appmessage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/util/random"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestPing tests the MsgPing API against the latest protocol version.
|
// TestPing tests the MsgPing API against the latest protocol version.
|
||||||
func TestPing(t *testing.T) {
|
func TestPing(t *testing.T) {
|
||||||
// Ensure we get the same nonce back out.
|
// Ensure we get the same nonce back out.
|
||||||
nonce := uint64(0x61c2c5535902862)
|
nonce, err := random.Uint64()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("random.Uint64: Error generating nonce: %v", err)
|
||||||
|
}
|
||||||
msg := NewMsgPing(nonce)
|
msg := NewMsgPing(nonce)
|
||||||
if msg.Nonce != nonce {
|
if msg.Nonce != nonce {
|
||||||
t.Errorf("NewMsgPing: wrong nonce - got %v, want %v",
|
t.Errorf("NewMsgPing: wrong nonce - got %v, want %v",
|
||||||
|
@ -6,11 +6,16 @@ package appmessage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/util/random"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestPongLatest tests the MsgPong API against the latest protocol version.
|
// TestPongLatest tests the MsgPong API against the latest protocol version.
|
||||||
func TestPongLatest(t *testing.T) {
|
func TestPongLatest(t *testing.T) {
|
||||||
nonce := uint64(0x1a05b581a5182c)
|
nonce, err := random.Uint64()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("random.Uint64: error generating nonce: %v", err)
|
||||||
|
}
|
||||||
msg := NewMsgPong(nonce)
|
msg := NewMsgPong(nonce)
|
||||||
if msg.Nonce != nonce {
|
if msg.Nonce != nonce {
|
||||||
t.Errorf("NewMsgPong: wrong nonce - got %v, want %v",
|
t.Errorf("NewMsgPong: wrong nonce - got %v, want %v",
|
||||||
|
23
app/appmessage/p2p_msgpruningpointhash.go
Normal file
23
app/appmessage/p2p_msgpruningpointhash.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package appmessage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MsgPruningPointHashMessage represents a kaspa PruningPointHash message
|
||||||
|
type MsgPruningPointHashMessage struct {
|
||||||
|
baseMessage
|
||||||
|
Hash *externalapi.DomainHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the protocol command string for the message
|
||||||
|
func (msg *MsgPruningPointHashMessage) Command() MessageCommand {
|
||||||
|
return CmdPruningPointHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPruningPointHashMessage returns a new kaspa PruningPointHash message
|
||||||
|
func NewPruningPointHashMessage(hash *externalapi.DomainHash) *MsgPruningPointHashMessage {
|
||||||
|
return &MsgPruningPointHashMessage{
|
||||||
|
Hash: hash,
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgPruningPointProof represents a kaspa PruningPointProof message
|
|
||||||
type MsgPruningPointProof struct {
|
|
||||||
baseMessage
|
|
||||||
|
|
||||||
Headers [][]*MsgBlockHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *MsgPruningPointProof) Command() MessageCommand {
|
|
||||||
return CmdPruningPointProof
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgPruningPointProof returns a new MsgPruningPointProof.
|
|
||||||
func NewMsgPruningPointProof(headers [][]*MsgBlockHeader) *MsgPruningPointProof {
|
|
||||||
return &MsgPruningPointProof{
|
|
||||||
Headers: headers,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgPruningPoints represents a kaspa PruningPoints message
|
|
||||||
type MsgPruningPoints struct {
|
|
||||||
baseMessage
|
|
||||||
|
|
||||||
Headers []*MsgBlockHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *MsgPruningPoints) Command() MessageCommand {
|
|
||||||
return CmdPruningPoints
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgPruningPoints returns a new MsgPruningPoints.
|
|
||||||
func NewMsgPruningPoints(headers []*MsgBlockHeader) *MsgPruningPoints {
|
|
||||||
return &MsgPruningPoints{
|
|
||||||
Headers: headers,
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,6 +31,6 @@ type OutpointAndUTXOEntryPair struct {
|
|||||||
type UTXOEntry struct {
|
type UTXOEntry struct {
|
||||||
Amount uint64
|
Amount uint64
|
||||||
ScriptPublicKey *externalapi.ScriptPublicKey
|
ScriptPublicKey *externalapi.ScriptPublicKey
|
||||||
BlockDAAScore uint64
|
BlockBlueScore uint64
|
||||||
IsCoinbase bool
|
IsCoinbase bool
|
||||||
}
|
}
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
// Copyright (c) 2013-2016 The btcsuite developers
|
|
||||||
// Use of this source code is governed by an ISC
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package appmessage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MsgRequestAnticone implements the Message interface and represents a kaspa
|
|
||||||
// RequestHeaders message. It is used to request the set past(ContextHash) \cap anticone(BlockHash)
|
|
||||||
type MsgRequestAnticone struct {
|
|
||||||
baseMessage
|
|
||||||
BlockHash *externalapi.DomainHash
|
|
||||||
ContextHash *externalapi.DomainHash
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message. This is part
|
|
||||||
// of the Message interface implementation.
|
|
||||||
func (msg *MsgRequestAnticone) Command() MessageCommand {
|
|
||||||
return CmdRequestAnticone
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgRequestAnticone returns a new kaspa RequestPastDiff message that conforms to the
|
|
||||||
// Message interface using the passed parameters and defaults for the remaining
|
|
||||||
// fields.
|
|
||||||
func NewMsgRequestAnticone(blockHash, contextHash *externalapi.DomainHash) *MsgRequestAnticone {
|
|
||||||
return &MsgRequestAnticone{
|
|
||||||
BlockHash: blockHash,
|
|
||||||
ContextHash: contextHash,
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,6 +10,7 @@ import (
|
|||||||
// The locator is returned via a locator message (MsgBlockLocator).
|
// The locator is returned via a locator message (MsgBlockLocator).
|
||||||
type MsgRequestBlockLocator struct {
|
type MsgRequestBlockLocator struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
|
LowHash *externalapi.DomainHash
|
||||||
HighHash *externalapi.DomainHash
|
HighHash *externalapi.DomainHash
|
||||||
Limit uint32
|
Limit uint32
|
||||||
}
|
}
|
||||||
@ -23,8 +24,9 @@ func (msg *MsgRequestBlockLocator) Command() MessageCommand {
|
|||||||
// NewMsgRequestBlockLocator returns a new RequestBlockLocator message that conforms to the
|
// NewMsgRequestBlockLocator returns a new RequestBlockLocator message that conforms to the
|
||||||
// Message interface using the passed parameters and defaults for the remaining
|
// Message interface using the passed parameters and defaults for the remaining
|
||||||
// fields.
|
// fields.
|
||||||
func NewMsgRequestBlockLocator(highHash *externalapi.DomainHash, limit uint32) *MsgRequestBlockLocator {
|
func NewMsgRequestBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) *MsgRequestBlockLocator {
|
||||||
return &MsgRequestBlockLocator{
|
return &MsgRequestBlockLocator{
|
||||||
|
LowHash: lowHash,
|
||||||
HighHash: highHash,
|
HighHash: highHash,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ func TestRequestBlockLocator(t *testing.T) {
|
|||||||
|
|
||||||
// Ensure the command is expected value.
|
// Ensure the command is expected value.
|
||||||
wantCmd := MessageCommand(9)
|
wantCmd := MessageCommand(9)
|
||||||
msg := NewMsgRequestBlockLocator(highHash, 0)
|
msg := NewMsgRequestBlockLocator(highHash, &externalapi.DomainHash{}, 0)
|
||||||
if cmd := msg.Command(); cmd != wantCmd {
|
if cmd := msg.Command(); cmd != wantCmd {
|
||||||
t.Errorf("NewMsgRequestBlockLocator: wrong command - got %v want %v",
|
t.Errorf("NewMsgRequestBlockLocator: wrong command - got %v want %v",
|
||||||
cmd, wantCmd)
|
cmd, wantCmd)
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestRequstIBDBlocks tests the MsgRequestIBDBlocks API.
|
// TestRequstIBDBlocks tests the MsgRequestHeaders API.
|
||||||
func TestRequstIBDBlocks(t *testing.T) {
|
func TestRequstIBDBlocks(t *testing.T) {
|
||||||
hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0"
|
hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0"
|
||||||
lowHash, err := externalapi.NewDomainHashFromString(hashStr)
|
lowHash, err := externalapi.NewDomainHashFromString(hashStr)
|
||||||
@ -27,14 +27,14 @@ func TestRequstIBDBlocks(t *testing.T) {
|
|||||||
// Ensure we get the same data back out.
|
// Ensure we get the same data back out.
|
||||||
msg := NewMsgRequstHeaders(lowHash, highHash)
|
msg := NewMsgRequstHeaders(lowHash, highHash)
|
||||||
if !msg.HighHash.Equal(highHash) {
|
if !msg.HighHash.Equal(highHash) {
|
||||||
t.Errorf("NewMsgRequstIBDBlocks: wrong high hash - got %v, want %v",
|
t.Errorf("NewMsgRequstHeaders: wrong high hash - got %v, want %v",
|
||||||
msg.HighHash, highHash)
|
msg.HighHash, highHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the command is expected value.
|
// Ensure the command is expected value.
|
||||||
wantCmd := MessageCommand(4)
|
wantCmd := MessageCommand(4)
|
||||||
if cmd := msg.Command(); cmd != wantCmd {
|
if cmd := msg.Command(); cmd != wantCmd {
|
||||||
t.Errorf("NewMsgRequstIBDBlocks: wrong command - got %v want %v",
|
t.Errorf("NewMsgRequstHeaders: wrong command - got %v want %v",
|
||||||
cmd, wantCmd)
|
cmd, wantCmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MsgRequestIBDChainBlockLocator implements the Message interface and represents a kaspa
|
|
||||||
// IBDRequestChainBlockLocator message. It is used to request a block locator between low
|
|
||||||
// and high hash.
|
|
||||||
// The locator is returned via a locator message (MsgIBDChainBlockLocator).
|
|
||||||
type MsgRequestIBDChainBlockLocator struct {
|
|
||||||
baseMessage
|
|
||||||
HighHash *externalapi.DomainHash
|
|
||||||
LowHash *externalapi.DomainHash
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message. This is part
|
|
||||||
// of the Message interface implementation.
|
|
||||||
func (msg *MsgRequestIBDChainBlockLocator) Command() MessageCommand {
|
|
||||||
return CmdRequestIBDChainBlockLocator
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgIBDRequestChainBlockLocator returns a new IBDRequestChainBlockLocator message that conforms to the
|
|
||||||
// Message interface using the passed parameters and defaults for the remaining
|
|
||||||
// fields.
|
|
||||||
func NewMsgIBDRequestChainBlockLocator(highHash, lowHash *externalapi.DomainHash) *MsgRequestIBDChainBlockLocator {
|
|
||||||
return &MsgRequestIBDChainBlockLocator{
|
|
||||||
HighHash: highHash,
|
|
||||||
LowHash: lowHash,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgRequestNextPruningPointAndItsAnticoneBlocks implements the Message interface and represents a kaspa
|
|
||||||
// RequestNextPruningPointAndItsAnticoneBlocks message. It is used to notify the IBD syncer peer to send
|
|
||||||
// more blocks from the pruning anticone.
|
|
||||||
//
|
|
||||||
// This message has no payload.
|
|
||||||
type MsgRequestNextPruningPointAndItsAnticoneBlocks struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message. This is part
|
|
||||||
// of the Message interface implementation.
|
|
||||||
func (msg *MsgRequestNextPruningPointAndItsAnticoneBlocks) Command() MessageCommand {
|
|
||||||
return CmdRequestNextPruningPointAndItsAnticoneBlocks
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgRequestNextPruningPointAndItsAnticoneBlocks returns a new kaspa RequestNextPruningPointAndItsAnticoneBlocks message that conforms to the
|
|
||||||
// Message interface.
|
|
||||||
func NewMsgRequestNextPruningPointAndItsAnticoneBlocks() *MsgRequestNextPruningPointAndItsAnticoneBlocks {
|
|
||||||
return &MsgRequestNextPruningPointAndItsAnticoneBlocks{}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgRequestPruningPointProof represents a kaspa RequestPruningPointProof message
|
|
||||||
type MsgRequestPruningPointProof struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *MsgRequestPruningPointProof) Command() MessageCommand {
|
|
||||||
return CmdRequestPruningPointProof
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgRequestPruningPointProof returns a new MsgRequestPruningPointProof.
|
|
||||||
func NewMsgRequestPruningPointProof() *MsgRequestPruningPointProof {
|
|
||||||
return &MsgRequestPruningPointProof{}
|
|
||||||
}
|
|
@ -4,20 +4,20 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgRequestPruningPointUTXOSet represents a kaspa RequestPruningPointUTXOSet message
|
// MsgRequestPruningPointUTXOSetAndBlock represents a kaspa RequestPruningPointUTXOSetAndBlock message
|
||||||
type MsgRequestPruningPointUTXOSet struct {
|
type MsgRequestPruningPointUTXOSetAndBlock struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
PruningPointHash *externalapi.DomainHash
|
PruningPointHash *externalapi.DomainHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
func (msg *MsgRequestPruningPointUTXOSet) Command() MessageCommand {
|
func (msg *MsgRequestPruningPointUTXOSetAndBlock) Command() MessageCommand {
|
||||||
return CmdRequestPruningPointUTXOSet
|
return CmdRequestPruningPointUTXOSetAndBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMsgRequestPruningPointUTXOSet returns a new MsgRequestPruningPointUTXOSet
|
// NewMsgRequestPruningPointUTXOSetAndBlock returns a new MsgRequestPruningPointUTXOSetAndBlock
|
||||||
func NewMsgRequestPruningPointUTXOSet(pruningPointHash *externalapi.DomainHash) *MsgRequestPruningPointUTXOSet {
|
func NewMsgRequestPruningPointUTXOSetAndBlock(pruningPointHash *externalapi.DomainHash) *MsgRequestPruningPointUTXOSetAndBlock {
|
||||||
return &MsgRequestPruningPointUTXOSet{
|
return &MsgRequestPruningPointUTXOSetAndBlock{
|
||||||
PruningPointHash: pruningPointHash,
|
PruningPointHash: pruningPointHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgTrustedData represents a kaspa TrustedData message
|
|
||||||
type MsgTrustedData struct {
|
|
||||||
baseMessage
|
|
||||||
|
|
||||||
DAAWindow []*TrustedDataDAAHeader
|
|
||||||
GHOSTDAGData []*BlockGHOSTDAGDataHashPair
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *MsgTrustedData) Command() MessageCommand {
|
|
||||||
return CmdTrustedData
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgTrustedData returns a new MsgTrustedData.
|
|
||||||
func NewMsgTrustedData() *MsgTrustedData {
|
|
||||||
return &MsgTrustedData{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustedDataDAAHeader is an appmessage representation of externalapi.TrustedDataDataDAAHeader
|
|
||||||
type TrustedDataDAAHeader struct {
|
|
||||||
Header *MsgBlockHeader
|
|
||||||
GHOSTDAGData *BlockGHOSTDAGData
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ package appmessage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
@ -90,18 +91,16 @@ type TxIn struct {
|
|||||||
PreviousOutpoint Outpoint
|
PreviousOutpoint Outpoint
|
||||||
SignatureScript []byte
|
SignatureScript []byte
|
||||||
Sequence uint64
|
Sequence uint64
|
||||||
SigOpCount byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTxIn returns a new kaspa transaction input with the provided
|
// NewTxIn returns a new kaspa transaction input with the provided
|
||||||
// previous outpoint point and signature script with a default sequence of
|
// previous outpoint point and signature script with a default sequence of
|
||||||
// MaxTxInSequenceNum.
|
// MaxTxInSequenceNum.
|
||||||
func NewTxIn(prevOut *Outpoint, signatureScript []byte, sequence uint64, sigOpCount byte) *TxIn {
|
func NewTxIn(prevOut *Outpoint, signatureScript []byte, sequence uint64) *TxIn {
|
||||||
return &TxIn{
|
return &TxIn{
|
||||||
PreviousOutpoint: *prevOut,
|
PreviousOutpoint: *prevOut,
|
||||||
SignatureScript: signatureScript,
|
SignatureScript: signatureScript,
|
||||||
Sequence: sequence,
|
Sequence: sequence,
|
||||||
SigOpCount: sigOpCount,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +133,7 @@ type MsgTx struct {
|
|||||||
LockTime uint64
|
LockTime uint64
|
||||||
SubnetworkID externalapi.DomainSubnetworkID
|
SubnetworkID externalapi.DomainSubnetworkID
|
||||||
Gas uint64
|
Gas uint64
|
||||||
|
PayloadHash externalapi.DomainHash
|
||||||
Payload []byte
|
Payload []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +179,7 @@ func (msg *MsgTx) Copy() *MsgTx {
|
|||||||
LockTime: msg.LockTime,
|
LockTime: msg.LockTime,
|
||||||
SubnetworkID: msg.SubnetworkID,
|
SubnetworkID: msg.SubnetworkID,
|
||||||
Gas: msg.Gas,
|
Gas: msg.Gas,
|
||||||
|
PayloadHash: msg.PayloadHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.Payload != nil {
|
if msg.Payload != nil {
|
||||||
@ -208,7 +209,6 @@ func (msg *MsgTx) Copy() *MsgTx {
|
|||||||
PreviousOutpoint: newOutpoint,
|
PreviousOutpoint: newOutpoint,
|
||||||
SignatureScript: newScript,
|
SignatureScript: newScript,
|
||||||
Sequence: oldTxIn.Sequence,
|
Sequence: oldTxIn.Sequence,
|
||||||
SigOpCount: oldTxIn.SigOpCount,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, append this fully copied txin.
|
// Finally, append this fully copied txin.
|
||||||
@ -280,12 +280,18 @@ func newMsgTx(version uint16, txIn []*TxIn, txOut []*TxOut, subnetworkID *extern
|
|||||||
txOut = make([]*TxOut, 0, defaultTxInOutAlloc)
|
txOut = make([]*TxOut, 0, defaultTxInOutAlloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var payloadHash externalapi.DomainHash
|
||||||
|
if *subnetworkID != subnetworks.SubnetworkIDNative {
|
||||||
|
payloadHash = *hashes.PayloadHash(payload)
|
||||||
|
}
|
||||||
|
|
||||||
return &MsgTx{
|
return &MsgTx{
|
||||||
Version: version,
|
Version: version,
|
||||||
TxIn: txIn,
|
TxIn: txIn,
|
||||||
TxOut: txOut,
|
TxOut: txOut,
|
||||||
SubnetworkID: *subnetworkID,
|
SubnetworkID: *subnetworkID,
|
||||||
Gas: gas,
|
Gas: gas,
|
||||||
|
PayloadHash: payloadHash,
|
||||||
Payload: payload,
|
Payload: payload,
|
||||||
LockTime: lockTime,
|
LockTime: lockTime,
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
|
|
||||||
// TestTx tests the MsgTx API.
|
// TestTx tests the MsgTx API.
|
||||||
func TestTx(t *testing.T) {
|
func TestTx(t *testing.T) {
|
||||||
pver := uint32(4)
|
pver := ProtocolVersion
|
||||||
|
|
||||||
txIDStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
|
txIDStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
|
||||||
txID, err := transactionid.FromString(txIDStr)
|
txID, err := transactionid.FromString(txIDStr)
|
||||||
@ -68,7 +68,7 @@ func TestTx(t *testing.T) {
|
|||||||
|
|
||||||
// Ensure we get the same transaction input back out.
|
// Ensure we get the same transaction input back out.
|
||||||
sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62}
|
sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62}
|
||||||
txIn := NewTxIn(prevOut, sigScript, constants.MaxTxInSequenceNum, 1)
|
txIn := NewTxIn(prevOut, sigScript, constants.MaxTxInSequenceNum)
|
||||||
if !reflect.DeepEqual(&txIn.PreviousOutpoint, prevOut) {
|
if !reflect.DeepEqual(&txIn.PreviousOutpoint, prevOut) {
|
||||||
t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v",
|
t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v",
|
||||||
spew.Sprint(&txIn.PreviousOutpoint),
|
spew.Sprint(&txIn.PreviousOutpoint),
|
||||||
@ -133,8 +133,8 @@ func TestTx(t *testing.T) {
|
|||||||
|
|
||||||
// TestTxHash tests the ability to generate the hash of a transaction accurately.
|
// TestTxHash tests the ability to generate the hash of a transaction accurately.
|
||||||
func TestTxHashAndID(t *testing.T) {
|
func TestTxHashAndID(t *testing.T) {
|
||||||
txHash1Str := "b06f8b650115b5cf4d59499e10764a9312742930cb43c9b4ff6495d76f332ed7"
|
txHash1Str := "4bee9ee495bd93a755de428376bd582a2bb6ec37c041753b711c0606d5745c13"
|
||||||
txID1Str := "e20225c3d065ee41743607ee627db44d01ef396dc9779b05b2caf55bac50e12d"
|
txID1Str := "f868bd20e816256b80eac976821be4589d24d21141bd1cec6e8005d0c16c6881"
|
||||||
wantTxID1, err := transactionid.FromString(txID1Str)
|
wantTxID1, err := transactionid.FromString(txID1Str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewTxIDFromStr: %v", err)
|
t.Fatalf("NewTxIDFromStr: %v", err)
|
||||||
@ -185,14 +185,14 @@ func TestTxHashAndID(t *testing.T) {
|
|||||||
spew.Sprint(tx1ID), spew.Sprint(wantTxID1))
|
spew.Sprint(tx1ID), spew.Sprint(wantTxID1))
|
||||||
}
|
}
|
||||||
|
|
||||||
hash2Str := "fa16a8ce88d52ca1ff45187bbba0d33044e9f5fe309e8d0b22d4812dcf1782b7"
|
hash2Str := "cb1bdb4a83d4885535fb3cceb5c96597b7df903db83f0ffcd779d703affd8efd"
|
||||||
wantHash2, err := externalapi.NewDomainHashFromString(hash2Str)
|
wantHash2, err := externalapi.NewDomainHashFromString(hash2Str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("NewTxIDFromStr: %v", err)
|
t.Errorf("NewTxIDFromStr: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id2Str := "89ffb49474637502d9059af38b8a95fc2f0d3baef5c801d7a9b9c8830671b711"
|
id2Str := "ca080073d4ddf5b84443a0964af633f3c70a5b290fd3bc35a7e6f93fd33f9330"
|
||||||
wantID2, err := transactionid.FromString(id2Str)
|
wantID2, err := transactionid.FromString(id2Str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("NewTxIDFromStr: %v", err)
|
t.Errorf("NewTxIDFromStr: %v", err)
|
||||||
|
@ -82,12 +82,12 @@ func (msg *MsgVersion) Command() MessageCommand {
|
|||||||
// Message interface using the passed parameters and defaults for the remaining
|
// Message interface using the passed parameters and defaults for the remaining
|
||||||
// fields.
|
// fields.
|
||||||
func NewMsgVersion(addr *NetAddress, id *id.ID, network string,
|
func NewMsgVersion(addr *NetAddress, id *id.ID, network string,
|
||||||
subnetworkID *externalapi.DomainSubnetworkID, protocolVersion uint32) *MsgVersion {
|
subnetworkID *externalapi.DomainSubnetworkID) *MsgVersion {
|
||||||
|
|
||||||
// Limit the timestamp to one millisecond precision since the protocol
|
// Limit the timestamp to one millisecond precision since the protocol
|
||||||
// doesn't support better.
|
// doesn't support better.
|
||||||
return &MsgVersion{
|
return &MsgVersion{
|
||||||
ProtocolVersion: protocolVersion,
|
ProtocolVersion: ProtocolVersion,
|
||||||
Network: network,
|
Network: network,
|
||||||
Services: 0,
|
Services: 0,
|
||||||
Timestamp: mstime.Now(),
|
Timestamp: mstime.Now(),
|
||||||
|
@ -15,18 +15,18 @@ import (
|
|||||||
|
|
||||||
// TestVersion tests the MsgVersion API.
|
// TestVersion tests the MsgVersion API.
|
||||||
func TestVersion(t *testing.T) {
|
func TestVersion(t *testing.T) {
|
||||||
pver := uint32(4)
|
pver := ProtocolVersion
|
||||||
|
|
||||||
// Create version message data.
|
// Create version message data.
|
||||||
tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 16111}
|
tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 16111}
|
||||||
me := NewNetAddress(tcpAddrMe)
|
me := NewNetAddress(tcpAddrMe, SFNodeNetwork)
|
||||||
generatedID, err := id.GenerateID()
|
generatedID, err := id.GenerateID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("id.GenerateID: %s", err)
|
t.Fatalf("id.GenerateID: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we get the correct data back out.
|
// Ensure we get the correct data back out.
|
||||||
msg := NewMsgVersion(me, generatedID, "mainnet", nil, 4)
|
msg := NewMsgVersion(me, generatedID, "mainnet", nil)
|
||||||
if msg.ProtocolVersion != pver {
|
if msg.ProtocolVersion != pver {
|
||||||
t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v",
|
t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v",
|
||||||
msg.ProtocolVersion, pver)
|
msg.ProtocolVersion, pver)
|
||||||
|
@ -5,9 +5,8 @@
|
|||||||
package appmessage
|
package appmessage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
"github.com/kaspanet/kaspad/util/mstime"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetAddress defines information about a peer on the network including the time
|
// NetAddress defines information about a peer on the network including the time
|
||||||
@ -16,6 +15,9 @@ type NetAddress struct {
|
|||||||
// Last time the address was seen.
|
// Last time the address was seen.
|
||||||
Timestamp mstime.Time
|
Timestamp mstime.Time
|
||||||
|
|
||||||
|
// Bitfield which identifies the services supported by the address.
|
||||||
|
Services ServiceFlag
|
||||||
|
|
||||||
// IP address of the peer.
|
// IP address of the peer.
|
||||||
IP net.IP
|
IP net.IP
|
||||||
|
|
||||||
@ -24,6 +26,17 @@ type NetAddress struct {
|
|||||||
Port uint16
|
Port uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasService returns whether the specified service is supported by the address.
|
||||||
|
func (na *NetAddress) HasService(service ServiceFlag) bool {
|
||||||
|
return na.Services&service == service
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddService adds service as a supported service by the peer generating the
|
||||||
|
// message.
|
||||||
|
func (na *NetAddress) AddService(service ServiceFlag) {
|
||||||
|
na.Services |= service
|
||||||
|
}
|
||||||
|
|
||||||
// TCPAddress converts the NetAddress to *net.TCPAddr
|
// TCPAddress converts the NetAddress to *net.TCPAddr
|
||||||
func (na *NetAddress) TCPAddress() *net.TCPAddr {
|
func (na *NetAddress) TCPAddress() *net.TCPAddr {
|
||||||
return &net.TCPAddr{
|
return &net.TCPAddr{
|
||||||
@ -34,19 +47,20 @@ func (na *NetAddress) TCPAddress() *net.TCPAddr {
|
|||||||
|
|
||||||
// NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
|
// NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
|
||||||
// supported services with defaults for the remaining fields.
|
// supported services with defaults for the remaining fields.
|
||||||
func NewNetAddressIPPort(ip net.IP, port uint16) *NetAddress {
|
func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
|
||||||
return NewNetAddressTimestamp(mstime.Now(), ip, port)
|
return NewNetAddressTimestamp(mstime.Now(), services, ip, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNetAddressTimestamp returns a new NetAddress using the provided
|
// NewNetAddressTimestamp returns a new NetAddress using the provided
|
||||||
// timestamp, IP, port, and supported services. The timestamp is rounded to
|
// timestamp, IP, port, and supported services. The timestamp is rounded to
|
||||||
// single millisecond precision.
|
// single millisecond precision.
|
||||||
func NewNetAddressTimestamp(
|
func NewNetAddressTimestamp(
|
||||||
timestamp mstime.Time, ip net.IP, port uint16) *NetAddress {
|
timestamp mstime.Time, services ServiceFlag, ip net.IP, port uint16) *NetAddress {
|
||||||
// Limit the timestamp to one millisecond precision since the protocol
|
// Limit the timestamp to one millisecond precision since the protocol
|
||||||
// doesn't support better.
|
// doesn't support better.
|
||||||
na := NetAddress{
|
na := NetAddress{
|
||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
|
Services: services,
|
||||||
IP: ip,
|
IP: ip,
|
||||||
Port: port,
|
Port: port,
|
||||||
}
|
}
|
||||||
@ -55,10 +69,6 @@ func NewNetAddressTimestamp(
|
|||||||
|
|
||||||
// NewNetAddress returns a new NetAddress using the provided TCP address and
|
// NewNetAddress returns a new NetAddress using the provided TCP address and
|
||||||
// supported services with defaults for the remaining fields.
|
// supported services with defaults for the remaining fields.
|
||||||
func NewNetAddress(addr *net.TCPAddr) *NetAddress {
|
func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress {
|
||||||
return NewNetAddressIPPort(addr.IP, uint16(addr.Port))
|
return NewNetAddressIPPort(addr.IP, uint16(addr.Port), services)
|
||||||
}
|
|
||||||
|
|
||||||
func (na NetAddress) String() string {
|
|
||||||
return na.TCPAddress().String()
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ func TestNetAddress(t *testing.T) {
|
|||||||
port := 16111
|
port := 16111
|
||||||
|
|
||||||
// Test NewNetAddress.
|
// Test NewNetAddress.
|
||||||
na := NewNetAddress(&net.TCPAddr{IP: ip, Port: port})
|
na := NewNetAddress(&net.TCPAddr{IP: ip, Port: port}, 0)
|
||||||
|
|
||||||
// Ensure we get the same ip, port, and services back out.
|
// Ensure we get the same ip, port, and services back out.
|
||||||
if !na.IP.Equal(ip) {
|
if !na.IP.Equal(ip) {
|
||||||
@ -25,4 +25,21 @@ func TestNetAddress(t *testing.T) {
|
|||||||
t.Errorf("NetNetAddress: wrong port - got %v, want %v", na.Port,
|
t.Errorf("NetNetAddress: wrong port - got %v, want %v", na.Port,
|
||||||
port)
|
port)
|
||||||
}
|
}
|
||||||
|
if na.Services != 0 {
|
||||||
|
t.Errorf("NetNetAddress: wrong services - got %v, want %v",
|
||||||
|
na.Services, 0)
|
||||||
|
}
|
||||||
|
if na.HasService(SFNodeNetwork) {
|
||||||
|
t.Errorf("HasService: SFNodeNetwork service is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure adding the full service node flag works.
|
||||||
|
na.AddService(SFNodeNetwork)
|
||||||
|
if na.Services != SFNodeNetwork {
|
||||||
|
t.Errorf("AddService: wrong services - got %v, want %v",
|
||||||
|
na.Services, SFNodeNetwork)
|
||||||
|
}
|
||||||
|
if !na.HasService(SFNodeNetwork) {
|
||||||
|
t.Errorf("HasService: SFNodeNetwork service not set")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MsgReady implements the Message interface and represents a kaspa
|
|
||||||
// Ready message. It is used to notify that the peer is ready to receive
|
|
||||||
// messages.
|
|
||||||
//
|
|
||||||
// This message has no payload.
|
|
||||||
type MsgReady struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message. This is part
|
|
||||||
// of the Message interface implementation.
|
|
||||||
func (msg *MsgReady) Command() MessageCommand {
|
|
||||||
return CmdReady
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMsgReady returns a new kaspa Ready message that conforms to the
|
|
||||||
// Message interface.
|
|
||||||
func NewMsgReady() *MsgReady {
|
|
||||||
return &MsgReady{}
|
|
||||||
}
|
|
16
app/appmessage/p2p_requestpruningpointhash.go
Normal file
16
app/appmessage/p2p_requestpruningpointhash.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package appmessage
|
||||||
|
|
||||||
|
// MsgRequestPruningPointHashMessage represents a kaspa RequestPruningPointHashMessage message
|
||||||
|
type MsgRequestPruningPointHashMessage struct {
|
||||||
|
baseMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the protocol command string for the message
|
||||||
|
func (msg *MsgRequestPruningPointHashMessage) Command() MessageCommand {
|
||||||
|
return CmdRequestPruningPointHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMsgRequestPruningPointHashMessage returns a new kaspa RequestPruningPointHash message
|
||||||
|
func NewMsgRequestPruningPointHashMessage() *MsgRequestPruningPointHashMessage {
|
||||||
|
return &MsgRequestPruningPointHashMessage{}
|
||||||
|
}
|
@ -11,6 +11,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// ProtocolVersion is the latest protocol version this package supports.
|
||||||
|
ProtocolVersion uint32 = 1
|
||||||
|
|
||||||
// DefaultServices describes the default services that are supported by
|
// DefaultServices describes the default services that are supported by
|
||||||
// the server.
|
// the server.
|
||||||
DefaultServices = SFNodeNetwork | SFNodeBloom | SFNodeCF
|
DefaultServices = SFNodeNetwork | SFNodeBloom | SFNodeCF
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// EstimateNetworkHashesPerSecondRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type EstimateNetworkHashesPerSecondRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
StartHash string
|
|
||||||
WindowSize uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *EstimateNetworkHashesPerSecondRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdEstimateNetworkHashesPerSecondRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEstimateNetworkHashesPerSecondRequestMessage returns a instance of the message
|
|
||||||
func NewEstimateNetworkHashesPerSecondRequestMessage(startHash string, windowSize uint32) *EstimateNetworkHashesPerSecondRequestMessage {
|
|
||||||
return &EstimateNetworkHashesPerSecondRequestMessage{
|
|
||||||
StartHash: startHash,
|
|
||||||
WindowSize: windowSize,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EstimateNetworkHashesPerSecondResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type EstimateNetworkHashesPerSecondResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
NetworkHashesPerSecond uint64
|
|
||||||
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *EstimateNetworkHashesPerSecondResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdEstimateNetworkHashesPerSecondResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEstimateNetworkHashesPerSecondResponseMessage returns a instance of the message
|
|
||||||
func NewEstimateNetworkHashesPerSecondResponseMessage(networkHashesPerSecond uint64) *EstimateNetworkHashesPerSecondResponseMessage {
|
|
||||||
return &EstimateNetworkHashesPerSecondResponseMessage{
|
|
||||||
NetworkHashesPerSecond: networkHashesPerSecond,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// GetFeeEstimateRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetFeeEstimateRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetFeeEstimateRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdGetFeeEstimateRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetFeeEstimateRequestMessage returns a instance of the message
|
|
||||||
func NewGetFeeEstimateRequestMessage() *GetFeeEstimateRequestMessage {
|
|
||||||
return &GetFeeEstimateRequestMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type RPCFeeRateBucket struct {
|
|
||||||
Feerate float64
|
|
||||||
EstimatedSeconds float64
|
|
||||||
}
|
|
||||||
|
|
||||||
type RPCFeeEstimate struct {
|
|
||||||
PriorityBucket RPCFeeRateBucket
|
|
||||||
NormalBuckets []RPCFeeRateBucket
|
|
||||||
LowBuckets []RPCFeeRateBucket
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCoinSupplyResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetFeeEstimateResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Estimate RPCFeeEstimate
|
|
||||||
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetFeeEstimateResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdGetFeeEstimateResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetFeeEstimateResponseMessage returns a instance of the message
|
|
||||||
func NewGetFeeEstimateResponseMessage() *GetFeeEstimateResponseMessage {
|
|
||||||
return &GetFeeEstimateResponseMessage{}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// GetBalanceByAddressRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetBalanceByAddressRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Address string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetBalanceByAddressRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdGetBalanceByAddressRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetBalanceByAddressRequest returns a instance of the message
|
|
||||||
func NewGetBalanceByAddressRequest(address string) *GetBalanceByAddressRequestMessage {
|
|
||||||
return &GetBalanceByAddressRequestMessage{
|
|
||||||
Address: address,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBalanceByAddressResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetBalanceByAddressResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Balance uint64
|
|
||||||
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetBalanceByAddressResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdGetBalanceByAddressResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetBalanceByAddressResponse returns an instance of the message
|
|
||||||
func NewGetBalanceByAddressResponse(Balance uint64) *GetBalanceByAddressResponseMessage {
|
|
||||||
return &GetBalanceByAddressResponseMessage{
|
|
||||||
Balance: Balance,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// GetBalancesByAddressesRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetBalancesByAddressesRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Addresses []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetBalancesByAddressesRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdGetBalancesByAddressesRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetBalancesByAddressesRequest returns a instance of the message
|
|
||||||
func NewGetBalancesByAddressesRequest(addresses []string) *GetBalancesByAddressesRequestMessage {
|
|
||||||
return &GetBalancesByAddressesRequestMessage{
|
|
||||||
Addresses: addresses,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalancesByAddressesEntry represents the balance of some address
|
|
||||||
type BalancesByAddressesEntry struct {
|
|
||||||
Address string
|
|
||||||
Balance uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBalancesByAddressesResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetBalancesByAddressesResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Entries []*BalancesByAddressesEntry
|
|
||||||
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetBalancesByAddressesResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdGetBalancesByAddressesResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetBalancesByAddressesResponse returns an instance of the message
|
|
||||||
func NewGetBalancesByAddressesResponse(entries []*BalancesByAddressesEntry) *GetBalancesByAddressesResponseMessage {
|
|
||||||
return &GetBalancesByAddressesResponseMessage{
|
|
||||||
Entries: entries,
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ package appmessage
|
|||||||
type GetBlockRequestMessage struct {
|
type GetBlockRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Hash string
|
Hash string
|
||||||
IncludeTransactions bool
|
IncludeTransactionVerboseData bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -14,10 +14,10 @@ func (msg *GetBlockRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetBlockRequestMessage returns a instance of the message
|
// NewGetBlockRequestMessage returns a instance of the message
|
||||||
func NewGetBlockRequestMessage(hash string, includeTransactions bool) *GetBlockRequestMessage {
|
func NewGetBlockRequestMessage(hash string, includeTransactionVerboseData bool) *GetBlockRequestMessage {
|
||||||
return &GetBlockRequestMessage{
|
return &GetBlockRequestMessage{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
IncludeTransactions: includeTransactions,
|
IncludeTransactionVerboseData: includeTransactionVerboseData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ func NewGetBlockRequestMessage(hash string, includeTransactions bool) *GetBlockR
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetBlockResponseMessage struct {
|
type GetBlockResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Block *RPCBlock
|
BlockVerboseData *BlockVerboseData
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
@ -39,3 +39,69 @@ func (msg *GetBlockResponseMessage) Command() MessageCommand {
|
|||||||
func NewGetBlockResponseMessage() *GetBlockResponseMessage {
|
func NewGetBlockResponseMessage() *GetBlockResponseMessage {
|
||||||
return &GetBlockResponseMessage{}
|
return &GetBlockResponseMessage{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockVerboseData holds verbose data about a block
|
||||||
|
type BlockVerboseData struct {
|
||||||
|
Hash string
|
||||||
|
Version uint16
|
||||||
|
VersionHex string
|
||||||
|
HashMerkleRoot string
|
||||||
|
AcceptedIDMerkleRoot string
|
||||||
|
UTXOCommitment string
|
||||||
|
TxIDs []string
|
||||||
|
TransactionVerboseData []*TransactionVerboseData
|
||||||
|
Time int64
|
||||||
|
Nonce uint64
|
||||||
|
Bits string
|
||||||
|
Difficulty float64
|
||||||
|
ParentHashes []string
|
||||||
|
SelectedParentHash string
|
||||||
|
BlueScore uint64
|
||||||
|
IsHeaderOnly bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransactionVerboseData holds verbose data about a transaction
|
||||||
|
type TransactionVerboseData struct {
|
||||||
|
TxID string
|
||||||
|
Hash string
|
||||||
|
Size uint64
|
||||||
|
Version uint16
|
||||||
|
LockTime uint64
|
||||||
|
SubnetworkID string
|
||||||
|
Gas uint64
|
||||||
|
PayloadHash string
|
||||||
|
Payload string
|
||||||
|
TransactionVerboseInputs []*TransactionVerboseInput
|
||||||
|
TransactionVerboseOutputs []*TransactionVerboseOutput
|
||||||
|
BlockHash string
|
||||||
|
Time uint64
|
||||||
|
BlockTime uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransactionVerboseInput holds data about a transaction input
|
||||||
|
type TransactionVerboseInput struct {
|
||||||
|
TxID string
|
||||||
|
OutputIndex uint32
|
||||||
|
ScriptSig *ScriptSig
|
||||||
|
Sequence uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScriptSig holds data about a script signature
|
||||||
|
type ScriptSig struct {
|
||||||
|
Asm string
|
||||||
|
Hex string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransactionVerboseOutput holds data about a transaction output
|
||||||
|
type TransactionVerboseOutput struct {
|
||||||
|
Value uint64
|
||||||
|
Index uint32
|
||||||
|
ScriptPubKey *ScriptPubKeyResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScriptPubKeyResult holds data about a script public key
|
||||||
|
type ScriptPubKeyResult struct {
|
||||||
|
Hex string
|
||||||
|
Type string
|
||||||
|
Address string
|
||||||
|
}
|
||||||
|
@ -27,8 +27,6 @@ type GetBlockDAGInfoResponseMessage struct {
|
|||||||
VirtualParentHashes []string
|
VirtualParentHashes []string
|
||||||
Difficulty float64
|
Difficulty float64
|
||||||
PastMedianTime int64
|
PastMedianTime int64
|
||||||
PruningPointHash string
|
|
||||||
VirtualDAAScore uint64
|
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ package appmessage
|
|||||||
type GetBlockTemplateRequestMessage struct {
|
type GetBlockTemplateRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
PayAddress string
|
PayAddress string
|
||||||
ExtraData string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -14,10 +13,9 @@ func (msg *GetBlockTemplateRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetBlockTemplateRequestMessage returns a instance of the message
|
// NewGetBlockTemplateRequestMessage returns a instance of the message
|
||||||
func NewGetBlockTemplateRequestMessage(payAddress, extraData string) *GetBlockTemplateRequestMessage {
|
func NewGetBlockTemplateRequestMessage(payAddress string) *GetBlockTemplateRequestMessage {
|
||||||
return &GetBlockTemplateRequestMessage{
|
return &GetBlockTemplateRequestMessage{
|
||||||
PayAddress: payAddress,
|
PayAddress: payAddress,
|
||||||
ExtraData: extraData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ func NewGetBlockTemplateRequestMessage(payAddress, extraData string) *GetBlockTe
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetBlockTemplateResponseMessage struct {
|
type GetBlockTemplateResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Block *RPCBlock
|
MsgBlock *MsgBlock
|
||||||
IsSynced bool
|
IsSynced bool
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
@ -37,9 +35,9 @@ func (msg *GetBlockTemplateResponseMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetBlockTemplateResponseMessage returns a instance of the message
|
// NewGetBlockTemplateResponseMessage returns a instance of the message
|
||||||
func NewGetBlockTemplateResponseMessage(block *RPCBlock, isSynced bool) *GetBlockTemplateResponseMessage {
|
func NewGetBlockTemplateResponseMessage(msgBlock *MsgBlock, isSynced bool) *GetBlockTemplateResponseMessage {
|
||||||
return &GetBlockTemplateResponseMessage{
|
return &GetBlockTemplateResponseMessage{
|
||||||
Block: block,
|
MsgBlock: msgBlock,
|
||||||
IsSynced: isSynced,
|
IsSynced: isSynced,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ package appmessage
|
|||||||
type GetBlocksRequestMessage struct {
|
type GetBlocksRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
LowHash string
|
LowHash string
|
||||||
IncludeBlocks bool
|
IncludeBlockVerboseData bool
|
||||||
IncludeTransactions bool
|
IncludeTransactionVerboseData bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -15,12 +15,12 @@ func (msg *GetBlocksRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetBlocksRequestMessage returns a instance of the message
|
// NewGetBlocksRequestMessage returns a instance of the message
|
||||||
func NewGetBlocksRequestMessage(lowHash string, includeBlocks bool,
|
func NewGetBlocksRequestMessage(lowHash string, includeBlockVerboseData bool,
|
||||||
includeTransactions bool) *GetBlocksRequestMessage {
|
includeTransactionVerboseData bool) *GetBlocksRequestMessage {
|
||||||
return &GetBlocksRequestMessage{
|
return &GetBlocksRequestMessage{
|
||||||
LowHash: lowHash,
|
LowHash: lowHash,
|
||||||
IncludeBlocks: includeBlocks,
|
IncludeBlockVerboseData: includeBlockVerboseData,
|
||||||
IncludeTransactions: includeTransactions,
|
IncludeTransactionVerboseData: includeTransactionVerboseData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ func NewGetBlocksRequestMessage(lowHash string, includeBlocks bool,
|
|||||||
type GetBlocksResponseMessage struct {
|
type GetBlocksResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
BlockHashes []string
|
BlockHashes []string
|
||||||
Blocks []*RPCBlock
|
BlockVerboseData []*BlockVerboseData
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
@ -40,6 +40,11 @@ func (msg *GetBlocksResponseMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetBlocksResponseMessage returns a instance of the message
|
// NewGetBlocksResponseMessage returns a instance of the message
|
||||||
func NewGetBlocksResponseMessage() *GetBlocksResponseMessage {
|
func NewGetBlocksResponseMessage(blockHashes []string, blockHexes []string,
|
||||||
return &GetBlocksResponseMessage{}
|
blockVerboseData []*BlockVerboseData) *GetBlocksResponseMessage {
|
||||||
|
|
||||||
|
return &GetBlocksResponseMessage{
|
||||||
|
BlockHashes: blockHashes,
|
||||||
|
BlockVerboseData: blockVerboseData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// GetCoinSupplyRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetCoinSupplyRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetCoinSupplyRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdGetCoinSupplyRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetCoinSupplyRequestMessage returns a instance of the message
|
|
||||||
func NewGetCoinSupplyRequestMessage() *GetCoinSupplyRequestMessage {
|
|
||||||
return &GetCoinSupplyRequestMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCoinSupplyResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetCoinSupplyResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
MaxSompi uint64
|
|
||||||
CirculatingSompi uint64
|
|
||||||
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetCoinSupplyResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdGetCoinSupplyResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetCoinSupplyResponseMessage returns a instance of the message
|
|
||||||
func NewGetCoinSupplyResponseMessage(maxSompi uint64, circulatingSompi uint64) *GetCoinSupplyResponseMessage {
|
|
||||||
return &GetCoinSupplyResponseMessage{
|
|
||||||
MaxSompi: maxSompi,
|
|
||||||
CirculatingSompi: circulatingSompi,
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,8 +11,8 @@ func (msg *GetInfoRequestMessage) Command() MessageCommand {
|
|||||||
return CmdGetInfoRequestMessage
|
return CmdGetInfoRequestMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGetInfoRequestMessage returns a instance of the message
|
// NewGeInfoRequestMessage returns a instance of the message
|
||||||
func NewGetInfoRequestMessage() *GetInfoRequestMessage {
|
func NewGeInfoRequestMessage() *GetInfoRequestMessage {
|
||||||
return &GetInfoRequestMessage{}
|
return &GetInfoRequestMessage{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,10 +21,6 @@ func NewGetInfoRequestMessage() *GetInfoRequestMessage {
|
|||||||
type GetInfoResponseMessage struct {
|
type GetInfoResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
P2PID string
|
P2PID string
|
||||||
MempoolSize uint64
|
|
||||||
ServerVersion string
|
|
||||||
IsUtxoIndexed bool
|
|
||||||
IsSynced bool
|
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
@ -35,12 +31,8 @@ func (msg *GetInfoResponseMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetInfoResponseMessage returns a instance of the message
|
// NewGetInfoResponseMessage returns a instance of the message
|
||||||
func NewGetInfoResponseMessage(p2pID string, mempoolSize uint64, serverVersion string, isUtxoIndexed bool, isSynced bool) *GetInfoResponseMessage {
|
func NewGetInfoResponseMessage(p2pID string) *GetInfoResponseMessage {
|
||||||
return &GetInfoResponseMessage{
|
return &GetInfoResponseMessage{
|
||||||
P2PID: p2pID,
|
P2PID: p2pID,
|
||||||
MempoolSize: mempoolSize,
|
|
||||||
ServerVersion: serverVersion,
|
|
||||||
IsUtxoIndexed: isUtxoIndexed,
|
|
||||||
IsSynced: isSynced,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@ package appmessage
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetMempoolEntriesRequestMessage struct {
|
type GetMempoolEntriesRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
IncludeOrphanPool bool
|
|
||||||
FilterTransactionPool bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -14,11 +12,8 @@ func (msg *GetMempoolEntriesRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetMempoolEntriesRequestMessage returns a instance of the message
|
// NewGetMempoolEntriesRequestMessage returns a instance of the message
|
||||||
func NewGetMempoolEntriesRequestMessage(includeOrphanPool bool, filterTransactionPool bool) *GetMempoolEntriesRequestMessage {
|
func NewGetMempoolEntriesRequestMessage() *GetMempoolEntriesRequestMessage {
|
||||||
return &GetMempoolEntriesRequestMessage{
|
return &GetMempoolEntriesRequestMessage{}
|
||||||
IncludeOrphanPool: includeOrphanPool,
|
|
||||||
FilterTransactionPool: filterTransactionPool,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempoolEntriesResponseMessage is an appmessage corresponding to
|
// GetMempoolEntriesResponseMessage is an appmessage corresponding to
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// MempoolEntryByAddress represents MempoolEntries associated with some address
|
|
||||||
type MempoolEntryByAddress struct {
|
|
||||||
Address string
|
|
||||||
Receiving []*MempoolEntry
|
|
||||||
Sending []*MempoolEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMempoolEntriesByAddressesRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetMempoolEntriesByAddressesRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Addresses []string
|
|
||||||
IncludeOrphanPool bool
|
|
||||||
FilterTransactionPool bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetMempoolEntriesByAddressesRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdGetMempoolEntriesByAddressesRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetMempoolEntriesByAddressesRequestMessage returns a instance of the message
|
|
||||||
func NewGetMempoolEntriesByAddressesRequestMessage(addresses []string, includeOrphanPool bool, filterTransactionPool bool) *GetMempoolEntriesByAddressesRequestMessage {
|
|
||||||
return &GetMempoolEntriesByAddressesRequestMessage{
|
|
||||||
Addresses: addresses,
|
|
||||||
IncludeOrphanPool: includeOrphanPool,
|
|
||||||
FilterTransactionPool: filterTransactionPool,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMempoolEntriesByAddressesResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type GetMempoolEntriesByAddressesResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Entries []*MempoolEntryByAddress
|
|
||||||
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *GetMempoolEntriesByAddressesResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdGetMempoolEntriesByAddressesResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetMempoolEntriesByAddressesResponseMessage returns a instance of the message
|
|
||||||
func NewGetMempoolEntriesByAddressesResponseMessage(entries []*MempoolEntryByAddress) *GetMempoolEntriesByAddressesResponseMessage {
|
|
||||||
return &GetMempoolEntriesByAddressesResponseMessage{
|
|
||||||
Entries: entries,
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,8 +5,6 @@ package appmessage
|
|||||||
type GetMempoolEntryRequestMessage struct {
|
type GetMempoolEntryRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
TxID string
|
TxID string
|
||||||
IncludeOrphanPool bool
|
|
||||||
FilterTransactionPool bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -15,12 +13,8 @@ func (msg *GetMempoolEntryRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetMempoolEntryRequestMessage returns a instance of the message
|
// NewGetMempoolEntryRequestMessage returns a instance of the message
|
||||||
func NewGetMempoolEntryRequestMessage(txID string, includeOrphanPool bool, filterTransactionPool bool) *GetMempoolEntryRequestMessage {
|
func NewGetMempoolEntryRequestMessage(txID string) *GetMempoolEntryRequestMessage {
|
||||||
return &GetMempoolEntryRequestMessage{
|
return &GetMempoolEntryRequestMessage{TxID: txID}
|
||||||
TxID: txID,
|
|
||||||
IncludeOrphanPool: includeOrphanPool,
|
|
||||||
FilterTransactionPool: filterTransactionPool,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempoolEntryResponseMessage is an appmessage corresponding to
|
// GetMempoolEntryResponseMessage is an appmessage corresponding to
|
||||||
@ -35,8 +29,7 @@ type GetMempoolEntryResponseMessage struct {
|
|||||||
// MempoolEntry represents a transaction in the mempool.
|
// MempoolEntry represents a transaction in the mempool.
|
||||||
type MempoolEntry struct {
|
type MempoolEntry struct {
|
||||||
Fee uint64
|
Fee uint64
|
||||||
Transaction *RPCTransaction
|
TransactionVerboseData *TransactionVerboseData
|
||||||
IsOrphan bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -45,12 +38,11 @@ func (msg *GetMempoolEntryResponseMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetMempoolEntryResponseMessage returns a instance of the message
|
// NewGetMempoolEntryResponseMessage returns a instance of the message
|
||||||
func NewGetMempoolEntryResponseMessage(fee uint64, transaction *RPCTransaction, isOrphan bool) *GetMempoolEntryResponseMessage {
|
func NewGetMempoolEntryResponseMessage(fee uint64, transactionVerboseData *TransactionVerboseData) *GetMempoolEntryResponseMessage {
|
||||||
return &GetMempoolEntryResponseMessage{
|
return &GetMempoolEntryResponseMessage{
|
||||||
Entry: &MempoolEntry{
|
Entry: &MempoolEntry{
|
||||||
Fee: fee,
|
Fee: fee,
|
||||||
Transaction: transaction,
|
TransactionVerboseData: transactionVerboseData,
|
||||||
IsOrphan: isOrphan,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ package appmessage
|
|||||||
type GetVirtualSelectedParentChainFromBlockRequestMessage struct {
|
type GetVirtualSelectedParentChainFromBlockRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
StartHash string
|
StartHash string
|
||||||
IncludeAcceptedTransactionIDs bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -14,29 +13,18 @@ func (msg *GetVirtualSelectedParentChainFromBlockRequestMessage) Command() Messa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetVirtualSelectedParentChainFromBlockRequestMessage returns a instance of the message
|
// NewGetVirtualSelectedParentChainFromBlockRequestMessage returns a instance of the message
|
||||||
func NewGetVirtualSelectedParentChainFromBlockRequestMessage(
|
func NewGetVirtualSelectedParentChainFromBlockRequestMessage(startHash string) *GetVirtualSelectedParentChainFromBlockRequestMessage {
|
||||||
startHash string, includeAcceptedTransactionIDs bool) *GetVirtualSelectedParentChainFromBlockRequestMessage {
|
|
||||||
|
|
||||||
return &GetVirtualSelectedParentChainFromBlockRequestMessage{
|
return &GetVirtualSelectedParentChainFromBlockRequestMessage{
|
||||||
StartHash: startHash,
|
StartHash: startHash,
|
||||||
IncludeAcceptedTransactionIDs: includeAcceptedTransactionIDs,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptedTransactionIDs is a part of the GetVirtualSelectedParentChainFromBlockResponseMessage and
|
|
||||||
// VirtualSelectedParentChainChangedNotificationMessage appmessages
|
|
||||||
type AcceptedTransactionIDs struct {
|
|
||||||
AcceptingBlockHash string
|
|
||||||
AcceptedTransactionIDs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVirtualSelectedParentChainFromBlockResponseMessage is an appmessage corresponding to
|
// GetVirtualSelectedParentChainFromBlockResponseMessage is an appmessage corresponding to
|
||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetVirtualSelectedParentChainFromBlockResponseMessage struct {
|
type GetVirtualSelectedParentChainFromBlockResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
RemovedChainBlockHashes []string
|
RemovedChainBlockHashes []string
|
||||||
AddedChainBlockHashes []string
|
AddedChainBlocks []*ChainBlock
|
||||||
AcceptedTransactionIDs []*AcceptedTransactionIDs
|
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
@ -47,12 +35,11 @@ func (msg *GetVirtualSelectedParentChainFromBlockResponseMessage) Command() Mess
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetVirtualSelectedParentChainFromBlockResponseMessage returns a instance of the message
|
// NewGetVirtualSelectedParentChainFromBlockResponseMessage returns a instance of the message
|
||||||
func NewGetVirtualSelectedParentChainFromBlockResponseMessage(removedChainBlockHashes,
|
func NewGetVirtualSelectedParentChainFromBlockResponseMessage(removedChainBlockHashes []string,
|
||||||
addedChainBlockHashes []string, acceptedTransactionIDs []*AcceptedTransactionIDs) *GetVirtualSelectedParentChainFromBlockResponseMessage {
|
addedChainBlocks []*ChainBlock) *GetVirtualSelectedParentChainFromBlockResponseMessage {
|
||||||
|
|
||||||
return &GetVirtualSelectedParentChainFromBlockResponseMessage{
|
return &GetVirtualSelectedParentChainFromBlockResponseMessage{
|
||||||
RemovedChainBlockHashes: removedChainBlockHashes,
|
RemovedChainBlockHashes: removedChainBlockHashes,
|
||||||
AddedChainBlockHashes: addedChainBlockHashes,
|
AddedChainBlocks: addedChainBlocks,
|
||||||
AcceptedTransactionIDs: acceptedTransactionIDs,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,8 @@ func NewNotifyBlockAddedResponseMessage() *NotifyBlockAddedResponseMessage {
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type BlockAddedNotificationMessage struct {
|
type BlockAddedNotificationMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Block *RPCBlock
|
Block *MsgBlock
|
||||||
|
BlockVerboseData *BlockVerboseData
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -46,8 +47,9 @@ func (msg *BlockAddedNotificationMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockAddedNotificationMessage returns a instance of the message
|
// NewBlockAddedNotificationMessage returns a instance of the message
|
||||||
func NewBlockAddedNotificationMessage(block *RPCBlock) *BlockAddedNotificationMessage {
|
func NewBlockAddedNotificationMessage(block *MsgBlock, blockVerboseData *BlockVerboseData) *BlockAddedNotificationMessage {
|
||||||
return &BlockAddedNotificationMessage{
|
return &BlockAddedNotificationMessage{
|
||||||
Block: block,
|
Block: block,
|
||||||
|
BlockVerboseData: blockVerboseData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// NotifyNewBlockTemplateRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type NotifyNewBlockTemplateRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *NotifyNewBlockTemplateRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyNewBlockTemplateRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNotifyNewBlockTemplateRequestMessage returns an instance of the message
|
|
||||||
func NewNotifyNewBlockTemplateRequestMessage() *NotifyNewBlockTemplateRequestMessage {
|
|
||||||
return &NotifyNewBlockTemplateRequestMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyNewBlockTemplateResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type NotifyNewBlockTemplateResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *NotifyNewBlockTemplateResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyNewBlockTemplateResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNotifyNewBlockTemplateResponseMessage returns an instance of the message
|
|
||||||
func NewNotifyNewBlockTemplateResponseMessage() *NotifyNewBlockTemplateResponseMessage {
|
|
||||||
return &NotifyNewBlockTemplateResponseMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBlockTemplateNotificationMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type NewBlockTemplateNotificationMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *NewBlockTemplateNotificationMessage) Command() MessageCommand {
|
|
||||||
return CmdNewBlockTemplateNotificationMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNewBlockTemplateNotificationMessage returns an instance of the message
|
|
||||||
func NewNewBlockTemplateNotificationMessage() *NewBlockTemplateNotificationMessage {
|
|
||||||
return &NewBlockTemplateNotificationMessage{}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// NotifyPruningPointUTXOSetOverrideRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type NotifyPruningPointUTXOSetOverrideRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *NotifyPruningPointUTXOSetOverrideRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyPruningPointUTXOSetOverrideRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNotifyPruningPointUTXOSetOverrideRequestMessage returns a instance of the message
|
|
||||||
func NewNotifyPruningPointUTXOSetOverrideRequestMessage() *NotifyPruningPointUTXOSetOverrideRequestMessage {
|
|
||||||
return &NotifyPruningPointUTXOSetOverrideRequestMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyPruningPointUTXOSetOverrideResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type NotifyPruningPointUTXOSetOverrideResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *NotifyPruningPointUTXOSetOverrideResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyPruningPointUTXOSetOverrideResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNotifyPruningPointUTXOSetOverrideResponseMessage returns a instance of the message
|
|
||||||
func NewNotifyPruningPointUTXOSetOverrideResponseMessage() *NotifyPruningPointUTXOSetOverrideResponseMessage {
|
|
||||||
return &NotifyPruningPointUTXOSetOverrideResponseMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PruningPointUTXOSetOverrideNotificationMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type PruningPointUTXOSetOverrideNotificationMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *PruningPointUTXOSetOverrideNotificationMessage) Command() MessageCommand {
|
|
||||||
return CmdPruningPointUTXOSetOverrideNotificationMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPruningPointUTXOSetOverrideNotificationMessage returns a instance of the message
|
|
||||||
func NewPruningPointUTXOSetOverrideNotificationMessage() *PruningPointUTXOSetOverrideNotificationMessage {
|
|
||||||
return &PruningPointUTXOSetOverrideNotificationMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopNotifyingPruningPointUTXOSetOverrideRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type StopNotifyingPruningPointUTXOSetOverrideRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *StopNotifyingPruningPointUTXOSetOverrideRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyPruningPointUTXOSetOverrideRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStopNotifyingPruningPointUTXOSetOverrideRequestMessage returns a instance of the message
|
|
||||||
func NewStopNotifyingPruningPointUTXOSetOverrideRequestMessage() *StopNotifyingPruningPointUTXOSetOverrideRequestMessage {
|
|
||||||
return &StopNotifyingPruningPointUTXOSetOverrideRequestMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopNotifyingPruningPointUTXOSetOverrideResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type StopNotifyingPruningPointUTXOSetOverrideResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *StopNotifyingPruningPointUTXOSetOverrideResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyPruningPointUTXOSetOverrideResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStopNotifyingPruningPointUTXOSetOverrideResponseMessage returns a instance of the message
|
|
||||||
func NewStopNotifyingPruningPointUTXOSetOverrideResponseMessage() *StopNotifyingPruningPointUTXOSetOverrideResponseMessage {
|
|
||||||
return &StopNotifyingPruningPointUTXOSetOverrideResponseMessage{}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// NotifyVirtualDaaScoreChangedRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type NotifyVirtualDaaScoreChangedRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *NotifyVirtualDaaScoreChangedRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyVirtualDaaScoreChangedRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNotifyVirtualDaaScoreChangedRequestMessage returns a instance of the message
|
|
||||||
func NewNotifyVirtualDaaScoreChangedRequestMessage() *NotifyVirtualDaaScoreChangedRequestMessage {
|
|
||||||
return &NotifyVirtualDaaScoreChangedRequestMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyVirtualDaaScoreChangedResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type NotifyVirtualDaaScoreChangedResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *NotifyVirtualDaaScoreChangedResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdNotifyVirtualDaaScoreChangedResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNotifyVirtualDaaScoreChangedResponseMessage returns a instance of the message
|
|
||||||
func NewNotifyVirtualDaaScoreChangedResponseMessage() *NotifyVirtualDaaScoreChangedResponseMessage {
|
|
||||||
return &NotifyVirtualDaaScoreChangedResponseMessage{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VirtualDaaScoreChangedNotificationMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type VirtualDaaScoreChangedNotificationMessage struct {
|
|
||||||
baseMessage
|
|
||||||
VirtualDaaScore uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *VirtualDaaScoreChangedNotificationMessage) Command() MessageCommand {
|
|
||||||
return CmdVirtualDaaScoreChangedNotificationMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVirtualDaaScoreChangedNotificationMessage returns a instance of the message
|
|
||||||
func NewVirtualDaaScoreChangedNotificationMessage(
|
|
||||||
virtualDaaScore uint64) *VirtualDaaScoreChangedNotificationMessage {
|
|
||||||
|
|
||||||
return &VirtualDaaScoreChangedNotificationMessage{
|
|
||||||
VirtualDaaScore: virtualDaaScore,
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ package appmessage
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type NotifyVirtualSelectedParentChainChangedRequestMessage struct {
|
type NotifyVirtualSelectedParentChainChangedRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
IncludeAcceptedTransactionIDs bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -12,13 +11,9 @@ func (msg *NotifyVirtualSelectedParentChainChangedRequestMessage) Command() Mess
|
|||||||
return CmdNotifyVirtualSelectedParentChainChangedRequestMessage
|
return CmdNotifyVirtualSelectedParentChainChangedRequestMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNotifyVirtualSelectedParentChainChangedRequestMessage returns an instance of the message
|
// NewNotifyVirtualSelectedParentChainChangedRequestMessage returns a instance of the message
|
||||||
func NewNotifyVirtualSelectedParentChainChangedRequestMessage(
|
func NewNotifyVirtualSelectedParentChainChangedRequestMessage() *NotifyVirtualSelectedParentChainChangedRequestMessage {
|
||||||
includeAcceptedTransactionIDs bool) *NotifyVirtualSelectedParentChainChangedRequestMessage {
|
return &NotifyVirtualSelectedParentChainChangedRequestMessage{}
|
||||||
|
|
||||||
return &NotifyVirtualSelectedParentChainChangedRequestMessage{
|
|
||||||
IncludeAcceptedTransactionIDs: includeAcceptedTransactionIDs,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyVirtualSelectedParentChainChangedResponseMessage is an appmessage corresponding to
|
// NotifyVirtualSelectedParentChainChangedResponseMessage is an appmessage corresponding to
|
||||||
@ -43,8 +38,19 @@ func NewNotifyVirtualSelectedParentChainChangedResponseMessage() *NotifyVirtualS
|
|||||||
type VirtualSelectedParentChainChangedNotificationMessage struct {
|
type VirtualSelectedParentChainChangedNotificationMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
RemovedChainBlockHashes []string
|
RemovedChainBlockHashes []string
|
||||||
AddedChainBlockHashes []string
|
AddedChainBlocks []*ChainBlock
|
||||||
AcceptedTransactionIDs []*AcceptedTransactionIDs
|
}
|
||||||
|
|
||||||
|
// ChainBlock represents a DAG chain-block
|
||||||
|
type ChainBlock struct {
|
||||||
|
Hash string
|
||||||
|
AcceptedBlocks []*AcceptedBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptedBlock represents a block accepted into the DAG
|
||||||
|
type AcceptedBlock struct {
|
||||||
|
Hash string
|
||||||
|
AcceptedTransactionIDs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -53,12 +59,11 @@ func (msg *VirtualSelectedParentChainChangedNotificationMessage) Command() Messa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewVirtualSelectedParentChainChangedNotificationMessage returns a instance of the message
|
// NewVirtualSelectedParentChainChangedNotificationMessage returns a instance of the message
|
||||||
func NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes,
|
func NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes []string,
|
||||||
addedChainBlocks []string, acceptedTransactionIDs []*AcceptedTransactionIDs) *VirtualSelectedParentChainChangedNotificationMessage {
|
addedChainBlocks []*ChainBlock) *VirtualSelectedParentChainChangedNotificationMessage {
|
||||||
|
|
||||||
return &VirtualSelectedParentChainChangedNotificationMessage{
|
return &VirtualSelectedParentChainChangedNotificationMessage{
|
||||||
RemovedChainBlockHashes: removedChainBlockHashes,
|
RemovedChainBlockHashes: removedChainBlockHashes,
|
||||||
AddedChainBlockHashes: addedChainBlocks,
|
AddedChainBlocks: addedChainBlocks,
|
||||||
AcceptedTransactionIDs: acceptedTransactionIDs,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// StopNotifyingUTXOsChangedRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type StopNotifyingUTXOsChangedRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Addresses []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *StopNotifyingUTXOsChangedRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdStopNotifyingUTXOsChangedRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStopNotifyingUTXOsChangedRequestMessage returns a instance of the message
|
|
||||||
func NewStopNotifyingUTXOsChangedRequestMessage(addresses []string) *StopNotifyingUTXOsChangedRequestMessage {
|
|
||||||
return &StopNotifyingUTXOsChangedRequestMessage{
|
|
||||||
Addresses: addresses,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopNotifyingUTXOsChangedResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type StopNotifyingUTXOsChangedResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *StopNotifyingUTXOsChangedResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdStopNotifyingUTXOsChangedResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStopNotifyingUTXOsChangedResponseMessage returns a instance of the message
|
|
||||||
func NewStopNotifyingUTXOsChangedResponseMessage() *StopNotifyingUTXOsChangedResponseMessage {
|
|
||||||
return &StopNotifyingUTXOsChangedResponseMessage{}
|
|
||||||
}
|
|
@ -4,8 +4,7 @@ package appmessage
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type SubmitBlockRequestMessage struct {
|
type SubmitBlockRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Block *RPCBlock
|
Block *MsgBlock
|
||||||
AllowNonDAABlocks bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -14,10 +13,9 @@ func (msg *SubmitBlockRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewSubmitBlockRequestMessage returns a instance of the message
|
// NewSubmitBlockRequestMessage returns a instance of the message
|
||||||
func NewSubmitBlockRequestMessage(block *RPCBlock, allowNonDAABlocks bool) *SubmitBlockRequestMessage {
|
func NewSubmitBlockRequestMessage(block *MsgBlock) *SubmitBlockRequestMessage {
|
||||||
return &SubmitBlockRequestMessage{
|
return &SubmitBlockRequestMessage{
|
||||||
Block: block,
|
Block: block,
|
||||||
AllowNonDAABlocks: allowNonDAABlocks,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,51 +53,7 @@ func (msg *SubmitBlockResponseMessage) Command() MessageCommand {
|
|||||||
return CmdSubmitBlockResponseMessage
|
return CmdSubmitBlockResponseMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubmitBlockResponseMessage returns an instance of the message
|
// NewSubmitBlockResponseMessage returns a instance of the message
|
||||||
func NewSubmitBlockResponseMessage() *SubmitBlockResponseMessage {
|
func NewSubmitBlockResponseMessage() *SubmitBlockResponseMessage {
|
||||||
return &SubmitBlockResponseMessage{}
|
return &SubmitBlockResponseMessage{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCBlock is a kaspad block representation meant to be
|
|
||||||
// used over RPC
|
|
||||||
type RPCBlock struct {
|
|
||||||
Header *RPCBlockHeader
|
|
||||||
Transactions []*RPCTransaction
|
|
||||||
VerboseData *RPCBlockVerboseData
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCBlockHeader is a kaspad block header representation meant to be
|
|
||||||
// used over RPC
|
|
||||||
type RPCBlockHeader struct {
|
|
||||||
Version uint32
|
|
||||||
Parents []*RPCBlockLevelParents
|
|
||||||
HashMerkleRoot string
|
|
||||||
AcceptedIDMerkleRoot string
|
|
||||||
UTXOCommitment string
|
|
||||||
Timestamp int64
|
|
||||||
Bits uint32
|
|
||||||
Nonce uint64
|
|
||||||
DAAScore uint64
|
|
||||||
BlueScore uint64
|
|
||||||
BlueWork string
|
|
||||||
PruningPoint string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCBlockLevelParents holds parent hashes for one block level
|
|
||||||
type RPCBlockLevelParents struct {
|
|
||||||
ParentHashes []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCBlockVerboseData holds verbose data about a block
|
|
||||||
type RPCBlockVerboseData struct {
|
|
||||||
Hash string
|
|
||||||
Difficulty float64
|
|
||||||
SelectedParentHash string
|
|
||||||
TransactionIDs []string
|
|
||||||
IsHeaderOnly bool
|
|
||||||
BlueScore uint64
|
|
||||||
ChildrenHashes []string
|
|
||||||
MergeSetBluesHashes []string
|
|
||||||
MergeSetRedsHashes []string
|
|
||||||
IsChainBlock bool
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,6 @@ package appmessage
|
|||||||
type SubmitTransactionRequestMessage struct {
|
type SubmitTransactionRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Transaction *RPCTransaction
|
Transaction *RPCTransaction
|
||||||
AllowOrphan bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@ -14,10 +13,9 @@ func (msg *SubmitTransactionRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewSubmitTransactionRequestMessage returns a instance of the message
|
// NewSubmitTransactionRequestMessage returns a instance of the message
|
||||||
func NewSubmitTransactionRequestMessage(transaction *RPCTransaction, allowOrphan bool) *SubmitTransactionRequestMessage {
|
func NewSubmitTransactionRequestMessage(transaction *RPCTransaction) *SubmitTransactionRequestMessage {
|
||||||
return &SubmitTransactionRequestMessage{
|
return &SubmitTransactionRequestMessage{
|
||||||
Transaction: transaction,
|
Transaction: transaction,
|
||||||
AllowOrphan: allowOrphan,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,9 +49,8 @@ type RPCTransaction struct {
|
|||||||
LockTime uint64
|
LockTime uint64
|
||||||
SubnetworkID string
|
SubnetworkID string
|
||||||
Gas uint64
|
Gas uint64
|
||||||
|
PayloadHash string
|
||||||
Payload string
|
Payload string
|
||||||
Mass uint64
|
|
||||||
VerboseData *RPCTransactionVerboseData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCTransactionInput is a kaspad transaction input representation
|
// RPCTransactionInput is a kaspad transaction input representation
|
||||||
@ -62,8 +59,6 @@ type RPCTransactionInput struct {
|
|||||||
PreviousOutpoint *RPCOutpoint
|
PreviousOutpoint *RPCOutpoint
|
||||||
SignatureScript string
|
SignatureScript string
|
||||||
Sequence uint64
|
Sequence uint64
|
||||||
SigOpCount byte
|
|
||||||
VerboseData *RPCTransactionInputVerboseData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCScriptPublicKey is a kaspad ScriptPublicKey representation
|
// RPCScriptPublicKey is a kaspad ScriptPublicKey representation
|
||||||
@ -77,7 +72,6 @@ type RPCScriptPublicKey struct {
|
|||||||
type RPCTransactionOutput struct {
|
type RPCTransactionOutput struct {
|
||||||
Amount uint64
|
Amount uint64
|
||||||
ScriptPublicKey *RPCScriptPublicKey
|
ScriptPublicKey *RPCScriptPublicKey
|
||||||
VerboseData *RPCTransactionOutputVerboseData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCOutpoint is a kaspad outpoint representation meant to be used
|
// RPCOutpoint is a kaspad outpoint representation meant to be used
|
||||||
@ -92,25 +86,6 @@ type RPCOutpoint struct {
|
|||||||
type RPCUTXOEntry struct {
|
type RPCUTXOEntry struct {
|
||||||
Amount uint64
|
Amount uint64
|
||||||
ScriptPublicKey *RPCScriptPublicKey
|
ScriptPublicKey *RPCScriptPublicKey
|
||||||
BlockDAAScore uint64
|
BlockBlueScore uint64
|
||||||
IsCoinbase bool
|
IsCoinbase bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCTransactionVerboseData holds verbose data about a transaction
|
|
||||||
type RPCTransactionVerboseData struct {
|
|
||||||
TransactionID string
|
|
||||||
Hash string
|
|
||||||
Mass uint64
|
|
||||||
BlockHash string
|
|
||||||
BlockTime uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCTransactionInputVerboseData holds data about a transaction input
|
|
||||||
type RPCTransactionInputVerboseData struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// RPCTransactionOutputVerboseData holds data about a transaction output
|
|
||||||
type RPCTransactionOutputVerboseData struct {
|
|
||||||
ScriptPublicKeyType string
|
|
||||||
ScriptPublicKeyAddress string
|
|
||||||
}
|
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
package appmessage
|
|
||||||
|
|
||||||
// SubmitTransactionReplacementRequestMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type SubmitTransactionReplacementRequestMessage struct {
|
|
||||||
baseMessage
|
|
||||||
Transaction *RPCTransaction
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *SubmitTransactionReplacementRequestMessage) Command() MessageCommand {
|
|
||||||
return CmdSubmitTransactionReplacementRequestMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSubmitTransactionReplacementRequestMessage returns a instance of the message
|
|
||||||
func NewSubmitTransactionReplacementRequestMessage(transaction *RPCTransaction) *SubmitTransactionReplacementRequestMessage {
|
|
||||||
return &SubmitTransactionReplacementRequestMessage{
|
|
||||||
Transaction: transaction,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubmitTransactionReplacementResponseMessage is an appmessage corresponding to
|
|
||||||
// its respective RPC message
|
|
||||||
type SubmitTransactionReplacementResponseMessage struct {
|
|
||||||
baseMessage
|
|
||||||
TransactionID string
|
|
||||||
ReplacedTransaction *RPCTransaction
|
|
||||||
|
|
||||||
Error *RPCError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
|
||||||
func (msg *SubmitTransactionReplacementResponseMessage) Command() MessageCommand {
|
|
||||||
return CmdSubmitTransactionReplacementResponseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSubmitTransactionReplacementResponseMessage returns a instance of the message
|
|
||||||
func NewSubmitTransactionReplacementResponseMessage(transactionID string) *SubmitTransactionReplacementResponseMessage {
|
|
||||||
return &SubmitTransactionReplacementResponseMessage{
|
|
||||||
TransactionID: transactionID,
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,21 +4,23 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/protocol"
|
"github.com/kaspanet/kaspad/app/protocol"
|
||||||
"github.com/kaspanet/kaspad/app/rpc"
|
"github.com/kaspanet/kaspad/app/rpc"
|
||||||
"github.com/kaspanet/kaspad/domain"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus"
|
|
||||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/dnsseed"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
|
||||||
"github.com/kaspanet/kaspad/util/panics"
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,6 +50,8 @@ func (a *ComponentManager) Start() {
|
|||||||
panics.Exit(log, fmt.Sprintf("Error starting the net adapter: %+v", err))
|
panics.Exit(log, fmt.Sprintf("Error starting the net adapter: %+v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.maybeSeedFromDNS()
|
||||||
|
|
||||||
a.connectionManager.Start()
|
a.connectionManager.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,9 +72,6 @@ func (a *ComponentManager) Stop() {
|
|||||||
log.Errorf("Error stopping the net adapter: %+v", err)
|
log.Errorf("Error stopping the net adapter: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.protocolManager.Close()
|
|
||||||
close(a.protocolManager.Context().Domain().ConsensusEventsChannel())
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,16 +80,7 @@ func (a *ComponentManager) Stop() {
|
|||||||
func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, interrupt chan<- struct{}) (
|
func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, interrupt chan<- struct{}) (
|
||||||
*ComponentManager, error) {
|
*ComponentManager, error) {
|
||||||
|
|
||||||
consensusConfig := consensus.Config{
|
domain, err := domain.New(cfg.ActiveNetParams, db, cfg.IsArchivalNode)
|
||||||
Params: *cfg.ActiveNetParams,
|
|
||||||
IsArchival: cfg.IsArchivalNode,
|
|
||||||
EnableSanityCheckPruningUTXOSet: cfg.EnableSanityCheckPruningUTXOSet,
|
|
||||||
}
|
|
||||||
mempoolConfig := mempool.DefaultConfig(&consensusConfig.Params)
|
|
||||||
mempoolConfig.MaximumOrphanTransactionCount = cfg.MaxOrphanTxs
|
|
||||||
mempoolConfig.MinimumRelayTransactionFee = cfg.MinRelayTxFee
|
|
||||||
|
|
||||||
domain, err := domain.New(&consensusConfig, mempoolConfig, db)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -98,18 +90,14 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
addressManager, err := addressmanager.New(addressmanager.NewConfig(cfg), db)
|
addressManager, err := addressmanager.New(addressmanager.NewConfig(cfg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var utxoIndex *utxoindex.UTXOIndex
|
var utxoIndex *utxoindex.UTXOIndex
|
||||||
if cfg.UTXOIndex {
|
if cfg.UTXOIndex {
|
||||||
utxoIndex, err = utxoindex.New(domain, db)
|
utxoIndex = utxoindex.New(domain.Consensus(), db)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("UTXO index started")
|
log.Infof("UTXO index started")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +109,7 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rpcManager := setupRPC(cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, utxoIndex, domain.ConsensusEventsChannel(), interrupt)
|
rpcManager := setupRPC(cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, utxoIndex, interrupt)
|
||||||
|
|
||||||
return &ComponentManager{
|
return &ComponentManager{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
@ -142,7 +130,6 @@ func setupRPC(
|
|||||||
connectionManager *connmanager.ConnectionManager,
|
connectionManager *connmanager.ConnectionManager,
|
||||||
addressManager *addressmanager.AddressManager,
|
addressManager *addressmanager.AddressManager,
|
||||||
utxoIndex *utxoindex.UTXOIndex,
|
utxoIndex *utxoindex.UTXOIndex,
|
||||||
consensusEventsChan chan externalapi.ConsensusEvent,
|
|
||||||
shutDownChan chan<- struct{},
|
shutDownChan chan<- struct{},
|
||||||
) *rpc.Manager {
|
) *rpc.Manager {
|
||||||
|
|
||||||
@ -154,15 +141,30 @@ func setupRPC(
|
|||||||
connectionManager,
|
connectionManager,
|
||||||
addressManager,
|
addressManager,
|
||||||
utxoIndex,
|
utxoIndex,
|
||||||
consensusEventsChan,
|
|
||||||
shutDownChan,
|
shutDownChan,
|
||||||
)
|
)
|
||||||
protocolManager.SetOnNewBlockTemplateHandler(rpcManager.NotifyNewBlockTemplate)
|
protocolManager.SetOnBlockAddedToDAGHandler(rpcManager.NotifyBlockAddedToDAG)
|
||||||
protocolManager.SetOnPruningPointUTXOSetOverrideHandler(rpcManager.NotifyPruningPointUTXOSetOverride)
|
|
||||||
|
|
||||||
return rpcManager
|
return rpcManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ComponentManager) maybeSeedFromDNS() {
|
||||||
|
if !a.cfg.DisableDNSSeed {
|
||||||
|
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, appmessage.SFNodeNetwork, false, nil,
|
||||||
|
a.cfg.Lookup, func(addresses []*appmessage.NetAddress) {
|
||||||
|
// Kaspad uses a lookup of the dns seeder here. Since seeder returns
|
||||||
|
// IPs of nodes and not its own IP, we can not know real IP of
|
||||||
|
// source. So we'll take first returned address as source.
|
||||||
|
a.addressManager.AddAddresses(addresses...)
|
||||||
|
})
|
||||||
|
|
||||||
|
dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, appmessage.SFNodeNetwork, false, nil,
|
||||||
|
func(addresses []*appmessage.NetAddress) {
|
||||||
|
a.addressManager.AddAddresses(addresses...)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// P2PNodeID returns the network ID associated with this ComponentManager
|
// P2PNodeID returns the network ID associated with this ComponentManager
|
||||||
func (a *ComponentManager) P2PNodeID() *id.ID {
|
func (a *ComponentManager) P2PNodeID() *id.ID {
|
||||||
return a.netAdapter.ID()
|
return a.netAdapter.ID()
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const currentDatabaseVersion = 1
|
|
||||||
|
|
||||||
func checkDatabaseVersion(dbPath string) (err error) {
|
|
||||||
versionFileName := versionFilePath(dbPath)
|
|
||||||
|
|
||||||
versionBytes, err := os.ReadFile(versionFileName)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) { // If version file doesn't exist, we assume that the database is new
|
|
||||||
return createDatabaseVersionFile(dbPath, versionFileName)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
databaseVersion, err := strconv.Atoi(string(versionBytes))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if databaseVersion != currentDatabaseVersion {
|
|
||||||
// TODO: Once there's more then one database version, it might make sense to add upgrade logic at this point
|
|
||||||
return errors.Errorf("Invalid database version %d. Expected version: %d", databaseVersion, currentDatabaseVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDatabaseVersionFile(dbPath string, versionFileName string) error {
|
|
||||||
err := os.MkdirAll(dbPath, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
versionFile, err := os.Create(versionFileName)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer versionFile.Close()
|
|
||||||
|
|
||||||
versionString := strconv.Itoa(currentDatabaseVersion)
|
|
||||||
_, err = versionFile.Write([]byte(versionString))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func versionFilePath(dbPath string) string {
|
|
||||||
dbVersionFileName := path.Join(dbPath, "version")
|
|
||||||
return dbVersionFileName
|
|
||||||
}
|
|
@ -7,6 +7,8 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logger.RegisterSubSystem("KASD")
|
var log, _ = logger.Get(logger.SubsystemTags.KASD)
|
||||||
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
|
||||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -10,18 +8,7 @@ import (
|
|||||||
|
|
||||||
// DefaultTimeout is the default duration to wait for enqueuing/dequeuing
|
// DefaultTimeout is the default duration to wait for enqueuing/dequeuing
|
||||||
// to/from routes.
|
// to/from routes.
|
||||||
const DefaultTimeout = 120 * time.Second
|
const DefaultTimeout = 30 * time.Second
|
||||||
|
|
||||||
// ErrPeerWithSameIDExists signifies that a peer with the same ID already exist.
|
// ErrPeerWithSameIDExists signifies that a peer with the same ID already exist.
|
||||||
var ErrPeerWithSameIDExists = errors.New("ready peer with the same ID already exists")
|
var ErrPeerWithSameIDExists = errors.New("ready peer with the same ID already exists")
|
||||||
|
|
||||||
type flowExecuteFunc func(peer *peerpkg.Peer)
|
|
||||||
|
|
||||||
// Flow is a a data structure that is used in order to associate a p2p flow to some route in a router.
|
|
||||||
type Flow struct {
|
|
||||||
Name string
|
|
||||||
ExecuteFunc flowExecuteFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlowInitializeFunc is a function that is used in order to initialize a flow
|
|
||||||
type FlowInitializeFunc func(route *routerpkg.Route, peer *peerpkg.Peer) error
|
|
||||||
|
@ -1,73 +1,65 @@
|
|||||||
package flowcontext
|
package flowcontext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OnNewBlock updates the mempool after a new block arrival, and
|
// OnNewBlock updates the mempool after a new block arrival, and
|
||||||
// relays newly unorphaned transactions and possibly rebroadcast
|
// relays newly unorphaned transactions and possibly rebroadcast
|
||||||
// manually added transactions when not in IBD.
|
// manually added transactions when not in IBD.
|
||||||
func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error {
|
func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock,
|
||||||
|
blockInsertionResult *externalapi.BlockInsertionResult) error {
|
||||||
|
|
||||||
hash := consensushashing.BlockHash(block)
|
hash := consensushashing.BlockHash(block)
|
||||||
log.Tracef("OnNewBlock start for block %s", hash)
|
log.Debugf("OnNewBlock start for block %s", hash)
|
||||||
defer log.Tracef("OnNewBlock end for block %s", hash)
|
defer log.Debugf("OnNewBlock end for block %s", hash)
|
||||||
|
|
||||||
unorphanedBlocks, err := f.UnorphanBlocks(block)
|
unorphaningResults, err := f.UnorphanBlocks(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("OnNewBlock: block %s unorphaned %d blocks", hash, len(unorphanedBlocks))
|
log.Debugf("OnNewBlock: block %s unorphaned %d blocks", hash, len(unorphaningResults))
|
||||||
|
|
||||||
newBlocks := []*externalapi.DomainBlock{block}
|
newBlocks := []*externalapi.DomainBlock{block}
|
||||||
newBlocks = append(newBlocks, unorphanedBlocks...)
|
newBlockInsertionResults := []*externalapi.BlockInsertionResult{blockInsertionResult}
|
||||||
|
for _, unorphaningResult := range unorphaningResults {
|
||||||
|
newBlocks = append(newBlocks, unorphaningResult.block)
|
||||||
|
newBlockInsertionResults = append(newBlockInsertionResults, unorphaningResult.blockInsertionResult)
|
||||||
|
}
|
||||||
|
|
||||||
allAcceptedTransactions := make([]*externalapi.DomainTransaction, 0)
|
for i, newBlock := range newBlocks {
|
||||||
for _, newBlock := range newBlocks {
|
|
||||||
log.Debugf("OnNewBlock: passing block %s transactions to mining manager", hash)
|
log.Debugf("OnNewBlock: passing block %s transactions to mining manager", hash)
|
||||||
acceptedTransactions, err := f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions)
|
_, err = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
allAcceptedTransactions = append(allAcceptedTransactions, acceptedTransactions...)
|
|
||||||
|
if f.onBlockAddedToDAGHandler != nil {
|
||||||
|
log.Debugf("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash)
|
||||||
|
blockInsertionResult = newBlockInsertionResults[i]
|
||||||
|
err := f.onBlockAddedToDAGHandler(newBlock, blockInsertionResult)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.broadcastTransactionsAfterBlockAdded(newBlocks, allAcceptedTransactions)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnNewBlockTemplate calls the handler function whenever a new block template is available for miners.
|
|
||||||
func (f *FlowContext) OnNewBlockTemplate() error {
|
|
||||||
// Clear current template cache. Note we call this even if the handler is nil, in order to keep the
|
|
||||||
// state consistent without dependency on external event registration
|
|
||||||
f.Domain().MiningManager().ClearBlockTemplate()
|
|
||||||
if f.onNewBlockTemplateHandler != nil {
|
|
||||||
return f.onNewBlockTemplateHandler()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnPruningPointUTXOSetOverride calls the handler function whenever the UTXO set
|
|
||||||
// resets due to pruning point change via IBD.
|
|
||||||
func (f *FlowContext) OnPruningPointUTXOSetOverride() error {
|
|
||||||
if f.onPruningPointUTXOSetOverrideHandler != nil {
|
|
||||||
return f.onPruningPointUTXOSetOverrideHandler()
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
||||||
addedBlocks []*externalapi.DomainBlock, transactionsAcceptedToMempool []*externalapi.DomainTransaction) error {
|
block *externalapi.DomainBlock, transactionsAcceptedToMempool []*externalapi.DomainTransaction) error {
|
||||||
|
|
||||||
|
f.updateTransactionsToRebroadcast(block)
|
||||||
|
|
||||||
// Don't relay transactions when in IBD.
|
// Don't relay transactions when in IBD.
|
||||||
if f.IsIBDRunning() {
|
if f.IsIBDRunning() {
|
||||||
@ -76,12 +68,7 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
|||||||
|
|
||||||
var txIDsToRebroadcast []*externalapi.DomainTransactionID
|
var txIDsToRebroadcast []*externalapi.DomainTransactionID
|
||||||
if f.shouldRebroadcastTransactions() {
|
if f.shouldRebroadcastTransactions() {
|
||||||
txsToRebroadcast, err := f.Domain().MiningManager().RevalidateHighPriorityTransactions()
|
txIDsToRebroadcast = f.txIDsToRebroadcast()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
txIDsToRebroadcast = consensushashing.TransactionIDs(txsToRebroadcast)
|
|
||||||
f.lastRebroadcastTime = time.Now()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
txIDsToBroadcast := make([]*externalapi.DomainTransactionID, len(transactionsAcceptedToMempool)+len(txIDsToRebroadcast))
|
txIDsToBroadcast := make([]*externalapi.DomainTransactionID, len(transactionsAcceptedToMempool)+len(txIDsToRebroadcast))
|
||||||
@ -92,33 +79,33 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
|||||||
for i, txID := range txIDsToRebroadcast {
|
for i, txID := range txIDsToRebroadcast {
|
||||||
txIDsToBroadcast[offset+i] = txID
|
txIDsToBroadcast[offset+i] = txID
|
||||||
}
|
}
|
||||||
return f.EnqueueTransactionIDsForPropagation(txIDsToBroadcast)
|
|
||||||
|
if len(txIDsToBroadcast) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(txIDsToBroadcast) > appmessage.MaxInvPerTxInvMsg {
|
||||||
|
txIDsToBroadcast = txIDsToBroadcast[:appmessage.MaxInvPerTxInvMsg]
|
||||||
|
}
|
||||||
|
inv := appmessage.NewMsgInvTransaction(txIDsToBroadcast)
|
||||||
|
return f.Broadcast(inv)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SharedRequestedBlocks returns a *blockrelay.SharedRequestedBlocks for sharing
|
// SharedRequestedBlocks returns a *blockrelay.SharedRequestedBlocks for sharing
|
||||||
// data about requested blocks between different peers.
|
// data about requested blocks between different peers.
|
||||||
func (f *FlowContext) SharedRequestedBlocks() *SharedRequestedBlocks {
|
func (f *FlowContext) SharedRequestedBlocks() *blockrelay.SharedRequestedBlocks {
|
||||||
return f.sharedRequestedBlocks
|
return f.sharedRequestedBlocks
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddBlock adds the given block to the DAG and propagates it.
|
// AddBlock adds the given block to the DAG and propagates it.
|
||||||
func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
||||||
if len(block.Transactions) == 0 {
|
blockInsertionResult, err := f.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||||
return protocolerrors.Errorf(false, "cannot add header only block")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := f.Domain().Consensus().ValidateAndInsertBlock(block, true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
log.Warnf("Validation failed for block %s: %s", consensushashing.BlockHash(block), err)
|
log.Warnf("Validation failed for block %s: %s", consensushashing.BlockHash(block), err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = f.OnNewBlockTemplate()
|
err = f.OnNewBlock(block, blockInsertionResult)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = f.OnNewBlock(block)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -143,7 +130,7 @@ func (f *FlowContext) TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
f.ibdPeer = ibdPeer
|
f.ibdPeer = ibdPeer
|
||||||
log.Infof("IBD started with peer %s", ibdPeer)
|
log.Infof("IBD started")
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -158,6 +145,7 @@ func (f *FlowContext) UnsetIBDRunning() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.ibdPeer = nil
|
f.ibdPeer = nil
|
||||||
|
log.Infof("IBD finished")
|
||||||
}
|
}
|
||||||
|
|
||||||
// IBDPeer returns the current IBD peer or null if the node is not
|
// IBDPeer returns the current IBD peer or null if the node is not
|
||||||
|
@ -2,7 +2,6 @@ package flowcontext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
@ -10,11 +9,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrPingTimeout signifies that a ping operation timed out.
|
|
||||||
ErrPingTimeout = protocolerrors.New(false, "timeout expired on ping")
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandleError handles an error from a flow,
|
// HandleError handles an error from a flow,
|
||||||
// It sends the error to errChan if isStopping == 0 and increments isStopping
|
// It sends the error to errChan if isStopping == 0 and increments isStopping
|
||||||
//
|
//
|
||||||
@ -24,26 +18,14 @@ var (
|
|||||||
func (*FlowContext) HandleError(err error, flowName string, isStopping *uint32, errChan chan<- error) {
|
func (*FlowContext) HandleError(err error, flowName string, isStopping *uint32, errChan chan<- error) {
|
||||||
isErrRouteClosed := errors.Is(err, router.ErrRouteClosed)
|
isErrRouteClosed := errors.Is(err, router.ErrRouteClosed)
|
||||||
if !isErrRouteClosed {
|
if !isErrRouteClosed {
|
||||||
if protocolErr := (protocolerrors.ProtocolError{}); !errors.As(err, &protocolErr) {
|
if protocolErr := &(protocolerrors.ProtocolError{}); !errors.As(err, &protocolErr) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if errors.Is(err, ErrPingTimeout) {
|
|
||||||
// Avoid printing the call stack on ping timeouts, since users get panicked and this case is not interesting
|
|
||||||
log.Errorf("error from %s: %s", flowName, err)
|
log.Errorf("error from %s: %s", flowName, err)
|
||||||
} else {
|
|
||||||
// Explain to the user that this is not a panic, but only a protocol error with a specific peer
|
|
||||||
logFrame := strings.Repeat("=", 52)
|
|
||||||
log.Errorf("Non-critical peer protocol error from %s, printing the full stack for debug purposes: \n%s\n%+v \n%s",
|
|
||||||
flowName, logFrame, err, logFrame)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if atomic.AddUint32(isStopping, 1) == 1 {
|
if atomic.AddUint32(isStopping, 1) == 1 {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsRecoverableError returns whether the error is recoverable
|
|
||||||
func (*FlowContext) IsRecoverableError(err error) bool {
|
|
||||||
return err == nil || errors.Is(err, router.ErrRouteClosed) || errors.As(err, &protocolerrors.ProtocolError{})
|
|
||||||
}
|
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package flowcontext
|
package flowcontext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/util/mstime"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain"
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||||
@ -18,12 +19,9 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OnNewBlockTemplateHandler is a handler function that's triggered when a new block template is available
|
// OnBlockAddedToDAGHandler is a handler function that's triggered
|
||||||
type OnNewBlockTemplateHandler func() error
|
// when a block is added to the DAG
|
||||||
|
type OnBlockAddedToDAGHandler func(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error
|
||||||
// OnPruningPointUTXOSetOverrideHandler is a handle function that's triggered whenever the UTXO set
|
|
||||||
// resets due to pruning point change via IBD.
|
|
||||||
type OnPruningPointUTXOSetOverrideHandler func() error
|
|
||||||
|
|
||||||
// OnTransactionAddedToMempoolHandler is a handler function that's triggered
|
// OnTransactionAddedToMempoolHandler is a handler function that's triggered
|
||||||
// when a transaction is added to the mempool
|
// when a transaction is added to the mempool
|
||||||
@ -40,14 +38,15 @@ type FlowContext struct {
|
|||||||
|
|
||||||
timeStarted int64
|
timeStarted int64
|
||||||
|
|
||||||
onNewBlockTemplateHandler OnNewBlockTemplateHandler
|
onBlockAddedToDAGHandler OnBlockAddedToDAGHandler
|
||||||
onPruningPointUTXOSetOverrideHandler OnPruningPointUTXOSetOverrideHandler
|
|
||||||
onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler
|
onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler
|
||||||
|
|
||||||
|
transactionsToRebroadcastLock sync.Mutex
|
||||||
|
transactionsToRebroadcast map[externalapi.DomainTransactionID]*externalapi.DomainTransaction
|
||||||
lastRebroadcastTime time.Time
|
lastRebroadcastTime time.Time
|
||||||
sharedRequestedTransactions *SharedRequestedTransactions
|
sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions
|
||||||
|
|
||||||
sharedRequestedBlocks *SharedRequestedBlocks
|
sharedRequestedBlocks *blockrelay.SharedRequestedBlocks
|
||||||
|
|
||||||
ibdPeer *peerpkg.Peer
|
ibdPeer *peerpkg.Peer
|
||||||
ibdPeerMutex sync.RWMutex
|
ibdPeerMutex sync.RWMutex
|
||||||
@ -57,12 +56,6 @@ type FlowContext struct {
|
|||||||
|
|
||||||
orphans map[externalapi.DomainHash]*externalapi.DomainBlock
|
orphans map[externalapi.DomainHash]*externalapi.DomainBlock
|
||||||
orphansMutex sync.RWMutex
|
orphansMutex sync.RWMutex
|
||||||
|
|
||||||
transactionIDsToPropagate []*externalapi.DomainTransactionID
|
|
||||||
lastTransactionIDPropagationTime time.Time
|
|
||||||
transactionIDPropagationLock sync.Mutex
|
|
||||||
|
|
||||||
shutdownChan chan struct{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new instance of FlowContext.
|
// New returns a new instance of FlowContext.
|
||||||
@ -75,41 +68,18 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage
|
|||||||
domain: domain,
|
domain: domain,
|
||||||
addressManager: addressManager,
|
addressManager: addressManager,
|
||||||
connectionManager: connectionManager,
|
connectionManager: connectionManager,
|
||||||
sharedRequestedTransactions: NewSharedRequestedTransactions(),
|
sharedRequestedTransactions: transactionrelay.NewSharedRequestedTransactions(),
|
||||||
sharedRequestedBlocks: NewSharedRequestedBlocks(),
|
sharedRequestedBlocks: blockrelay.NewSharedRequestedBlocks(),
|
||||||
peers: make(map[id.ID]*peerpkg.Peer),
|
peers: make(map[id.ID]*peerpkg.Peer),
|
||||||
|
transactionsToRebroadcast: make(map[externalapi.DomainTransactionID]*externalapi.DomainTransaction),
|
||||||
orphans: make(map[externalapi.DomainHash]*externalapi.DomainBlock),
|
orphans: make(map[externalapi.DomainHash]*externalapi.DomainBlock),
|
||||||
timeStarted: mstime.Now().UnixMilliseconds(),
|
timeStarted: mstime.Now().UnixMilliseconds(),
|
||||||
transactionIDsToPropagate: []*externalapi.DomainTransactionID{},
|
|
||||||
lastTransactionIDPropagationTime: time.Now(),
|
|
||||||
shutdownChan: make(chan struct{}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close signals to all flows the the protocol manager is closed.
|
// SetOnBlockAddedToDAGHandler sets the onBlockAddedToDAG handler
|
||||||
func (f *FlowContext) Close() {
|
func (f *FlowContext) SetOnBlockAddedToDAGHandler(onBlockAddedToDAGHandler OnBlockAddedToDAGHandler) {
|
||||||
close(f.shutdownChan)
|
f.onBlockAddedToDAGHandler = onBlockAddedToDAGHandler
|
||||||
}
|
|
||||||
|
|
||||||
// ShutdownChan is a chan where flows can subscribe to shutdown
|
|
||||||
// event.
|
|
||||||
func (f *FlowContext) ShutdownChan() <-chan struct{} {
|
|
||||||
return f.shutdownChan
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNearlySynced returns whether current consensus is considered synced or close to being synced.
|
|
||||||
func (f *FlowContext) IsNearlySynced() (bool, error) {
|
|
||||||
return f.Domain().Consensus().IsNearlySynced()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOnNewBlockTemplateHandler sets the onNewBlockTemplateHandler handler
|
|
||||||
func (f *FlowContext) SetOnNewBlockTemplateHandler(onNewBlockTemplateHandler OnNewBlockTemplateHandler) {
|
|
||||||
f.onNewBlockTemplateHandler = onNewBlockTemplateHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOnPruningPointUTXOSetOverrideHandler sets the onPruningPointUTXOSetOverrideHandler handler
|
|
||||||
func (f *FlowContext) SetOnPruningPointUTXOSetOverrideHandler(onPruningPointUTXOSetOverrideHandler OnPruningPointUTXOSetOverrideHandler) {
|
|
||||||
f.onPruningPointUTXOSetOverrideHandler = onPruningPointUTXOSetOverrideHandler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetOnTransactionAddedToMempoolHandler sets the onTransactionAddedToMempool handler
|
// SetOnTransactionAddedToMempoolHandler sets the onTransactionAddedToMempool handler
|
||||||
|
@ -2,6 +2,8 @@ package flowcontext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logger.RegisterSubSystem("PROT")
|
var log, _ = logger.Get(logger.SubsystemTags.PROT)
|
||||||
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
@ -72,10 +72,3 @@ func (f *FlowContext) Peers() []*peerpkg.Peer {
|
|||||||
}
|
}
|
||||||
return peers
|
return peers
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasPeers returns whether there are currently active peers
|
|
||||||
func (f *FlowContext) HasPeers() bool {
|
|
||||||
f.peersMutex.RLock()
|
|
||||||
defer f.peersMutex.RUnlock()
|
|
||||||
return len(f.peers) > 0
|
|
||||||
}
|
|
||||||
|
@ -15,6 +15,12 @@ import (
|
|||||||
// on: 2^orphanResolutionRange * PHANTOM K.
|
// on: 2^orphanResolutionRange * PHANTOM K.
|
||||||
const maxOrphans = 600
|
const maxOrphans = 600
|
||||||
|
|
||||||
|
// UnorphaningResult is the result of unorphaning a block
|
||||||
|
type UnorphaningResult struct {
|
||||||
|
block *externalapi.DomainBlock
|
||||||
|
blockInsertionResult *externalapi.BlockInsertionResult
|
||||||
|
}
|
||||||
|
|
||||||
// AddOrphan adds the block to the orphan set
|
// AddOrphan adds the block to the orphan set
|
||||||
func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) {
|
func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) {
|
||||||
f.orphansMutex.Lock()
|
f.orphansMutex.Lock()
|
||||||
@ -51,7 +57,7 @@ func (f *FlowContext) IsOrphan(blockHash *externalapi.DomainHash) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnorphanBlocks removes the block from the orphan set, and remove all of the blocks that are not orphans anymore.
|
// UnorphanBlocks removes the block from the orphan set, and remove all of the blocks that are not orphans anymore.
|
||||||
func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*externalapi.DomainBlock, error) {
|
func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*UnorphaningResult, error) {
|
||||||
f.orphansMutex.Lock()
|
f.orphansMutex.Lock()
|
||||||
defer f.orphansMutex.Unlock()
|
defer f.orphansMutex.Unlock()
|
||||||
|
|
||||||
@ -60,17 +66,17 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*ext
|
|||||||
rootBlockHash := consensushashing.BlockHash(rootBlock)
|
rootBlockHash := consensushashing.BlockHash(rootBlock)
|
||||||
processQueue := f.addChildOrphansToProcessQueue(rootBlockHash, []externalapi.DomainHash{})
|
processQueue := f.addChildOrphansToProcessQueue(rootBlockHash, []externalapi.DomainHash{})
|
||||||
|
|
||||||
var unorphanedBlocks []*externalapi.DomainBlock
|
var unorphaningResults []*UnorphaningResult
|
||||||
for len(processQueue) > 0 {
|
for len(processQueue) > 0 {
|
||||||
var orphanHash externalapi.DomainHash
|
var orphanHash externalapi.DomainHash
|
||||||
orphanHash, processQueue = processQueue[0], processQueue[1:]
|
orphanHash, processQueue = processQueue[0], processQueue[1:]
|
||||||
orphanBlock := f.orphans[orphanHash]
|
orphanBlock := f.orphans[orphanHash]
|
||||||
|
|
||||||
log.Debugf("Considering to unorphan block %s with parents %s",
|
log.Debugf("Considering to unorphan block %s with parents %s",
|
||||||
orphanHash, orphanBlock.Header.DirectParents())
|
orphanHash, orphanBlock.Header.ParentHashes())
|
||||||
|
|
||||||
canBeUnorphaned := true
|
canBeUnorphaned := true
|
||||||
for _, orphanBlockParentHash := range orphanBlock.Header.DirectParents() {
|
for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes() {
|
||||||
orphanBlockParentInfo, err := f.domain.Consensus().GetBlockInfo(orphanBlockParentHash)
|
orphanBlockParentInfo, err := f.domain.Consensus().GetBlockInfo(orphanBlockParentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -84,18 +90,21 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*ext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if canBeUnorphaned {
|
if canBeUnorphaned {
|
||||||
unorphaningSucceeded, err := f.unorphanBlock(orphanHash)
|
blockInsertionResult, unorphaningSucceeded, err := f.unorphanBlock(orphanHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if unorphaningSucceeded {
|
if unorphaningSucceeded {
|
||||||
unorphanedBlocks = append(unorphanedBlocks, orphanBlock)
|
unorphaningResults = append(unorphaningResults, &UnorphaningResult{
|
||||||
|
block: orphanBlock,
|
||||||
|
blockInsertionResult: blockInsertionResult,
|
||||||
|
})
|
||||||
processQueue = f.addChildOrphansToProcessQueue(&orphanHash, processQueue)
|
processQueue = f.addChildOrphansToProcessQueue(&orphanHash, processQueue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return unorphanedBlocks, nil
|
return unorphaningResults, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// addChildOrphansToProcessQueue finds all child orphans of `blockHash`
|
// addChildOrphansToProcessQueue finds all child orphans of `blockHash`
|
||||||
@ -124,7 +133,7 @@ func (f *FlowContext) addChildOrphansToProcessQueue(blockHash *externalapi.Domai
|
|||||||
func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash) []externalapi.DomainHash {
|
func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash) []externalapi.DomainHash {
|
||||||
var childOrphans []externalapi.DomainHash
|
var childOrphans []externalapi.DomainHash
|
||||||
for orphanHash, orphanBlock := range f.orphans {
|
for orphanHash, orphanBlock := range f.orphans {
|
||||||
for _, orphanBlockParentHash := range orphanBlock.Header.DirectParents() {
|
for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes() {
|
||||||
if orphanBlockParentHash.Equal(blockHash) {
|
if orphanBlockParentHash.Equal(blockHash) {
|
||||||
childOrphans = append(childOrphans, orphanHash)
|
childOrphans = append(childOrphans, orphanHash)
|
||||||
break
|
break
|
||||||
@ -134,24 +143,24 @@ func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash)
|
|||||||
return childOrphans
|
return childOrphans
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (bool, error) {
|
func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externalapi.BlockInsertionResult, bool, error) {
|
||||||
orphanBlock, ok := f.orphans[orphanHash]
|
orphanBlock, ok := f.orphans[orphanHash]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false, errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash)
|
return nil, false, errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash)
|
||||||
}
|
}
|
||||||
delete(f.orphans, orphanHash)
|
delete(f.orphans, orphanHash)
|
||||||
|
|
||||||
err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock, true)
|
blockInsertionResult, err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
log.Warnf("Validation failed for orphan block %s: %s", orphanHash, err)
|
log.Warnf("Validation failed for orphan block %s: %s", orphanHash, err)
|
||||||
return false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
return false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Unorphaned block %s", orphanHash)
|
log.Infof("Unorphaned block %s", orphanHash)
|
||||||
return true, nil
|
return blockInsertionResult, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrphanRoots returns the roots of the missing ancestors DAG of the given orphan
|
// GetOrphanRoots returns the roots of the missing ancestors DAG of the given orphan
|
||||||
@ -192,7 +201,7 @@ func (f *FlowContext) GetOrphanRoots(orphan *externalapi.DomainHash) ([]*externa
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, parent := range block.Header.DirectParents() {
|
for _, parent := range block.Header.ParentHashes() {
|
||||||
if !addedToQueueSet.Contains(parent) {
|
if !addedToQueueSet.Contains(parent) {
|
||||||
queue = append(queue, parent)
|
queue = append(queue, parent)
|
||||||
addedToQueueSet.Add(parent)
|
addedToQueueSet.Add(parent)
|
||||||
|
43
app/protocol/flowcontext/should_mine.go
Normal file
43
app/protocol/flowcontext/should_mine.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package flowcontext
|
||||||
|
|
||||||
|
import "github.com/kaspanet/kaspad/util/mstime"
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 60 * 60 * 1000 // 1 Hour
|
||||||
|
)
|
||||||
|
|
||||||
|
// ShouldMine returns whether it's ok to use block template from this node
|
||||||
|
// for mining purposes.
|
||||||
|
func (f *FlowContext) ShouldMine() (bool, error) {
|
||||||
|
peers := f.Peers()
|
||||||
|
if len(peers) == 0 {
|
||||||
|
log.Debugf("The node is not connected, so ShouldMine returns false")
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.IsIBDRunning() {
|
||||||
|
log.Debugf("IBD is running, so ShouldMine returns false")
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualSelectedParent, err := f.domain.Consensus().GetVirtualSelectedParent()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualSelectedParentHeader, err := f.domain.Consensus().GetBlockHeader(virtualSelectedParent)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := mstime.Now().UnixMilliseconds()
|
||||||
|
if now-virtualSelectedParentHeader.TimeInMilliseconds() < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds {
|
||||||
|
log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true",
|
||||||
|
virtualSelectedParentHeader.TimeInMilliseconds())
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false",
|
||||||
|
virtualSelectedParentHeader.TimeInMilliseconds())
|
||||||
|
return false, nil
|
||||||
|
}
|
@ -4,22 +4,36 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TransactionIDPropagationInterval is the interval between transaction IDs propagations
|
|
||||||
const TransactionIDPropagationInterval = 500 * time.Millisecond
|
|
||||||
|
|
||||||
// AddTransaction adds transaction to the mempool and propagates it.
|
// AddTransaction adds transaction to the mempool and propagates it.
|
||||||
func (f *FlowContext) AddTransaction(tx *externalapi.DomainTransaction, allowOrphan bool) error {
|
func (f *FlowContext) AddTransaction(tx *externalapi.DomainTransaction) error {
|
||||||
acceptedTransactions, err := f.Domain().MiningManager().ValidateAndInsertTransaction(tx, true, allowOrphan)
|
f.transactionsToRebroadcastLock.Lock()
|
||||||
|
defer f.transactionsToRebroadcastLock.Unlock()
|
||||||
|
|
||||||
|
err := f.Domain().MiningManager().ValidateAndInsertTransaction(tx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptedTransactionIDs := consensushashing.TransactionIDs(acceptedTransactions)
|
transactionID := consensushashing.TransactionID(tx)
|
||||||
return f.EnqueueTransactionIDsForPropagation(acceptedTransactionIDs)
|
f.transactionsToRebroadcast[*transactionID] = tx
|
||||||
|
inv := appmessage.NewMsgInvTransaction([]*externalapi.DomainTransactionID{transactionID})
|
||||||
|
return f.Broadcast(inv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlowContext) updateTransactionsToRebroadcast(block *externalapi.DomainBlock) {
|
||||||
|
f.transactionsToRebroadcastLock.Lock()
|
||||||
|
defer f.transactionsToRebroadcastLock.Unlock()
|
||||||
|
// Note: if the block is red, its transactions won't be rebroadcasted
|
||||||
|
// anymore, although they are not included in the UTXO set.
|
||||||
|
// This is probably ok, since red blocks are quite rare.
|
||||||
|
for _, tx := range block.Transactions {
|
||||||
|
delete(f.transactionsToRebroadcast, *consensushashing.TransactionID(tx))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlowContext) shouldRebroadcastTransactions() bool {
|
func (f *FlowContext) shouldRebroadcastTransactions() bool {
|
||||||
@ -27,9 +41,22 @@ func (f *FlowContext) shouldRebroadcastTransactions() bool {
|
|||||||
return time.Since(f.lastRebroadcastTime) > rebroadcastInterval
|
return time.Since(f.lastRebroadcastTime) > rebroadcastInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FlowContext) txIDsToRebroadcast() []*externalapi.DomainTransactionID {
|
||||||
|
f.transactionsToRebroadcastLock.Lock()
|
||||||
|
defer f.transactionsToRebroadcastLock.Unlock()
|
||||||
|
|
||||||
|
txIDs := make([]*externalapi.DomainTransactionID, len(f.transactionsToRebroadcast))
|
||||||
|
i := 0
|
||||||
|
for _, tx := range f.transactionsToRebroadcast {
|
||||||
|
txIDs[i] = consensushashing.TransactionID(tx)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return txIDs
|
||||||
|
}
|
||||||
|
|
||||||
// SharedRequestedTransactions returns a *transactionrelay.SharedRequestedTransactions for sharing
|
// SharedRequestedTransactions returns a *transactionrelay.SharedRequestedTransactions for sharing
|
||||||
// data about requested transactions between different peers.
|
// data about requested transactions between different peers.
|
||||||
func (f *FlowContext) SharedRequestedTransactions() *SharedRequestedTransactions {
|
func (f *FlowContext) SharedRequestedTransactions() *transactionrelay.SharedRequestedTransactions {
|
||||||
return f.sharedRequestedTransactions
|
return f.sharedRequestedTransactions
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,42 +67,3 @@ func (f *FlowContext) OnTransactionAddedToMempool() {
|
|||||||
f.onTransactionAddedToMempoolHandler()
|
f.onTransactionAddedToMempoolHandler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnqueueTransactionIDsForPropagation add the given transactions IDs to a set of IDs to
|
|
||||||
// propagate. The IDs will be broadcast to all peers within a single transaction Inv message.
|
|
||||||
// The broadcast itself may happen only during a subsequent call to this method
|
|
||||||
func (f *FlowContext) EnqueueTransactionIDsForPropagation(transactionIDs []*externalapi.DomainTransactionID) error {
|
|
||||||
f.transactionIDPropagationLock.Lock()
|
|
||||||
defer f.transactionIDPropagationLock.Unlock()
|
|
||||||
|
|
||||||
f.transactionIDsToPropagate = append(f.transactionIDsToPropagate, transactionIDs...)
|
|
||||||
|
|
||||||
return f.maybePropagateTransactions()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlowContext) maybePropagateTransactions() error {
|
|
||||||
if time.Since(f.lastTransactionIDPropagationTime) < TransactionIDPropagationInterval &&
|
|
||||||
len(f.transactionIDsToPropagate) < appmessage.MaxInvPerTxInvMsg {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for len(f.transactionIDsToPropagate) > 0 {
|
|
||||||
transactionIDsToBroadcast := f.transactionIDsToPropagate
|
|
||||||
if len(transactionIDsToBroadcast) > appmessage.MaxInvPerTxInvMsg {
|
|
||||||
transactionIDsToBroadcast = f.transactionIDsToPropagate[:len(transactionIDsToBroadcast)]
|
|
||||||
}
|
|
||||||
log.Debugf("Transaction propagation: broadcasting %d transactions", len(transactionIDsToBroadcast))
|
|
||||||
|
|
||||||
inv := appmessage.NewMsgInvTransaction(transactionIDsToBroadcast)
|
|
||||||
err := f.Broadcast(inv)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
f.transactionIDsToPropagate = f.transactionIDsToPropagate[len(transactionIDsToBroadcast):]
|
|
||||||
}
|
|
||||||
|
|
||||||
f.lastTransactionIDPropagationTime = time.Now()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -35,5 +35,6 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou
|
|||||||
return protocolerrors.Errorf(true, "address count exceeded %d", addressmanager.GetAddressesMax)
|
return protocolerrors.Errorf(true, "address count exceeded %d", addressmanager.GetAddressesMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.AddressManager().AddAddresses(msgAddresses.AddressList...)
|
context.AddressManager().AddAddresses(msgAddresses.AddressList...)
|
||||||
|
return nil
|
||||||
}
|
}
|
29
app/protocol/flows/blockrelay/block_locator.go
Normal file
29
app/protocol/flows/blockrelay/block_locator.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package blockrelay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) sendGetBlockLocator(lowHash *externalapi.DomainHash,
|
||||||
|
highHash *externalapi.DomainHash, limit uint32) error {
|
||||||
|
|
||||||
|
msgGetBlockLocator := appmessage.NewMsgRequestBlockLocator(lowHash, highHash, limit)
|
||||||
|
return flow.outgoingRoute.Enqueue(msgGetBlockLocator)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) receiveBlockLocator() (blockLocatorHashes []*externalapi.DomainHash, err error) {
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msgBlockLocator, ok := message.(*appmessage.MsgBlockLocator)
|
||||||
|
if !ok {
|
||||||
|
return nil,
|
||||||
|
protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdBlockLocator, message.Command())
|
||||||
|
}
|
||||||
|
return msgBlockLocator.BlockLocatorHashes, nil
|
||||||
|
}
|
@ -33,7 +33,7 @@ func HandleIBDBlockLocator(context HandleIBDBlockLocatorContext, incomingRoute *
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !blockInfo.HasHeader() {
|
if !blockInfo.Exists {
|
||||||
return protocolerrors.Errorf(true, "received IBDBlockLocator "+
|
return protocolerrors.Errorf(true, "received IBDBlockLocator "+
|
||||||
"with an unknown targetHash %s", targetHash)
|
"with an unknown targetHash %s", targetHash)
|
||||||
}
|
}
|
||||||
@ -44,9 +44,7 @@ func HandleIBDBlockLocator(context HandleIBDBlockLocatorContext, incomingRoute *
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !blockInfo.Exists {
|
||||||
// The IBD block locator is checking only existing blocks with bodies.
|
|
||||||
if !blockInfo.HasBody() {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
"github.com/kaspanet/kaspad/domain"
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -27,15 +28,18 @@ func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute
|
|||||||
log.Debugf("Got request for %d ibd blocks", len(msgRequestIBDBlocks.Hashes))
|
log.Debugf("Got request for %d ibd blocks", len(msgRequestIBDBlocks.Hashes))
|
||||||
for i, hash := range msgRequestIBDBlocks.Hashes {
|
for i, hash := range msgRequestIBDBlocks.Hashes {
|
||||||
// Fetch the block from the database.
|
// Fetch the block from the database.
|
||||||
block, found, err := context.Domain().Consensus().GetBlock(hash)
|
blockInfo, err := context.Domain().Consensus().GetBlockInfo(hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !blockInfo.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
|
||||||
|
return protocolerrors.Errorf(true, "block %s not found", hash)
|
||||||
|
}
|
||||||
|
block, err := context.Domain().Consensus().GetBlock(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "unable to fetch requested block hash %s", hash)
|
return errors.Wrapf(err, "unable to fetch requested block hash %s", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
|
||||||
return protocolerrors.Errorf(false, "IBD block %s not found", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (Partial nodes): Convert block to partial block if needed
|
// TODO (Partial nodes): Convert block to partial block if needed
|
||||||
|
|
||||||
blockMessage := appmessage.DomainBlockToMsgBlock(block)
|
blockMessage := appmessage.DomainBlockToMsgBlock(block)
|
||||||
@ -44,7 +48,7 @@ func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debugf("sent %d out of %d", i+1, len(msgRequestIBDBlocks.Hashes))
|
log.Debugf("sent %d out of %d", i, len(msgRequestIBDBlocks.Hashes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package blockrelay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandlePruningPointHashRequestsFlowContext is the interface for the context needed for the handlePruningPointHashRequestsFlow flow.
|
||||||
|
type HandlePruningPointHashRequestsFlowContext interface {
|
||||||
|
Domain() domain.Domain
|
||||||
|
}
|
||||||
|
|
||||||
|
type handlePruningPointHashRequestsFlow struct {
|
||||||
|
HandlePruningPointHashRequestsFlowContext
|
||||||
|
incomingRoute, outgoingRoute *router.Route
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlePruningPointHashRequests listens to appmessage.MsgRequestPruningPointHashMessage messages and sends
|
||||||
|
// the pruning point hash as response.
|
||||||
|
func HandlePruningPointHashRequests(context HandlePruningPointHashRequestsFlowContext, incomingRoute,
|
||||||
|
outgoingRoute *router.Route) error {
|
||||||
|
flow := &handlePruningPointHashRequestsFlow{
|
||||||
|
HandlePruningPointHashRequestsFlowContext: context,
|
||||||
|
incomingRoute: incomingRoute,
|
||||||
|
outgoingRoute: outgoingRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handlePruningPointHashRequestsFlow) start() error {
|
||||||
|
for {
|
||||||
|
_, err := flow.incomingRoute.Dequeue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("Got request for a pruning point hash")
|
||||||
|
|
||||||
|
pruningPoint, err := flow.Domain().Consensus().PruningPoint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.outgoingRoute.Enqueue(appmessage.NewPruningPointHashMessage(pruningPoint))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("Sent pruning point hash %s", pruningPoint)
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
"github.com/kaspanet/kaspad/domain"
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -28,15 +29,18 @@ func HandleRelayBlockRequests(context RelayBlockRequestsContext, incomingRoute *
|
|||||||
log.Debugf("Got request for relay blocks with hashes %s", getRelayBlocksMessage.Hashes)
|
log.Debugf("Got request for relay blocks with hashes %s", getRelayBlocksMessage.Hashes)
|
||||||
for _, hash := range getRelayBlocksMessage.Hashes {
|
for _, hash := range getRelayBlocksMessage.Hashes {
|
||||||
// Fetch the block from the database.
|
// Fetch the block from the database.
|
||||||
block, found, err := context.Domain().Consensus().GetBlock(hash)
|
blockInfo, err := context.Domain().Consensus().GetBlockInfo(hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !blockInfo.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
|
||||||
|
return protocolerrors.Errorf(true, "block %s not found", hash)
|
||||||
|
}
|
||||||
|
block, err := context.Domain().Consensus().GetBlock(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "unable to fetch requested block hash %s", hash)
|
return errors.Wrapf(err, "unable to fetch requested block hash %s", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
|
||||||
return protocolerrors.Errorf(false, "Relay block %s not found", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (Partial nodes): Convert block to partial block if needed
|
// TODO (Partial nodes): Convert block to partial block if needed
|
||||||
|
|
||||||
err = outgoingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(block))
|
err = outgoingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(block))
|
@ -3,15 +3,12 @@ package blockrelay
|
|||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/flowcontext"
|
|
||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
"github.com/kaspanet/kaspad/domain"
|
"github.com/kaspanet/kaspad/domain"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -26,29 +23,22 @@ var orphanResolutionRange uint32 = 5
|
|||||||
type RelayInvsContext interface {
|
type RelayInvsContext interface {
|
||||||
Domain() domain.Domain
|
Domain() domain.Domain
|
||||||
Config() *config.Config
|
Config() *config.Config
|
||||||
OnNewBlock(block *externalapi.DomainBlock) error
|
OnNewBlock(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error
|
||||||
OnNewBlockTemplate() error
|
SharedRequestedBlocks() *SharedRequestedBlocks
|
||||||
OnPruningPointUTXOSetOverride() error
|
|
||||||
SharedRequestedBlocks() *flowcontext.SharedRequestedBlocks
|
|
||||||
Broadcast(message appmessage.Message) error
|
Broadcast(message appmessage.Message) error
|
||||||
AddOrphan(orphanBlock *externalapi.DomainBlock)
|
AddOrphan(orphanBlock *externalapi.DomainBlock)
|
||||||
GetOrphanRoots(orphanHash *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error)
|
GetOrphanRoots(orphanHash *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error)
|
||||||
IsOrphan(blockHash *externalapi.DomainHash) bool
|
IsOrphan(blockHash *externalapi.DomainHash) bool
|
||||||
IsIBDRunning() bool
|
IsIBDRunning() bool
|
||||||
IsRecoverableError(err error) bool
|
TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool
|
||||||
IsNearlySynced() (bool, error)
|
UnsetIBDRunning()
|
||||||
}
|
|
||||||
|
|
||||||
type invRelayBlock struct {
|
|
||||||
Hash *externalapi.DomainHash
|
|
||||||
IsOrphanRoot bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type handleRelayInvsFlow struct {
|
type handleRelayInvsFlow struct {
|
||||||
RelayInvsContext
|
RelayInvsContext
|
||||||
incomingRoute, outgoingRoute *router.Route
|
incomingRoute, outgoingRoute *router.Route
|
||||||
peer *peerpkg.Peer
|
peer *peerpkg.Peer
|
||||||
invsQueue []invRelayBlock
|
invsQueue []*appmessage.MsgInvRelayBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleRelayInvs listens to appmessage.MsgInvRelayBlock messages, requests their corresponding blocks if they
|
// HandleRelayInvs listens to appmessage.MsgInvRelayBlock messages, requests their corresponding blocks if they
|
||||||
@ -61,12 +51,9 @@ func HandleRelayInvs(context RelayInvsContext, incomingRoute *router.Route, outg
|
|||||||
incomingRoute: incomingRoute,
|
incomingRoute: incomingRoute,
|
||||||
outgoingRoute: outgoingRoute,
|
outgoingRoute: outgoingRoute,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
invsQueue: make([]invRelayBlock, 0),
|
invsQueue: make([]*appmessage.MsgInvRelayBlock, 0),
|
||||||
}
|
}
|
||||||
err := flow.start()
|
return flow.start()
|
||||||
// Currently, HandleRelayInvs flow is the only place where IBD is triggered, so the channel can be closed now
|
|
||||||
close(peer.IBDRequestChannel())
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) start() error {
|
func (flow *handleRelayInvsFlow) start() error {
|
||||||
@ -92,18 +79,7 @@ func (flow *handleRelayInvsFlow) start() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
isGenesisVirtualSelectedParent, err := flow.isGenesisVirtualSelectedParent()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if flow.IsOrphan(inv.Hash) {
|
if flow.IsOrphan(inv.Hash) {
|
||||||
if flow.Config().NetParams().DisallowDirectBlocksOnTopOfGenesis && !flow.Config().AllowSubmitBlockWhenNotSynced && isGenesisVirtualSelectedParent {
|
|
||||||
log.Infof("Cannot process orphan %s for a node with only the genesis block. The node needs to IBD "+
|
|
||||||
"to the recent pruning point before normal operation can resume.", inv.Hash)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Block %s is a known orphan. Requesting its missing ancestors", inv.Hash)
|
log.Debugf("Block %s is a known orphan. Requesting its missing ancestors", inv.Hash)
|
||||||
err := flow.AddOrphanRootsToQueue(inv.Hash)
|
err := flow.AddOrphanRootsToQueue(inv.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -112,17 +88,11 @@ func (flow *handleRelayInvsFlow) start() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block relay is disabled if the node is already during IBD AND considered out of sync
|
// Block relay is disabled during IBD
|
||||||
if flow.IsIBDRunning() {
|
if flow.IsIBDRunning() {
|
||||||
isNearlySynced, err := flow.IsNearlySynced()
|
log.Debugf("Got block %s while in IBD. continuing...", inv.Hash)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !isNearlySynced {
|
|
||||||
log.Debugf("Got block %s while in IBD and the node is out of sync. Continuing...", inv.Hash)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Requesting block %s", inv.Hash)
|
log.Debugf("Requesting block %s", inv.Hash)
|
||||||
block, exists, err := flow.requestBlock(inv.Hash)
|
block, exists, err := flow.requestBlock(inv.Hash)
|
||||||
@ -134,52 +104,9 @@ func (flow *handleRelayInvsFlow) start() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = flow.banIfBlockIsHeaderOnly(block)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if flow.Config().NetParams().DisallowDirectBlocksOnTopOfGenesis && !flow.Config().AllowSubmitBlockWhenNotSynced && !flow.Config().Devnet && flow.isChildOfGenesis(block) {
|
|
||||||
log.Infof("Cannot process %s because it's a direct child of genesis.", consensushashing.BlockHash(block))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note we do not apply the heuristic below if inv was queued as an orphan root, since
|
|
||||||
// that means the process started by a proper and relevant relay block
|
|
||||||
if !inv.IsOrphanRoot {
|
|
||||||
// Check bounded merge depth to avoid requesting irrelevant data which cannot be merged under virtual
|
|
||||||
virtualMergeDepthRoot, err := flow.Domain().Consensus().VirtualMergeDepthRoot()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !virtualMergeDepthRoot.Equal(model.VirtualGenesisBlockHash) {
|
|
||||||
mergeDepthRootHeader, err := flow.Domain().Consensus().GetBlockHeader(virtualMergeDepthRoot)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Since `BlueWork` respects topology, this condition means that the relay
|
|
||||||
// block is not in the future of virtual's merge depth root, and thus cannot be merged unless
|
|
||||||
// other valid blocks Kosherize it, in which case it will be obtained once the merger is relayed
|
|
||||||
if block.Header.BlueWork().Cmp(mergeDepthRootHeader.BlueWork()) <= 0 {
|
|
||||||
log.Debugf("Block %s has lower blue work than virtual's merge root %s (%d <= %d), hence we are skipping it",
|
|
||||||
inv.Hash, virtualMergeDepthRoot, block.Header.BlueWork(), mergeDepthRootHeader.BlueWork())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Processing block %s", inv.Hash)
|
log.Debugf("Processing block %s", inv.Hash)
|
||||||
oldVirtualInfo, err := flow.Domain().Consensus().GetVirtualInfo()
|
missingParents, blockInsertionResult, err := flow.processBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
missingParents, err := flow.processBlock(block)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, ruleerrors.ErrPrunedBlock) {
|
|
||||||
log.Infof("Ignoring pruned block %s", inv.Hash)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
log.Infof("Ignoring duplicate block %s", inv.Hash)
|
log.Infof("Ignoring duplicate block %s", inv.Hash)
|
||||||
continue
|
continue
|
||||||
@ -188,99 +115,55 @@ func (flow *handleRelayInvsFlow) start() error {
|
|||||||
}
|
}
|
||||||
if len(missingParents) > 0 {
|
if len(missingParents) > 0 {
|
||||||
log.Debugf("Block %s is orphan and has missing parents: %s", inv.Hash, missingParents)
|
log.Debugf("Block %s is orphan and has missing parents: %s", inv.Hash, missingParents)
|
||||||
err := flow.processOrphan(block)
|
err := flow.processOrphan(block, missingParents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
oldVirtualParents := hashset.New()
|
log.Debugf("Relaying block %s", inv.Hash)
|
||||||
for _, parent := range oldVirtualInfo.ParentHashes {
|
|
||||||
oldVirtualParents.Add(parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
newVirtualInfo, err := flow.Domain().Consensus().GetVirtualInfo()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
virtualHasNewParents := false
|
|
||||||
for _, parent := range newVirtualInfo.ParentHashes {
|
|
||||||
if oldVirtualParents.Contains(parent) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
virtualHasNewParents = true
|
|
||||||
block, found, err := flow.Domain().Consensus().GetBlock(parent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return protocolerrors.Errorf(false, "Virtual parent %s not found", parent)
|
|
||||||
}
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
|
||||||
log.Debugf("Relaying block %s", blockHash)
|
|
||||||
err = flow.relayBlock(block)
|
err = flow.relayBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if virtualHasNewParents {
|
|
||||||
log.Debugf("Virtual %d has new parents, raising new block template event", newVirtualInfo.DAAScore)
|
|
||||||
err = flow.OnNewBlockTemplate()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Accepted block %s via relay", inv.Hash)
|
log.Infof("Accepted block %s via relay", inv.Hash)
|
||||||
err = flow.OnNewBlock(block)
|
err = flow.OnNewBlock(block, blockInsertionResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) banIfBlockIsHeaderOnly(block *externalapi.DomainBlock) error {
|
func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) {
|
||||||
if len(block.Transactions) == 0 {
|
|
||||||
return protocolerrors.Errorf(true, "sent header of %s block where expected block with body",
|
|
||||||
consensushashing.BlockHash(block))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) readInv() (invRelayBlock, error) {
|
|
||||||
if len(flow.invsQueue) > 0 {
|
if len(flow.invsQueue) > 0 {
|
||||||
var inv invRelayBlock
|
var inv *appmessage.MsgInvRelayBlock
|
||||||
inv, flow.invsQueue = flow.invsQueue[0], flow.invsQueue[1:]
|
inv, flow.invsQueue = flow.invsQueue[0], flow.invsQueue[1:]
|
||||||
return inv, nil
|
return inv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, err := flow.incomingRoute.Dequeue()
|
msg, err := flow.incomingRoute.Dequeue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return invRelayBlock{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
msgInv, ok := msg.(*appmessage.MsgInvRelayBlock)
|
inv, ok := msg.(*appmessage.MsgInvRelayBlock)
|
||||||
if !ok {
|
if !ok {
|
||||||
return invRelayBlock{}, protocolerrors.Errorf(true, "unexpected %s message in the block relay handleRelayInvsFlow while "+
|
return nil, protocolerrors.Errorf(true, "unexpected %s message in the block relay handleRelayInvsFlow while "+
|
||||||
"expecting an inv message", msg.Command())
|
"expecting an inv message", msg.Command())
|
||||||
}
|
}
|
||||||
return invRelayBlock{Hash: msgInv.Hash, IsOrphanRoot: false}, nil
|
return inv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) requestBlock(requestHash *externalapi.DomainHash) (*externalapi.DomainBlock, bool, error) {
|
func (flow *handleRelayInvsFlow) requestBlock(requestHash *externalapi.DomainHash) (*externalapi.DomainBlock, bool, error) {
|
||||||
exists := flow.SharedRequestedBlocks().AddIfNotExists(requestHash)
|
exists := flow.SharedRequestedBlocks().addIfNotExists(requestHash)
|
||||||
if exists {
|
if exists {
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case the function returns earlier than expected, we want to make sure flow.SharedRequestedBlocks() is
|
// In case the function returns earlier than expected, we want to make sure flow.SharedRequestedBlocks() is
|
||||||
// clean from any pending blocks.
|
// clean from any pending blocks.
|
||||||
defer flow.SharedRequestedBlocks().Remove(requestHash)
|
defer flow.SharedRequestedBlocks().remove(requestHash)
|
||||||
|
|
||||||
getRelayBlocksMsg := appmessage.NewMsgRequestRelayBlocks([]*externalapi.DomainHash{requestHash})
|
getRelayBlocksMsg := appmessage.NewMsgRequestRelayBlocks([]*externalapi.DomainHash{requestHash})
|
||||||
err := flow.outgoingRoute.Enqueue(getRelayBlocksMsg)
|
err := flow.outgoingRoute.Enqueue(getRelayBlocksMsg)
|
||||||
@ -314,7 +197,7 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock,
|
|||||||
|
|
||||||
switch message := message.(type) {
|
switch message := message.(type) {
|
||||||
case *appmessage.MsgInvRelayBlock:
|
case *appmessage.MsgInvRelayBlock:
|
||||||
flow.invsQueue = append(flow.invsQueue, invRelayBlock{Hash: message.Hash, IsOrphanRoot: false})
|
flow.invsQueue = append(flow.invsQueue, message)
|
||||||
case *appmessage.MsgBlock:
|
case *appmessage.MsgBlock:
|
||||||
return message, nil
|
return message, nil
|
||||||
default:
|
default:
|
||||||
@ -323,25 +206,22 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) {
|
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) {
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
err := flow.Domain().Consensus().ValidateAndInsertBlock(block, true)
|
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
return nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
return nil, nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
missingParentsError := &ruleerrors.ErrMissingParents{}
|
missingParentsError := &ruleerrors.ErrMissingParents{}
|
||||||
if errors.As(err, missingParentsError) {
|
if errors.As(err, missingParentsError) {
|
||||||
return missingParentsError.MissingParentHashes, nil
|
return missingParentsError.MissingParentHashes, nil, nil
|
||||||
}
|
}
|
||||||
// A duplicate block should not appear to the user as a warning and is already reported in the calling function
|
|
||||||
if !errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
|
||||||
log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err)
|
log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err)
|
||||||
|
return nil, nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
||||||
}
|
}
|
||||||
return nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
return nil, blockInsertionResult, nil
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) relayBlock(block *externalapi.DomainBlock) error {
|
func (flow *handleRelayInvsFlow) relayBlock(block *externalapi.DomainBlock) error {
|
||||||
@ -349,7 +229,7 @@ func (flow *handleRelayInvsFlow) relayBlock(block *externalapi.DomainBlock) erro
|
|||||||
return flow.Broadcast(appmessage.NewMsgInvBlock(blockHash))
|
return flow.Broadcast(appmessage.NewMsgInvBlock(blockHash))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock) error {
|
func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock, missingParents []*externalapi.DomainHash) error {
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
|
||||||
// Return if the block has been orphaned from elsewhere already
|
// Return if the block has been orphaned from elsewhere already
|
||||||
@ -364,19 +244,6 @@ func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock) e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if isBlockInOrphanResolutionRange {
|
if isBlockInOrphanResolutionRange {
|
||||||
if flow.Config().NetParams().DisallowDirectBlocksOnTopOfGenesis && !flow.Config().AllowSubmitBlockWhenNotSynced {
|
|
||||||
isGenesisVirtualSelectedParent, err := flow.isGenesisVirtualSelectedParent()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if isGenesisVirtualSelectedParent {
|
|
||||||
log.Infof("Cannot process orphan %s for a node with only the genesis block. The node needs to IBD "+
|
|
||||||
"to the recent pruning point before normal operation can resume.", blockHash)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Block %s is within orphan resolution range. "+
|
log.Debugf("Block %s is within orphan resolution range. "+
|
||||||
"Adding it to the orphan set", blockHash)
|
"Adding it to the orphan set", blockHash)
|
||||||
flow.AddOrphan(block)
|
flow.AddOrphan(block)
|
||||||
@ -387,28 +254,7 @@ func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock) e
|
|||||||
// Start IBD unless we already are in IBD
|
// Start IBD unless we already are in IBD
|
||||||
log.Debugf("Block %s is out of orphan resolution range. "+
|
log.Debugf("Block %s is out of orphan resolution range. "+
|
||||||
"Attempting to start IBD against it.", blockHash)
|
"Attempting to start IBD against it.", blockHash)
|
||||||
|
return flow.runIBDIfNotRunning(blockHash)
|
||||||
// Send the block to IBD flow via the IBDRequestChannel.
|
|
||||||
// Note that this is a non-blocking send, since if IBD is already running, there is no need to trigger it
|
|
||||||
select {
|
|
||||||
case flow.peer.IBDRequestChannel() <- block:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) isGenesisVirtualSelectedParent() (bool, error) {
|
|
||||||
virtualSelectedParent, err := flow.Domain().Consensus().GetVirtualSelectedParent()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return virtualSelectedParent.Equal(flow.Config().NetParams().GenesisHash), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) isChildOfGenesis(block *externalapi.DomainBlock) bool {
|
|
||||||
parents := block.Header.DirectParents()
|
|
||||||
return len(parents) == 1 && parents[0].Equal(flow.Config().NetParams().GenesisHash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isBlockInOrphanResolutionRange finds out whether the given blockHash should be
|
// isBlockInOrphanResolutionRange finds out whether the given blockHash should be
|
||||||
@ -417,7 +263,8 @@ func (flow *handleRelayInvsFlow) isChildOfGenesis(block *externalapi.DomainBlock
|
|||||||
// In the response, if we know none of the hashes, we should retrieve the given
|
// In the response, if we know none of the hashes, we should retrieve the given
|
||||||
// blockHash via IBD. Otherwise, via unorphaning.
|
// blockHash via IBD. Otherwise, via unorphaning.
|
||||||
func (flow *handleRelayInvsFlow) isBlockInOrphanResolutionRange(blockHash *externalapi.DomainHash) (bool, error) {
|
func (flow *handleRelayInvsFlow) isBlockInOrphanResolutionRange(blockHash *externalapi.DomainHash) (bool, error) {
|
||||||
err := flow.sendGetBlockLocator(blockHash, orphanResolutionRange)
|
lowHash := flow.Config().ActiveNetParams.GenesisHash
|
||||||
|
err := flow.sendGetBlockLocator(lowHash, blockHash, orphanResolutionRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -449,16 +296,12 @@ func (flow *handleRelayInvsFlow) AddOrphanRootsToQueue(orphan *externalapi.Domai
|
|||||||
"probably happened because it was randomly evicted immediately after it was added.", orphan)
|
"probably happened because it was randomly evicted immediately after it was added.", orphan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(orphanRoots) == 0 {
|
|
||||||
// In some rare cases we get here when there are no orphan roots already
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
log.Infof("Block %s has %d missing ancestors. Adding them to the invs queue...", orphan, len(orphanRoots))
|
log.Infof("Block %s has %d missing ancestors. Adding them to the invs queue...", orphan, len(orphanRoots))
|
||||||
|
|
||||||
invMessages := make([]invRelayBlock, len(orphanRoots))
|
invMessages := make([]*appmessage.MsgInvRelayBlock, len(orphanRoots))
|
||||||
for i, root := range orphanRoots {
|
for i, root := range orphanRoots {
|
||||||
log.Debugf("Adding block %s missing ancestor %s to the invs queue", orphan, root)
|
log.Debugf("Adding block %s missing ancestor %s to the invs queue", orphan, root)
|
||||||
invMessages[i] = invRelayBlock{Hash: root, IsOrphanRoot: true}
|
invMessages[i] = appmessage.NewMsgInvBlock(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
flow.invsQueue = append(invMessages, flow.invsQueue...)
|
flow.invsQueue = append(invMessages, flow.invsQueue...)
|
@ -32,19 +32,20 @@ func HandleRequestBlockLocator(context RequestBlockLocatorContext, incomingRoute
|
|||||||
|
|
||||||
func (flow *handleRequestBlockLocatorFlow) start() error {
|
func (flow *handleRequestBlockLocatorFlow) start() error {
|
||||||
for {
|
for {
|
||||||
highHash, limit, err := flow.receiveGetBlockLocator()
|
lowHash, highHash, limit, err := flow.receiveGetBlockLocator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debugf("Received getBlockLocator with highHash: %s, limit: %d", highHash, limit)
|
log.Debugf("Received getBlockLocator with lowHash: %s, highHash: %s, limit: %d",
|
||||||
|
lowHash, highHash, limit)
|
||||||
|
|
||||||
locator, err := flow.Domain().Consensus().CreateBlockLocatorFromPruningPoint(highHash, limit)
|
locator, err := flow.Domain().Consensus().CreateBlockLocator(lowHash, highHash, limit)
|
||||||
if err != nil || len(locator) == 0 {
|
if err != nil || len(locator) == 0 {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Received error from CreateBlockLocatorFromPruningPoint: %s", err)
|
log.Debugf("Received error from CreateBlockLocator: %s", err)
|
||||||
}
|
}
|
||||||
return protocolerrors.Errorf(true, "couldn't build a block "+
|
return protocolerrors.Errorf(true, "couldn't build a block "+
|
||||||
"locator between the pruning point and %s", highHash)
|
"locator between blocks %s and %s", lowHash, highHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = flow.sendBlockLocator(locator)
|
err = flow.sendBlockLocator(locator)
|
||||||
@ -54,15 +55,16 @@ func (flow *handleRequestBlockLocatorFlow) start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRequestBlockLocatorFlow) receiveGetBlockLocator() (highHash *externalapi.DomainHash, limit uint32, err error) {
|
func (flow *handleRequestBlockLocatorFlow) receiveGetBlockLocator() (lowHash *externalapi.DomainHash,
|
||||||
|
highHash *externalapi.DomainHash, limit uint32, err error) {
|
||||||
|
|
||||||
message, err := flow.incomingRoute.Dequeue()
|
message, err := flow.incomingRoute.Dequeue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
msgGetBlockLocator := message.(*appmessage.MsgRequestBlockLocator)
|
msgGetBlockLocator := message.(*appmessage.MsgRequestBlockLocator)
|
||||||
|
|
||||||
return msgGetBlockLocator.HighHash, msgGetBlockLocator.Limit, nil
|
return msgGetBlockLocator.LowHash, msgGetBlockLocator.HighHash, msgGetBlockLocator.Limit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRequestBlockLocatorFlow) sendBlockLocator(locator externalapi.BlockLocator) error {
|
func (flow *handleRequestBlockLocatorFlow) sendBlockLocator(locator externalapi.BlockLocator) error {
|
@ -10,27 +10,25 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This constant must be equal at both syncer and syncee. Therefore, never (!!) change this constant unless a new p2p
|
const ibdBatchSize = router.DefaultMaxMessages
|
||||||
// version is introduced. See `TestIBDBatchSizeLessThanRouteCapacity` as well.
|
|
||||||
const ibdBatchSize = 99
|
|
||||||
|
|
||||||
// RequestHeadersContext is the interface for the context needed for the HandleRequestHeaders flow.
|
// RequestIBDBlocksContext is the interface for the context needed for the HandleRequestHeaders flow.
|
||||||
type RequestHeadersContext interface {
|
type RequestIBDBlocksContext interface {
|
||||||
Domain() domain.Domain
|
Domain() domain.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
type handleRequestHeadersFlow struct {
|
type handleRequestBlocksFlow struct {
|
||||||
RequestHeadersContext
|
RequestIBDBlocksContext
|
||||||
incomingRoute, outgoingRoute *router.Route
|
incomingRoute, outgoingRoute *router.Route
|
||||||
peer *peer.Peer
|
peer *peer.Peer
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleRequestHeaders handles RequestHeaders messages
|
// HandleRequestHeaders handles RequestHeaders messages
|
||||||
func HandleRequestHeaders(context RequestHeadersContext, incomingRoute *router.Route,
|
func HandleRequestHeaders(context RequestIBDBlocksContext, incomingRoute *router.Route,
|
||||||
outgoingRoute *router.Route, peer *peer.Peer) error {
|
outgoingRoute *router.Route, peer *peer.Peer) error {
|
||||||
|
|
||||||
flow := &handleRequestHeadersFlow{
|
flow := &handleRequestBlocksFlow{
|
||||||
RequestHeadersContext: context,
|
RequestIBDBlocksContext: context,
|
||||||
incomingRoute: incomingRoute,
|
incomingRoute: incomingRoute,
|
||||||
outgoingRoute: outgoingRoute,
|
outgoingRoute: outgoingRoute,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
@ -38,49 +36,21 @@ func HandleRequestHeaders(context RequestHeadersContext, incomingRoute *router.R
|
|||||||
return flow.start()
|
return flow.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRequestHeadersFlow) start() error {
|
func (flow *handleRequestBlocksFlow) start() error {
|
||||||
for {
|
for {
|
||||||
lowHash, highHash, err := receiveRequestHeaders(flow.incomingRoute)
|
lowHash, highHash, err := receiveRequestHeaders(flow.incomingRoute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debugf("Received requestHeaders with lowHash: %s, highHash: %s", lowHash, highHash)
|
log.Debugf("Recieved requestHeaders with lowHash: %s, highHash: %s", lowHash, highHash)
|
||||||
|
|
||||||
consensus := flow.Domain().Consensus()
|
|
||||||
|
|
||||||
lowHashInfo, err := consensus.GetBlockInfo(lowHash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !lowHashInfo.HasHeader() {
|
|
||||||
return protocolerrors.Errorf(true, "Block %s does not exist", lowHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
highHashInfo, err := consensus.GetBlockInfo(highHash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !highHashInfo.HasHeader() {
|
|
||||||
return protocolerrors.Errorf(true, "Block %s does not exist", highHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
isLowSelectedAncestorOfHigh, err := consensus.IsInSelectedParentChainOf(lowHash, highHash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !isLowSelectedAncestorOfHigh {
|
|
||||||
return protocolerrors.Errorf(true, "Expected %s to be on the selected chain of %s",
|
|
||||||
lowHash, highHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
for !lowHash.Equal(highHash) {
|
for !lowHash.Equal(highHash) {
|
||||||
log.Debugf("Getting block headers between %s and %s to %s", lowHash, highHash, flow.peer)
|
log.Debugf("Getting block headers between %s and %s to %s", lowHash, highHash, flow.peer)
|
||||||
|
|
||||||
// GetHashesBetween is a relatively heavy operation so we limit it
|
// GetHashesBetween is a relatively heavy operation so we limit it
|
||||||
// in order to avoid locking the consensus for too long
|
// in order to avoid locking the consensus for too long
|
||||||
// maxBlocks MUST be >= MergeSetSizeLimit + 1
|
const maxBlueScoreDifference = 1 << 10
|
||||||
const maxBlocks = 1 << 10
|
blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference)
|
||||||
blockHashes, _, err := consensus.GetHashesBetween(lowHash, highHash, maxBlocks)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -88,7 +58,7 @@ func (flow *handleRequestHeadersFlow) start() error {
|
|||||||
|
|
||||||
blockHeaders := make([]*appmessage.MsgBlockHeader, len(blockHashes))
|
blockHeaders := make([]*appmessage.MsgBlockHeader, len(blockHashes))
|
||||||
for i, blockHash := range blockHashes {
|
for i, blockHash := range blockHashes {
|
||||||
blockHeader, err := consensus.GetBlockHeader(blockHash)
|
blockHeader, err := flow.Domain().Consensus().GetBlockHeader(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
package blockrelay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleRequestPruningPointUTXOSetAndBlockContext is the interface for the context needed for the HandleRequestPruningPointUTXOSetAndBlock flow.
|
||||||
|
type HandleRequestPruningPointUTXOSetAndBlockContext interface {
|
||||||
|
Domain() domain.Domain
|
||||||
|
}
|
||||||
|
|
||||||
|
type handleRequestPruningPointUTXOSetAndBlockFlow struct {
|
||||||
|
HandleRequestPruningPointUTXOSetAndBlockContext
|
||||||
|
incomingRoute, outgoingRoute *router.Route
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleRequestPruningPointUTXOSetAndBlock listens to appmessage.MsgRequestPruningPointUTXOSetAndBlock messages and sends
|
||||||
|
// the pruning point UTXO set and block body.
|
||||||
|
func HandleRequestPruningPointUTXOSetAndBlock(context HandleRequestPruningPointUTXOSetAndBlockContext, incomingRoute,
|
||||||
|
outgoingRoute *router.Route) error {
|
||||||
|
flow := &handleRequestPruningPointUTXOSetAndBlockFlow{
|
||||||
|
HandleRequestPruningPointUTXOSetAndBlockContext: context,
|
||||||
|
incomingRoute: incomingRoute,
|
||||||
|
outgoingRoute: outgoingRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) start() error {
|
||||||
|
for {
|
||||||
|
msgRequestPruningPointUTXOSetAndBlock, err := flow.waitForRequestPruningPointUTXOSetAndBlockMessages()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.handleRequestPruningPointUTXOSetAndBlockMessage(msgRequestPruningPointUTXOSetAndBlock)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) handleRequestPruningPointUTXOSetAndBlockMessage(
|
||||||
|
msgRequestPruningPointUTXOSetAndBlock *appmessage.MsgRequestPruningPointUTXOSetAndBlock) error {
|
||||||
|
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "handleRequestPruningPointUTXOSetAndBlockFlow")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
|
log.Debugf("Got request for PruningPointHash UTXOSet and Block")
|
||||||
|
|
||||||
|
err := flow.sendPruningPointBlock(msgRequestPruningPointUTXOSetAndBlock)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow.sendPruningPointUTXOSet(msgRequestPruningPointUTXOSetAndBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) waitForRequestPruningPointUTXOSetAndBlockMessages() (
|
||||||
|
*appmessage.MsgRequestPruningPointUTXOSetAndBlock, error) {
|
||||||
|
|
||||||
|
message, err := flow.incomingRoute.Dequeue()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msgRequestPruningPointUTXOSetAndBlock, ok := message.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock)
|
||||||
|
if !ok {
|
||||||
|
return nil, protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdRequestPruningPointUTXOSetAndBlock, message.Command())
|
||||||
|
}
|
||||||
|
return msgRequestPruningPointUTXOSetAndBlock, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) sendPruningPointBlock(
|
||||||
|
msgRequestPruningPointUTXOSetAndBlock *appmessage.MsgRequestPruningPointUTXOSetAndBlock) error {
|
||||||
|
|
||||||
|
block, err := flow.Domain().Consensus().GetBlock(msgRequestPruningPointUTXOSetAndBlock.PruningPointHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("Retrieved pruning block %s", msgRequestPruningPointUTXOSetAndBlock.PruningPointHash)
|
||||||
|
|
||||||
|
return flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(block)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) sendPruningPointUTXOSet(
|
||||||
|
msgRequestPruningPointUTXOSetAndBlock *appmessage.MsgRequestPruningPointUTXOSetAndBlock) error {
|
||||||
|
|
||||||
|
// Send the UTXO set in `step`-sized chunks
|
||||||
|
const step = 1000
|
||||||
|
var fromOutpoint *externalapi.DomainOutpoint
|
||||||
|
chunksSent := 0
|
||||||
|
for {
|
||||||
|
pruningPointUTXOs, err := flow.Domain().Consensus().GetPruningPointUTXOs(
|
||||||
|
msgRequestPruningPointUTXOSetAndBlock.PruningPointHash, fromOutpoint, step)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, ruleerrors.ErrWrongPruningPointHash) {
|
||||||
|
return flow.outgoingRoute.Enqueue(appmessage.NewMsgUnexpectedPruningPoint())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Retrieved %d UTXOs for pruning block %s",
|
||||||
|
len(pruningPointUTXOs), msgRequestPruningPointUTXOSetAndBlock.PruningPointHash)
|
||||||
|
|
||||||
|
outpointAndUTXOEntryPairs :=
|
||||||
|
appmessage.DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(pruningPointUTXOs)
|
||||||
|
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgPruningPointUTXOSetChunk(outpointAndUTXOEntryPairs))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pruningPointUTXOs) < step {
|
||||||
|
log.Debugf("Finished sending UTXOs for pruning block %s",
|
||||||
|
msgRequestPruningPointUTXOSetAndBlock.PruningPointHash)
|
||||||
|
|
||||||
|
return flow.outgoingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks())
|
||||||
|
}
|
||||||
|
|
||||||
|
fromOutpoint = pruningPointUTXOs[len(pruningPointUTXOs)-1].Outpoint
|
||||||
|
chunksSent++
|
||||||
|
|
||||||
|
// Wait for the peer to request more chunks every `ibdBatchSize` chunks
|
||||||
|
if chunksSent%ibdBatchSize == 0 {
|
||||||
|
message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, ok := message.(*appmessage.MsgRequestNextPruningPointUTXOSetChunk)
|
||||||
|
if !ok {
|
||||||
|
return protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdRequestNextPruningPointUTXOSetChunk, message.Command())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
567
app/protocol/flows/blockrelay/ibd.go
Normal file
567
app/protocol/flows/blockrelay/ibd.go
Normal file
@ -0,0 +1,567 @@
|
|||||||
|
package blockrelay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.DomainHash) error {
|
||||||
|
wasIBDNotRunning := flow.TrySetIBDRunning(flow.peer)
|
||||||
|
if !wasIBDNotRunning {
|
||||||
|
log.Debugf("IBD is already running")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer flow.UnsetIBDRunning()
|
||||||
|
|
||||||
|
log.Debugf("IBD started with peer %s and highHash %s", flow.peer, highHash)
|
||||||
|
|
||||||
|
log.Debugf("Syncing headers up to %s", highHash)
|
||||||
|
headersSynced, err := flow.syncHeaders(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !headersSynced {
|
||||||
|
log.Debugf("Aborting IBD because the headers failed to sync")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Debugf("Finished syncing headers up to %s", highHash)
|
||||||
|
|
||||||
|
log.Debugf("Syncing the current pruning point UTXO set")
|
||||||
|
syncedPruningPointUTXOSetSuccessfully, err := flow.syncPruningPointUTXOSet()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !syncedPruningPointUTXOSetSuccessfully {
|
||||||
|
log.Debugf("Aborting IBD because the pruning point UTXO set failed to sync")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Debugf("Finished syncing the current pruning point UTXO set")
|
||||||
|
|
||||||
|
log.Debugf("Downloading block bodies up to %s", highHash)
|
||||||
|
err = flow.syncMissingBlockBodies(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("Finished downloading block bodies up to %s", highHash)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncHeaders attempts to sync headers from the peer. This method may fail
|
||||||
|
// because the peer and us have conflicting pruning points. In that case we
|
||||||
|
// return (false, nil) so that we may stop IBD gracefully.
|
||||||
|
func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) (bool, error) {
|
||||||
|
log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash)
|
||||||
|
highestSharedBlockHash, highestSharedBlockFound, err := flow.findHighestSharedBlockHash(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !highestSharedBlockFound {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer)
|
||||||
|
|
||||||
|
err = flow.downloadHeaders(highestSharedBlockHash, highHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the highHash has not been received, the peer is misbehaving
|
||||||
|
highHashBlockInfo, err := flow.Domain().Consensus().GetBlockInfo(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !highHashBlockInfo.Exists {
|
||||||
|
return false, protocolerrors.Errorf(true, "did not receive "+
|
||||||
|
"highHash header %s from peer %s during header download", highHash, flow.peer)
|
||||||
|
}
|
||||||
|
log.Debugf("Headers downloaded from peer %s", flow.peer)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// findHighestSharedBlock attempts to find the highest shared block between the peer
|
||||||
|
// and this node. This method may fail because the peer and us have conflicting pruning
|
||||||
|
// points. In that case we return (nil, false, nil) so that we may stop IBD gracefully.
|
||||||
|
func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(
|
||||||
|
targetHash *externalapi.DomainHash) (*externalapi.DomainHash, bool, error) {
|
||||||
|
|
||||||
|
log.Debugf("Sending a blockLocator to %s between pruning point and headers selected tip", flow.peer)
|
||||||
|
blockLocator, err := flow.Domain().Consensus().CreateFullHeadersSelectedChainBlockLocator()
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
highestHash, highestHashFound, err := flow.fetchHighestHash(targetHash, blockLocator)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if !highestHashFound {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
highestHashIndex, err := flow.findHighestHashIndex(highestHash, blockLocator)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if highestHashIndex == 0 ||
|
||||||
|
// If the block locator contains only two adjacent chain blocks, the
|
||||||
|
// syncer will always find the same highest chain block, so to avoid
|
||||||
|
// an endless loop, we explicitly stop the loop in such situation.
|
||||||
|
(len(blockLocator) == 2 && highestHashIndex == 1) {
|
||||||
|
|
||||||
|
return highestHash, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
locatorHashAboveHighestHash := highestHash
|
||||||
|
if highestHashIndex > 0 {
|
||||||
|
locatorHashAboveHighestHash = blockLocator[highestHashIndex-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
blockLocator, err = flow.nextBlockLocator(highestHash, locatorHashAboveHighestHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) nextBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) {
|
||||||
|
log.Debugf("Sending a blockLocator to %s between %s and %s", flow.peer, lowHash, highHash)
|
||||||
|
blockLocator, err := flow.Domain().Consensus().CreateHeadersSelectedChainBlockLocator(lowHash, highHash)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(model.ErrBlockNotInSelectedParentChain, err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Debugf("Headers selected parent chain moved since findHighestSharedBlockHash - " +
|
||||||
|
"restarting with full block locator")
|
||||||
|
blockLocator, err = flow.Domain().Consensus().CreateFullHeadersSelectedChainBlockLocator()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockLocator, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) findHighestHashIndex(
|
||||||
|
highestHash *externalapi.DomainHash, blockLocator externalapi.BlockLocator) (int, error) {
|
||||||
|
|
||||||
|
highestHashIndex := 0
|
||||||
|
highestHashIndexFound := false
|
||||||
|
for i, blockLocatorHash := range blockLocator {
|
||||||
|
if highestHash.Equal(blockLocatorHash) {
|
||||||
|
highestHashIndex = i
|
||||||
|
highestHashIndexFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !highestHashIndexFound {
|
||||||
|
return 0, protocolerrors.Errorf(true, "highest hash %s "+
|
||||||
|
"returned from peer %s is not in the original blockLocator", highestHash, flow.peer)
|
||||||
|
}
|
||||||
|
log.Debugf("The index of the highest hash in the original "+
|
||||||
|
"blockLocator sent to %s is %d", flow.peer, highestHashIndex)
|
||||||
|
|
||||||
|
return highestHashIndex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchHighestHash attempts to fetch the highest hash the peer knows amongst the given
|
||||||
|
// blockLocator. This method may fail because the peer and us have conflicting pruning
|
||||||
|
// points. In that case we return (nil, false, nil) so that we may stop IBD gracefully.
|
||||||
|
func (flow *handleRelayInvsFlow) fetchHighestHash(
|
||||||
|
targetHash *externalapi.DomainHash, blockLocator externalapi.BlockLocator) (*externalapi.DomainHash, bool, error) {
|
||||||
|
|
||||||
|
ibdBlockLocatorMessage := appmessage.NewMsgIBDBlockLocator(targetHash, blockLocator)
|
||||||
|
err := flow.outgoingRoute.Enqueue(ibdBlockLocatorMessage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
switch message := message.(type) {
|
||||||
|
case *appmessage.MsgIBDBlockLocatorHighestHash:
|
||||||
|
highestHash := message.HighestHash
|
||||||
|
log.Debugf("The highest hash the peer %s knows is %s", flow.peer, highestHash)
|
||||||
|
|
||||||
|
return highestHash, true, nil
|
||||||
|
case *appmessage.MsgIBDBlockLocatorHighestHashNotFound:
|
||||||
|
log.Debugf("Peer %s does not know any block within our blockLocator. "+
|
||||||
|
"This should only happen if there's a DAG split deeper than the pruning point.", flow.peer)
|
||||||
|
return nil, false, nil
|
||||||
|
default:
|
||||||
|
return nil, false, protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdIBDBlockLocatorHighestHash, message.Command())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash,
|
||||||
|
highHash *externalapi.DomainHash) error {
|
||||||
|
|
||||||
|
err := flow.sendRequestHeaders(highestSharedBlockHash, highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep a short queue of blockHeadersMessages so that there's
|
||||||
|
// never a moment when the node is not validating and inserting
|
||||||
|
// headers
|
||||||
|
blockHeadersMessageChan := make(chan *appmessage.BlockHeadersMessage, 2)
|
||||||
|
errChan := make(chan error)
|
||||||
|
spawn("handleRelayInvsFlow-downloadHeaders", func() {
|
||||||
|
for {
|
||||||
|
blockHeadersMessage, doneIBD, err := flow.receiveHeaders()
|
||||||
|
if err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if doneIBD {
|
||||||
|
close(blockHeadersMessageChan)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
blockHeadersMessageChan <- blockHeadersMessage
|
||||||
|
|
||||||
|
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestNextHeaders())
|
||||||
|
if err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case blockHeadersMessage, ok := <-blockHeadersMessageChan:
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, header := range blockHeadersMessage.BlockHeaders {
|
||||||
|
err = flow.processHeader(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case err := <-errChan:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) sendRequestHeaders(highestSharedBlockHash *externalapi.DomainHash,
|
||||||
|
peerSelectedTipHash *externalapi.DomainHash) error {
|
||||||
|
|
||||||
|
msgGetBlockInvs := appmessage.NewMsgRequstHeaders(highestSharedBlockHash, peerSelectedTipHash)
|
||||||
|
return flow.outgoingRoute.Enqueue(msgGetBlockInvs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) receiveHeaders() (msgIBDBlock *appmessage.BlockHeadersMessage, doneIBD bool, err error) {
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
switch message := message.(type) {
|
||||||
|
case *appmessage.BlockHeadersMessage:
|
||||||
|
return message, false, nil
|
||||||
|
case *appmessage.MsgDoneHeaders:
|
||||||
|
return nil, true, nil
|
||||||
|
default:
|
||||||
|
return nil, false,
|
||||||
|
protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s or %s, got: %s", appmessage.CmdHeader, appmessage.CmdDoneHeaders, message.Command())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlockHeader) error {
|
||||||
|
header := appmessage.BlockHeaderToDomainBlockHeader(msgBlockHeader)
|
||||||
|
block := &externalapi.DomainBlock{
|
||||||
|
Header: header,
|
||||||
|
Transactions: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
blockInfo, err := flow.Domain().Consensus().GetBlockInfo(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if blockInfo.Exists {
|
||||||
|
log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
|
return errors.Wrapf(err, "failed to process header %s during IBD", blockHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
|
log.Debugf("Skipping block header %s as it is a duplicate", blockHash)
|
||||||
|
} else {
|
||||||
|
log.Infof("Rejected block header %s from %s during IBD: %s", blockHash, flow.peer, err)
|
||||||
|
return protocolerrors.Wrapf(true, err, "got invalid block header %s during IBD", blockHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet() (bool, error) {
|
||||||
|
log.Debugf("Checking if a new pruning point is available")
|
||||||
|
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointHashMessage())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
msgPruningPointHash, ok := message.(*appmessage.MsgPruningPointHashMessage)
|
||||||
|
if !ok {
|
||||||
|
return false, protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdPruningPointHash, message.Command())
|
||||||
|
}
|
||||||
|
|
||||||
|
blockInfo, err := flow.Domain().Consensus().GetBlockInfo(msgPruningPointHash.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !blockInfo.Exists {
|
||||||
|
return false, errors.Errorf("The pruning point header is missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockInfo.BlockStatus != externalapi.StatusHeaderOnly {
|
||||||
|
log.Debugf("Already has the block data of the new suggested pruning point %s", msgPruningPointHash.Hash)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Checking if the suggested pruning point %s is compatible to the node DAG", msgPruningPointHash.Hash)
|
||||||
|
isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgPruningPointHash.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isValid {
|
||||||
|
log.Infof("The suggested pruning point %s is incompatible to this node DAG, so stopping IBD with this"+
|
||||||
|
" peer", msgPruningPointHash.Hash)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetching the pruning point UTXO set")
|
||||||
|
succeed, err := flow.fetchMissingUTXOSet(msgPruningPointHash.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !succeed {
|
||||||
|
log.Infof("Couldn't successfully fetch the pruning point UTXO set. Stopping IBD.")
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetched the new pruning point UTXO set")
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(pruningPointHash *externalapi.DomainHash) (succeed bool, err error) {
|
||||||
|
defer func() {
|
||||||
|
err := flow.Domain().Consensus().ClearImportedPruningPointData()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to clear imported pruning point data: %s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointUTXOSetAndBlock(pruningPointHash))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := flow.receivePruningPointBlock()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receivedAll, err := flow.receiveAndInsertPruningPointUTXOSet(pruningPointHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !receivedAll {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.Domain().Consensus().ValidateAndInsertImportedPruningPoint(block)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Find a better way to deal with finality conflicts.
|
||||||
|
if errors.Is(err, ruleerrors.ErrSuggestedPruningViolatesFinality) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with pruning point UTXO set")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) receivePruningPointBlock() (*externalapi.DomainBlock, error) {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "receivePruningPointBlock")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ibdBlockMessage, ok := message.(*appmessage.MsgIBDBlock)
|
||||||
|
if !ok {
|
||||||
|
return nil, protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdIBDBlock, message.Command())
|
||||||
|
}
|
||||||
|
block := appmessage.MsgBlockToDomainBlock(ibdBlockMessage.MsgBlock)
|
||||||
|
|
||||||
|
log.Debugf("Received pruning point block %s", consensushashing.BlockHash(block))
|
||||||
|
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) receiveAndInsertPruningPointUTXOSet(
|
||||||
|
pruningPointHash *externalapi.DomainHash) (bool, error) {
|
||||||
|
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "receiveAndInsertPruningPointUTXOSet")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
|
receivedChunkCount := 0
|
||||||
|
receivedUTXOCount := 0
|
||||||
|
for {
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch message := message.(type) {
|
||||||
|
case *appmessage.MsgPruningPointUTXOSetChunk:
|
||||||
|
receivedUTXOCount += len(message.OutpointAndUTXOEntryPairs)
|
||||||
|
domainOutpointAndUTXOEntryPairs :=
|
||||||
|
appmessage.OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs(message.OutpointAndUTXOEntryPairs)
|
||||||
|
|
||||||
|
err := flow.Domain().Consensus().AppendImportedPruningPointUTXOs(domainOutpointAndUTXOEntryPairs)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receivedChunkCount++
|
||||||
|
if receivedChunkCount%ibdBatchSize == 0 {
|
||||||
|
log.Debugf("Received %d UTXO set chunks so far, totaling in %d UTXOs",
|
||||||
|
receivedChunkCount, receivedUTXOCount)
|
||||||
|
|
||||||
|
requestNextPruningPointUTXOSetChunkMessage := appmessage.NewMsgRequestNextPruningPointUTXOSetChunk()
|
||||||
|
err := flow.outgoingRoute.Enqueue(requestNextPruningPointUTXOSetChunkMessage)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case *appmessage.MsgDonePruningPointUTXOSetChunks:
|
||||||
|
log.Infof("Finished receiving the UTXO set. Total UTXOs: %d", receivedUTXOCount)
|
||||||
|
return true, nil
|
||||||
|
|
||||||
|
case *appmessage.MsgUnexpectedPruningPoint:
|
||||||
|
log.Infof("Could not receive the next UTXO chunk because the pruning point %s "+
|
||||||
|
"is no longer the pruning point of peer %s", pruningPointHash, flow.peer)
|
||||||
|
return false, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false, protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s or %s or %s, got: %s", appmessage.CmdPruningPointUTXOSetChunk,
|
||||||
|
appmessage.CmdDonePruningPointUTXOSetChunks, appmessage.CmdUnexpectedPruningPoint, message.Command(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.DomainHash) error {
|
||||||
|
hashes, err := flow.Domain().Consensus().GetMissingBlockBodyHashes(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(hashes) == 0 {
|
||||||
|
// Blocks can be inserted inside the DAG during IBD if those were requested before IBD started.
|
||||||
|
// In rare cases, all the IBD blocks might be already inserted by the time we reach this point.
|
||||||
|
// In these cases - GetMissingBlockBodyHashes would return an empty array.
|
||||||
|
log.Debugf("No missing block body hashes found.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for offset := 0; offset < len(hashes); offset += ibdBatchSize {
|
||||||
|
var hashesToRequest []*externalapi.DomainHash
|
||||||
|
if offset+ibdBatchSize < len(hashes) {
|
||||||
|
hashesToRequest = hashes[offset : offset+ibdBatchSize]
|
||||||
|
} else {
|
||||||
|
hashesToRequest = hashes[offset:]
|
||||||
|
}
|
||||||
|
|
||||||
|
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDBlocks(hashesToRequest))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, expectedHash := range hashesToRequest {
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msgIBDBlock, ok := message.(*appmessage.MsgIBDBlock)
|
||||||
|
if !ok {
|
||||||
|
return protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdIBDBlock, message.Command())
|
||||||
|
}
|
||||||
|
|
||||||
|
block := appmessage.MsgBlockToDomainBlock(msgIBDBlock.MsgBlock)
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
if !expectedHash.Equal(blockHash) {
|
||||||
|
return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
|
log.Debugf("Skipping IBD Block %s as it has already been added to the DAG", blockHash)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash)
|
||||||
|
}
|
||||||
|
err = flow.OnNewBlock(block, blockInsertionResult)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dequeueIncomingMessageAndSkipInvs is a convenience method to be used during
|
||||||
|
// IBD. Inv messages are expected to arrive at any given moment, but should be
|
||||||
|
// ignored while we're in IBD
|
||||||
|
func (flow *handleRelayInvsFlow) dequeueIncomingMessageAndSkipInvs(timeout time.Duration) (appmessage.Message, error) {
|
||||||
|
for {
|
||||||
|
message, err := flow.incomingRoute.DequeueWithTimeout(timeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, ok := message.(*appmessage.MsgInvRelayBlock); !ok {
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,5 +5,5 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/util/panics"
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logger.RegisterSubSystem("PROT")
|
var log, _ = logger.Get(logger.SubsystemTags.PROT)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log)
|
var spawn = panics.GoroutineWrapperFunc(log)
|
@ -4,14 +4,12 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
"github.com/kaspanet/kaspad/domain"
|
"github.com/kaspanet/kaspad/domain"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SendVirtualSelectedParentInvContext is the interface for the context needed for the SendVirtualSelectedParentInv flow.
|
// SendVirtualSelectedParentInvContext is the interface for the context needed for the SendVirtualSelectedParentInv flow.
|
||||||
type SendVirtualSelectedParentInvContext interface {
|
type SendVirtualSelectedParentInvContext interface {
|
||||||
Domain() domain.Domain
|
Domain() domain.Domain
|
||||||
Config() *config.Config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendVirtualSelectedParentInv sends a peer the selected parent hash of the virtual
|
// SendVirtualSelectedParentInv sends a peer the selected parent hash of the virtual
|
||||||
@ -23,11 +21,6 @@ func SendVirtualSelectedParentInv(context SendVirtualSelectedParentInvContext,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if virtualSelectedParent.Equal(context.Config().NetParams().GenesisHash) {
|
|
||||||
log.Debugf("Skipping sending the virtual selected parent hash to peer %s because it's the genesis", peer)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Sending virtual selected parent hash %s to peer %s", virtualSelectedParent, peer)
|
log.Debugf("Sending virtual selected parent hash %s to peer %s", virtualSelectedParent, peer)
|
||||||
|
|
||||||
virtualSelectedParentInv := appmessage.NewMsgInvBlock(virtualSelectedParent)
|
virtualSelectedParentInv := appmessage.NewMsgInvBlock(virtualSelectedParent)
|
@ -1,4 +1,4 @@
|
|||||||
package flowcontext
|
package blockrelay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
@ -13,15 +13,13 @@ type SharedRequestedBlocks struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes a block from the set.
|
func (s *SharedRequestedBlocks) remove(hash *externalapi.DomainHash) {
|
||||||
func (s *SharedRequestedBlocks) Remove(hash *externalapi.DomainHash) {
|
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
delete(s.blocks, *hash)
|
delete(s.blocks, *hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveSet removes a set of blocks from the set.
|
func (s *SharedRequestedBlocks) removeSet(blockHashes map[externalapi.DomainHash]struct{}) {
|
||||||
func (s *SharedRequestedBlocks) RemoveSet(blockHashes map[externalapi.DomainHash]struct{}) {
|
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
for hash := range blockHashes {
|
for hash := range blockHashes {
|
||||||
@ -29,8 +27,7 @@ func (s *SharedRequestedBlocks) RemoveSet(blockHashes map[externalapi.DomainHash
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddIfNotExists adds a block to the set if it doesn't exist yet.
|
func (s *SharedRequestedBlocks) addIfNotExists(hash *externalapi.DomainHash) (exists bool) {
|
||||||
func (s *SharedRequestedBlocks) AddIfNotExists(hash *externalapi.DomainHash) (exists bool) {
|
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
_, ok := s.blocks[*hash]
|
_, ok := s.blocks[*hash]
|
@ -28,7 +28,7 @@ type HandleHandshakeContext interface {
|
|||||||
HandleError(err error, flowName string, isStopping *uint32, errChan chan<- error)
|
HandleError(err error, flowName string, isStopping *uint32, errChan chan<- error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleHandshake sets up the new_handshake protocol - It sends a version message and waits for an incoming
|
// HandleHandshake sets up the handshake protocol - It sends a version message and waits for an incoming
|
||||||
// version message, as well as a verack for the sent version
|
// version message, as well as a verack for the sent version
|
||||||
func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.NetConnection,
|
func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.NetConnection,
|
||||||
receiveVersionRoute *routerpkg.Route, sendVersionRoute *routerpkg.Route, outgoingRoute *routerpkg.Route,
|
receiveVersionRoute *routerpkg.Route, sendVersionRoute *routerpkg.Route, outgoingRoute *routerpkg.Route,
|
||||||
@ -89,16 +89,13 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
|
|||||||
}
|
}
|
||||||
|
|
||||||
if peerAddress != nil {
|
if peerAddress != nil {
|
||||||
err := context.AddressManager().AddAddresses(peerAddress)
|
context.AddressManager().AddAddresses(peerAddress)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return peer, nil
|
return peer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handshake is different from other flows, since in it should forward router.ErrRouteClosed to errChan
|
// Handshake is different from other flows, since in it should forward router.ErrRouteClosed to errChan
|
||||||
// Therefore we implement a separate handleError for new_handshake
|
// Therefore we implement a separate handleError for handshake
|
||||||
func handleError(err error, flowName string, isStopping *uint32, errChan chan error) {
|
func handleError(err error, flowName string, isStopping *uint32, errChan chan error) {
|
||||||
if errors.Is(err, routerpkg.ErrRouteClosed) {
|
if errors.Is(err, routerpkg.ErrRouteClosed) {
|
||||||
if atomic.AddUint32(isStopping, 1) == 1 {
|
if atomic.AddUint32(isStopping, 1) == 1 {
|
||||||
@ -107,7 +104,7 @@ func handleError(err error, flowName string, isStopping *uint32, errChan chan er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if protocolErr := (protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
if protocolErr := &(protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
||||||
log.Errorf("Handshake protocol error from %s: %s", flowName, err)
|
log.Errorf("Handshake protocol error from %s: %s", flowName, err)
|
||||||
if atomic.AddUint32(isStopping, 1) == 1 {
|
if atomic.AddUint32(isStopping, 1) == 1 {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
|
@ -5,5 +5,5 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/util/panics"
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logger.RegisterSubSystem("PROT")
|
var log, _ = logger.Get(logger.SubsystemTags.PROT)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log)
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user