mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-03-22 16:13:45 +00:00
Compare commits
112 Commits
ghostdagRe
...
v1sectimeo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5993f26b04 | ||
|
|
7bed86dc1b | ||
|
|
9b81f5145e | ||
|
|
cd8341ef57 | ||
|
|
ad8bdbed21 | ||
|
|
7cdceb6df0 | ||
|
|
cc5248106e | ||
|
|
e3463b7268 | ||
|
|
a2173ef80a | ||
|
|
aeb4500b61 | ||
|
|
0a1daae319 | ||
|
|
131cd3357e | ||
|
|
ff72568d6b | ||
|
|
2dddb650b9 | ||
|
|
99aaacd649 | ||
|
|
77a344cc29 | ||
|
|
3dbc42b4f7 | ||
|
|
1b9be28613 | ||
|
|
5dbb1da84b | ||
|
|
afaac28da1 | ||
|
|
0053ee788d | ||
|
|
af7e7de247 | ||
|
|
02a08902a7 | ||
|
|
d9bc94a2a8 | ||
|
|
837dac68b5 | ||
|
|
ba5880fab1 | ||
|
|
7b5720a155 | ||
|
|
65b5a080e4 | ||
|
|
ce17348175 | ||
|
|
d922ee1be2 | ||
|
|
4132891ac9 | ||
|
|
2094f4facf | ||
|
|
2de68f43f0 | ||
|
|
d748089a14 | ||
|
|
7d1071a9b1 | ||
|
|
f26a7fdedf | ||
|
|
d207888b67 | ||
|
|
38e2ee1b43 | ||
|
|
aba44e7bfb | ||
|
|
c731d74bc0 | ||
|
|
60e7a8ebed | ||
|
|
369a3bac09 | ||
|
|
8022e4cbea | ||
|
|
28ac77b202 | ||
|
|
28af7eb596 | ||
|
|
a4d241c30a | ||
|
|
487fab0e2b | ||
|
|
2f272cd517 | ||
|
|
e3a6d9e49a | ||
|
|
069ee26e84 | ||
|
|
61aa15fd61 | ||
|
|
f7cce5cb39 | ||
|
|
2f7a1395e7 | ||
|
|
8b1ac86532 | ||
|
|
ab721f3ad6 | ||
|
|
798c5fab7d | ||
|
|
c13a4d90ed | ||
|
|
4ba8b14675 | ||
|
|
319cbce768 | ||
|
|
bdd42903b4 | ||
|
|
9bedf84740 | ||
|
|
f317f51cdd | ||
|
|
4207c82f5a | ||
|
|
70399dae2a | ||
|
|
2ae1b7853f | ||
|
|
d53d040bee | ||
|
|
79c74c482b | ||
|
|
3b0394eefe | ||
|
|
43e6467ff1 | ||
|
|
363494ef7a | ||
|
|
d1df97c4c5 | ||
|
|
4f52a6de51 | ||
|
|
4f4a8934e7 | ||
|
|
16ba2bd312 | ||
|
|
6613faee2d | ||
|
|
edc459ae1b | ||
|
|
d7f2cf81c0 | ||
|
|
4658f9d05c | ||
|
|
010df3b0d3 | ||
|
|
346598e67f | ||
|
|
268906a7ce | ||
|
|
befc60b185 | ||
|
|
dd3e04e671 | ||
|
|
9c743db4d6 | ||
|
|
eb3dba5c88 | ||
|
|
e46e2580b1 | ||
|
|
414f58fb90 | ||
|
|
9df80957b1 | ||
|
|
268c9fa83c | ||
|
|
2e3592e351 | ||
|
|
19718ac102 | ||
|
|
28a8e96e65 | ||
|
|
4df283934a | ||
|
|
ab89efe3dc | ||
|
|
fa16c30cf3 | ||
|
|
c28366eb50 | ||
|
|
dc0bf56bf3 | ||
|
|
91de1807ad | ||
|
|
830684167c | ||
|
|
1f56a68a28 | ||
|
|
13a6b4cc51 | ||
|
|
dfd8b3423d | ||
|
|
28bfc0fb9c | ||
|
|
83beae4463 | ||
|
|
a6ebe83198 | ||
|
|
acdc59b565 | ||
|
|
15811b0bcb | ||
|
|
a8a7e3dd9b | ||
|
|
3f193e9219 | ||
|
|
dfa24d8353 | ||
|
|
3c3ad1425d | ||
|
|
9bb8123391 |
4
.github/workflows/SetPageFileSize.ps1
vendored
4
.github/workflows/SetPageFileSize.ps1
vendored
@@ -11,8 +11,8 @@
|
|||||||
#>
|
#>
|
||||||
|
|
||||||
param(
|
param(
|
||||||
[System.UInt64] $MinimumSize = 8gb ,
|
[System.UInt64] $MinimumSize = 16gb ,
|
||||||
[System.UInt64] $MaximumSize = 8gb ,
|
[System.UInt64] $MaximumSize = 16gb ,
|
||||||
[System.String] $DiskRoot = "D:"
|
[System.String] $DiskRoot = "D:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: Build and Upload assets
|
name: Build and upload assets
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [ published ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -10,34 +10,33 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||||
name: Building For ${{ matrix.os }}
|
name: Building, ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Fix windows CRLF
|
- name: Fix CRLF on Windows
|
||||||
|
if: runner.os == 'Windows'
|
||||||
run: git config --global core.autocrlf false
|
run: git config --global core.autocrlf false
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
# We need to increase the page size because the tests run out of memory on github CI windows.
|
# Increase the pagefile size on Windows to aviod running out of memory
|
||||||
# Use the powershell script from this github action: https://github.com/al-cheb/configure-pagefile-action/blob/master/scripts/SetPageFileSize.ps1
|
- name: Increase pagefile size on Windows
|
||||||
# MIT License (MIT) Copyright (c) 2020 Maxim Lobanov and contributors
|
|
||||||
- name: Increase page size on windows
|
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: powershell
|
run: powershell -command .github\workflows\SetPageFileSize.ps1
|
||||||
run: powershell -command .\.github\workflows\SetPageFileSize.ps1
|
|
||||||
|
|
||||||
|
|
||||||
- name: Set up Go 1.x
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.16
|
go-version: 1.16
|
||||||
|
|
||||||
- name: Build on linux
|
- name: Build on Linux
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
# `-extldflags=-static` - means static link everything, `-tags netgo,osusergo` means use pure go replacements for "os/user" and "net"
|
# `-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
|
# `-s -w` strips the binary to produce smaller size binaries
|
||||||
run: |
|
run: |
|
||||||
go build -v -ldflags="-s -w -extldflags=-static" -tags netgo,osusergo -o ./bin/ ./...
|
go build -v -ldflags="-s -w -extldflags=-static" -tags netgo,osusergo -o ./bin/ . ./cmd/...
|
||||||
archive="bin/kaspad-${{ github.event.release.tag_name }}-linux.zip"
|
archive="bin/kaspad-${{ github.event.release.tag_name }}-linux.zip"
|
||||||
asset_name="kaspad-${{ github.event.release.tag_name }}-linux.zip"
|
asset_name="kaspad-${{ github.event.release.tag_name }}-linux.zip"
|
||||||
zip -r "${archive}" ./bin/*
|
zip -r "${archive}" ./bin/*
|
||||||
@@ -48,7 +47,7 @@ jobs:
|
|||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
go build -v -ldflags="-s -w" -o bin/ ./...
|
go build -v -ldflags="-s -w" -o bin/ . ./cmd/...
|
||||||
archive="bin/kaspad-${{ github.event.release.tag_name }}-win64.zip"
|
archive="bin/kaspad-${{ github.event.release.tag_name }}-win64.zip"
|
||||||
asset_name="kaspad-${{ github.event.release.tag_name }}-win64.zip"
|
asset_name="kaspad-${{ github.event.release.tag_name }}-win64.zip"
|
||||||
powershell "Compress-Archive bin/* \"${archive}\""
|
powershell "Compress-Archive bin/* \"${archive}\""
|
||||||
@@ -58,7 +57,7 @@ jobs:
|
|||||||
- name: Build on MacOS
|
- name: Build on MacOS
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
go build -v -ldflags="-s -w" -o ./bin/ ./...
|
go build -v -ldflags="-s -w" -o ./bin/ . ./cmd/...
|
||||||
archive="bin/kaspad-${{ github.event.release.tag_name }}-osx.zip"
|
archive="bin/kaspad-${{ github.event.release.tag_name }}-osx.zip"
|
||||||
asset_name="kaspad-${{ github.event.release.tag_name }}-osx.zip"
|
asset_name="kaspad-${{ github.event.release.tag_name }}-osx.zip"
|
||||||
zip -r "${archive}" ./bin/*
|
zip -r "${archive}" ./bin/*
|
||||||
@@ -66,7 +65,7 @@ jobs:
|
|||||||
echo "asset_name=${asset_name}" >> $GITHUB_ENV
|
echo "asset_name=${asset_name}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
- name: Upload Release Asset
|
- name: Upload release asset
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Go-Race
|
name: Race
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
race_test:
|
race_test:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -19,10 +19,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go 1.x
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.15
|
go-version: 1.16
|
||||||
|
|
||||||
- name: Set scheduled branch name
|
- name: Set scheduled branch name
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -1,38 +1,36 @@
|
|||||||
name: Go
|
name: Tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
pull_request:
|
pull_request:
|
||||||
# edtited - "title, body, or the base branch of the PR is modified"
|
# edtited - because base branch can be modified
|
||||||
# synchronize - "commit(s) pushed to the pull request"
|
# synchronize - update commits on PR
|
||||||
types: [opened, synchronize, edited, reopened]
|
types: [opened, synchronize, edited]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-16.04, macos-10.15 ]
|
os: [ ubuntu-latest, macos-latest ]
|
||||||
name: Testing on on ${{ matrix.os }}
|
name: Tests, ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Fix windows CRLF
|
- name: Fix CRLF on Windows
|
||||||
|
if: runner.os == 'Windows'
|
||||||
run: git config --global core.autocrlf false
|
run: git config --global core.autocrlf false
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
# We need to increase the page size because the tests run out of memory on github CI windows.
|
# Increase the pagefile size on Windows to aviod running out of memory
|
||||||
# Use the powershell script from this github action: https://github.com/al-cheb/configure-pagefile-action/blob/master/scripts/SetPageFileSize.ps1
|
- name: Increase pagefile size on Windows
|
||||||
# MIT License (MIT) Copyright (c) 2020 Maxim Lobanov and contributors
|
|
||||||
- name: Increase page size on windows
|
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: powershell
|
run: powershell -command .github\workflows\SetPageFileSize.ps1
|
||||||
run: powershell -command .\.github\workflows\SetPageFileSize.ps1
|
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
- name: Set up Go 1.x
|
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.16
|
go-version: 1.16
|
||||||
@@ -51,14 +49,41 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: ./build_and_test.sh -v
|
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@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
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:
|
coverage:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
name: Produce code coverage
|
name: Produce code coverage
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Go 1.x
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.16
|
go-version: 1.16
|
||||||
@@ -70,4 +95,4 @@ jobs:
|
|||||||
run: go test -v -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./...
|
run: go test -v -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./...
|
||||||
|
|
||||||
- name: Upload coverage file
|
- name: Upload coverage file
|
||||||
run: bash <(curl -s https://codecov.io/bash)
|
run: bash <(curl -s https://codecov.io/bash)
|
||||||
@@ -63,6 +63,8 @@ Join our discord server using the following link: https://discord.gg/YNYnNN5Pf2
|
|||||||
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
|
||||||
|
|||||||
27
app/app.go
27
app/app.go
@@ -85,12 +85,6 @@ func (app *kaspadApp) main(startedChan chan<- struct{}) error {
|
|||||||
profiling.Start(app.cfg.Profile, log)
|
profiling.Start(app.cfg.Profile, 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) {
|
||||||
return nil
|
return nil
|
||||||
@@ -107,7 +101,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.Error(err)
|
log.Errorf("Loading database failed: %+v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,12 +157,6 @@ 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, "data")
|
return filepath.Join(cfg.AppDir, "data")
|
||||||
@@ -181,6 +169,17 @@ 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)
|
||||||
return ldb.NewLevelDB(dbPath, leveldbCacheSizeMiB)
|
db, err := ldb.NewLevelDB(dbPath, leveldbCacheSizeMiB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package appmessage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"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/hashes"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
@@ -28,13 +31,17 @@ 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(),
|
||||||
ParentHashes: domainBlockHeader.ParentHashes(),
|
Parents: domainBlockHeader.Parents(),
|
||||||
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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,13 +62,17 @@ 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.ParentHashes,
|
blockHeader.Parents,
|
||||||
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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +111,7 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +160,7 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,14 +176,10 @@ 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 {
|
||||||
transactionID, err := transactionid.FromString(input.PreviousOutpoint.TransactionID)
|
previousOutpoint, err := RPCOutpointToDomainOutpoint(input.PreviousOutpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
||||||
@@ -179,6 +188,7 @@ 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))
|
||||||
@@ -213,6 +223,36 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa
|
|||||||
}, 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))
|
||||||
@@ -227,6 +267,7 @@ 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))
|
||||||
@@ -257,22 +298,27 @@ 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] = &externalapi.OutpointAndUTXOEntryPair{
|
domainOutpointAndUTXOEntryPairs[i] = outpointAndUTXOEntryPairToDomainOutpointAndUTXOEntryPair(outpointAndUTXOEntryPair)
|
||||||
Outpoint: &externalapi.DomainOutpoint{
|
|
||||||
TransactionID: outpointAndUTXOEntryPair.Outpoint.TxID,
|
|
||||||
Index: outpointAndUTXOEntryPair.Outpoint.Index,
|
|
||||||
},
|
|
||||||
UTXOEntry: utxo.NewUTXOEntry(
|
|
||||||
outpointAndUTXOEntryPair.UTXOEntry.Amount,
|
|
||||||
outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey,
|
|
||||||
outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase,
|
|
||||||
outpointAndUTXOEntryPair.UTXOEntry.BlockDAAScore,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return domainOutpointAndUTXOEntryPairs
|
return domainOutpointAndUTXOEntryPairs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func outpointAndUTXOEntryPairToDomainOutpointAndUTXOEntryPair(
|
||||||
|
outpointAndUTXOEntryPair *OutpointAndUTXOEntryPair) *externalapi.OutpointAndUTXOEntryPair {
|
||||||
|
return &externalapi.OutpointAndUTXOEntryPair{
|
||||||
|
Outpoint: &externalapi.DomainOutpoint{
|
||||||
|
TransactionID: outpointAndUTXOEntryPair.Outpoint.TxID,
|
||||||
|
Index: outpointAndUTXOEntryPair.Outpoint.Index,
|
||||||
|
},
|
||||||
|
UTXOEntry: utxo.NewUTXOEntry(
|
||||||
|
outpointAndUTXOEntryPair.UTXOEntry.Amount,
|
||||||
|
outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey,
|
||||||
|
outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase,
|
||||||
|
outpointAndUTXOEntryPair.UTXOEntry.BlockDAAScore,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs converts
|
// DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs converts
|
||||||
// domain OutpointAndUTXOEntryPairs to OutpointAndUTXOEntryPairs
|
// domain OutpointAndUTXOEntryPairs to OutpointAndUTXOEntryPairs
|
||||||
func DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(
|
func DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(
|
||||||
@@ -298,15 +344,25 @@ func DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(
|
|||||||
|
|
||||||
// DomainBlockToRPCBlock converts DomainBlocks to RPCBlocks
|
// DomainBlockToRPCBlock converts DomainBlocks to RPCBlocks
|
||||||
func DomainBlockToRPCBlock(block *externalapi.DomainBlock) *RPCBlock {
|
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{
|
header := &RPCBlockHeader{
|
||||||
Version: uint32(block.Header.Version()),
|
Version: uint32(block.Header.Version()),
|
||||||
ParentHashes: hashes.ToStrings(block.Header.ParentHashes()),
|
Parents: parents,
|
||||||
HashMerkleRoot: block.Header.HashMerkleRoot().String(),
|
HashMerkleRoot: block.Header.HashMerkleRoot().String(),
|
||||||
AcceptedIDMerkleRoot: block.Header.AcceptedIDMerkleRoot().String(),
|
AcceptedIDMerkleRoot: block.Header.AcceptedIDMerkleRoot().String(),
|
||||||
UTXOCommitment: block.Header.UTXOCommitment().String(),
|
UTXOCommitment: block.Header.UTXOCommitment().String(),
|
||||||
Timestamp: block.Header.TimeInMilliseconds(),
|
Timestamp: block.Header.TimeInMilliseconds(),
|
||||||
Bits: block.Header.Bits(),
|
Bits: block.Header.Bits(),
|
||||||
Nonce: block.Header.Nonce(),
|
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))
|
transactions := make([]*RPCTransaction, len(block.Transactions))
|
||||||
for i, transaction := range block.Transactions {
|
for i, transaction := range block.Transactions {
|
||||||
@@ -320,13 +376,16 @@ func DomainBlockToRPCBlock(block *externalapi.DomainBlock) *RPCBlock {
|
|||||||
|
|
||||||
// RPCBlockToDomainBlock converts `block` into a DomainBlock
|
// RPCBlockToDomainBlock converts `block` into a DomainBlock
|
||||||
func RPCBlockToDomainBlock(block *RPCBlock) (*externalapi.DomainBlock, error) {
|
func RPCBlockToDomainBlock(block *RPCBlock) (*externalapi.DomainBlock, error) {
|
||||||
parentHashes := make([]*externalapi.DomainHash, len(block.Header.ParentHashes))
|
parents := make([]externalapi.BlockLevelParents, len(block.Header.Parents))
|
||||||
for i, parentHash := range block.Header.ParentHashes {
|
for i, blockLevelParents := range block.Header.Parents {
|
||||||
domainParentHashes, err := externalapi.NewDomainHashFromString(parentHash)
|
parents[i] = make(externalapi.BlockLevelParents, len(blockLevelParents.ParentHashes))
|
||||||
if err != nil {
|
for j, parentHash := range blockLevelParents.ParentHashes {
|
||||||
return nil, err
|
var err error
|
||||||
|
parents[i][j], err = externalapi.NewDomainHashFromString(parentHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
parentHashes[i] = domainParentHashes
|
|
||||||
}
|
}
|
||||||
hashMerkleRoot, err := externalapi.NewDomainHashFromString(block.Header.HashMerkleRoot)
|
hashMerkleRoot, err := externalapi.NewDomainHashFromString(block.Header.HashMerkleRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -340,15 +399,27 @@ func RPCBlockToDomainBlock(block *RPCBlock) (*externalapi.DomainBlock, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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(
|
header := blockheader.NewImmutableBlockHeader(
|
||||||
uint16(block.Header.Version),
|
uint16(block.Header.Version),
|
||||||
parentHashes,
|
parents,
|
||||||
hashMerkleRoot,
|
hashMerkleRoot,
|
||||||
acceptedIDMerkleRoot,
|
acceptedIDMerkleRoot,
|
||||||
utxoCommitment,
|
utxoCommitment,
|
||||||
block.Header.Timestamp,
|
block.Header.Timestamp,
|
||||||
block.Header.Bits,
|
block.Header.Bits,
|
||||||
block.Header.Nonce)
|
block.Header.Nonce,
|
||||||
|
block.Header.DAAScore,
|
||||||
|
block.Header.BlueScore,
|
||||||
|
blueWork,
|
||||||
|
pruningPoint)
|
||||||
transactions := make([]*externalapi.DomainTransaction, len(block.Transactions))
|
transactions := make([]*externalapi.DomainTransaction, len(block.Transactions))
|
||||||
for i, transaction := range block.Transactions {
|
for i, transaction := range block.Transactions {
|
||||||
domainTransaction, err := RPCTransactionToDomainTransaction(transaction)
|
domainTransaction, err := RPCTransactionToDomainTransaction(transaction)
|
||||||
@@ -362,3 +433,118 @@ func RPCBlockToDomainBlock(block *RPCBlock) (*externalapi.DomainBlock, error) {
|
|||||||
Transactions: transactions,
|
Transactions: transactions,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockWithTrustedDataToDomainBlockWithTrustedData converts *MsgBlockWithTrustedData to *externalapi.BlockWithTrustedData
|
||||||
|
func BlockWithTrustedDataToDomainBlockWithTrustedData(block *MsgBlockWithTrustedData) *externalapi.BlockWithTrustedData {
|
||||||
|
daaWindow := make([]*externalapi.TrustedDataDataDAABlock, len(block.DAAWindow))
|
||||||
|
for i, daaBlock := range block.DAAWindow {
|
||||||
|
daaWindow[i] = &externalapi.TrustedDataDataDAABlock{
|
||||||
|
Block: MsgBlockToDomainBlock(daaBlock.Block),
|
||||||
|
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),
|
||||||
|
DAAScore: block.DAAScore,
|
||||||
|
DAAWindow: daaWindow,
|
||||||
|
GHOSTDAGData: 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: DomainBlockToMsgBlock(daaBlock.Block),
|
||||||
|
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.DAAScore,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,24 +45,27 @@ const (
|
|||||||
CmdRequestRelayBlocks
|
CmdRequestRelayBlocks
|
||||||
CmdInvTransaction
|
CmdInvTransaction
|
||||||
CmdRequestTransactions
|
CmdRequestTransactions
|
||||||
CmdIBDBlock
|
|
||||||
CmdDoneHeaders
|
CmdDoneHeaders
|
||||||
CmdTransactionNotFound
|
CmdTransactionNotFound
|
||||||
CmdReject
|
CmdReject
|
||||||
CmdHeader
|
|
||||||
CmdRequestNextHeaders
|
CmdRequestNextHeaders
|
||||||
CmdRequestPruningPointUTXOSetAndBlock
|
CmdRequestPruningPointUTXOSet
|
||||||
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
|
||||||
|
|
||||||
// rpc
|
// rpc
|
||||||
CmdGetCurrentNetworkRequestMessage
|
CmdGetCurrentNetworkRequestMessage
|
||||||
@@ -137,6 +140,11 @@ const (
|
|||||||
CmdPruningPointUTXOSetOverrideNotificationMessage
|
CmdPruningPointUTXOSetOverrideNotificationMessage
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage
|
CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideResponseMessage
|
CmdStopNotifyingPruningPointUTXOSetOverrideResponseMessage
|
||||||
|
CmdEstimateNetworkHashesPerSecondRequestMessage
|
||||||
|
CmdEstimateNetworkHashesPerSecondResponseMessage
|
||||||
|
CmdNotifyVirtualDaaScoreChangedRequestMessage
|
||||||
|
CmdNotifyVirtualDaaScoreChangedResponseMessage
|
||||||
|
CmdVirtualDaaScoreChangedNotificationMessage
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
||||||
@@ -145,7 +153,7 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{
|
|||||||
CmdVerAck: "VerAck",
|
CmdVerAck: "VerAck",
|
||||||
CmdRequestAddresses: "RequestAddresses",
|
CmdRequestAddresses: "RequestAddresses",
|
||||||
CmdAddresses: "Addresses",
|
CmdAddresses: "Addresses",
|
||||||
CmdRequestHeaders: "RequestHeaders",
|
CmdRequestHeaders: "CmdRequestHeaders",
|
||||||
CmdBlock: "Block",
|
CmdBlock: "Block",
|
||||||
CmdTx: "Tx",
|
CmdTx: "Tx",
|
||||||
CmdPing: "Ping",
|
CmdPing: "Ping",
|
||||||
@@ -156,24 +164,27 @@ 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",
|
||||||
CmdRequestPruningPointUTXOSetAndBlock: "RequestPruningPointUTXOSetAndBlock",
|
CmdRequestPruningPointUTXOSet: "RequestPruningPointUTXOSet",
|
||||||
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",
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCMessageCommandToString maps all MessageCommands to their string representation
|
// RPCMessageCommandToString maps all MessageCommands to their string representation
|
||||||
@@ -248,6 +259,11 @@ var RPCMessageCommandToString = map[MessageCommand]string{
|
|||||||
CmdPruningPointUTXOSetOverrideNotificationMessage: "PruningPointUTXOSetOverrideNotification",
|
CmdPruningPointUTXOSetOverrideNotificationMessage: "PruningPointUTXOSetOverrideNotification",
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage: "StopNotifyingPruningPointUTXOSetOverrideRequest",
|
CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage: "StopNotifyingPruningPointUTXOSetOverrideRequest",
|
||||||
CmdStopNotifyingPruningPointUTXOSetOverrideResponseMessage: "StopNotifyingPruningPointUTXOSetOverrideResponse",
|
CmdStopNotifyingPruningPointUTXOSetOverrideResponseMessage: "StopNotifyingPruningPointUTXOSetOverrideResponse",
|
||||||
|
CmdEstimateNetworkHashesPerSecondRequestMessage: "EstimateNetworkHashesPerSecondRequest",
|
||||||
|
CmdEstimateNetworkHashesPerSecondResponseMessage: "EstimateNetworkHashesPerSecondResponse",
|
||||||
|
CmdNotifyVirtualDaaScoreChangedRequestMessage: "NotifyVirtualDaaScoreChangedRequest",
|
||||||
|
CmdNotifyVirtualDaaScoreChangedResponseMessage: "NotifyVirtualDaaScoreChangedResponse",
|
||||||
|
CmdVirtualDaaScoreChangedNotificationMessage: "VirtualDaaScoreChangedNotification",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is an interface that describes a kaspa message. A type that
|
// Message is an interface that describes a kaspa message. A type that
|
||||||
|
|||||||
@@ -21,13 +21,18 @@ func TestBlock(t *testing.T) {
|
|||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
|
|
||||||
// Block 1 header.
|
// Block 1 header.
|
||||||
parentHashes := blockOne.Header.ParentHashes
|
parents := blockOne.Header.Parents
|
||||||
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
|
||||||
bh := NewBlockHeader(1, parentHashes, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce)
|
daaScore := blockOne.Header.DAAScore
|
||||||
|
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)
|
||||||
@@ -131,7 +136,7 @@ func TestConvertToPartial(t *testing.T) {
|
|||||||
var blockOne = MsgBlock{
|
var blockOne = MsgBlock{
|
||||||
Header: MsgBlockHeader{
|
Header: MsgBlockHeader{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
ParentHashes: []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash},
|
Parents: []externalapi.BlockLevelParents{[]*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}},
|
||||||
HashMerkleRoot: mainnetGenesisMerkleRoot,
|
HashMerkleRoot: mainnetGenesisMerkleRoot,
|
||||||
AcceptedIDMerkleRoot: exampleAcceptedIDMerkleRoot,
|
AcceptedIDMerkleRoot: exampleAcceptedIDMerkleRoot,
|
||||||
UTXOCommitment: exampleUTXOCommitment,
|
UTXOCommitment: exampleUTXOCommitment,
|
||||||
|
|||||||
@@ -5,13 +5,12 @@
|
|||||||
package appmessage
|
package appmessage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math/big"
|
||||||
|
|
||||||
"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,
|
||||||
@@ -39,8 +38,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
|
||||||
|
|
||||||
// Hashes of the parent block headers in the blockDAG.
|
// Parents are the parent block hashes of the block in the DAG per superblock level.
|
||||||
ParentHashes []*externalapi.DomainHash
|
Parents []externalapi.BlockLevelParents
|
||||||
|
|
||||||
// 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
|
||||||
@@ -60,15 +59,16 @@ type MsgBlockHeader struct {
|
|||||||
|
|
||||||
// Nonce used to generate the block.
|
// Nonce used to generate the block.
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
}
|
|
||||||
|
|
||||||
// NumParentBlocks return the number of entries in ParentHashes
|
// DAASCore is the DAA score of the block.
|
||||||
func (h *MsgBlockHeader) NumParentBlocks() byte {
|
DAAScore uint64
|
||||||
numParents := len(h.ParentHashes)
|
|
||||||
if numParents > math.MaxUint8 {
|
BlueScore uint64
|
||||||
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.
|
||||||
return byte(numParents)
|
BlueWork *big.Int
|
||||||
|
|
||||||
|
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,33 +76,27 @@ 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, parentHashes []*externalapi.DomainHash, hashMerkleRoot *externalapi.DomainHash,
|
func NewBlockHeader(version uint16, parents []externalapi.BlockLevelParents, hashMerkleRoot *externalapi.DomainHash,
|
||||||
acceptedIDMerkleRoot *externalapi.DomainHash, utxoCommitment *externalapi.DomainHash, bits uint32, nonce uint64) *MsgBlockHeader {
|
acceptedIDMerkleRoot *externalapi.DomainHash, utxoCommitment *externalapi.DomainHash, bits uint32, nonce,
|
||||||
|
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,
|
||||||
ParentHashes: parentHashes,
|
Parents: parents,
|
||||||
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,29 +5,34 @@
|
|||||||
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"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestBlockHeader tests the MsgBlockHeader API.
|
// TestBlockHeader tests the MsgBlockHeader API.
|
||||||
func TestBlockHeader(t *testing.T) {
|
func TestBlockHeader(t *testing.T) {
|
||||||
nonce := uint64(0xba4d87a69924a93d)
|
nonce := uint64(0xba4d87a69924a93d)
|
||||||
|
|
||||||
hashes := []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}
|
parents := []externalapi.BlockLevelParents{[]*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}}
|
||||||
|
|
||||||
merkleHash := mainnetGenesisMerkleRoot
|
merkleHash := mainnetGenesisMerkleRoot
|
||||||
acceptedIDMerkleRoot := exampleAcceptedIDMerkleRoot
|
acceptedIDMerkleRoot := exampleAcceptedIDMerkleRoot
|
||||||
bits := uint32(0x1d00ffff)
|
bits := uint32(0x1d00ffff)
|
||||||
bh := NewBlockHeader(1, hashes, merkleHash, acceptedIDMerkleRoot, exampleUTXOCommitment, bits, nonce)
|
daaScore := uint64(123)
|
||||||
|
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.ParentHashes, hashes) {
|
if !reflect.DeepEqual(bh.Parents, parents) {
|
||||||
t.Errorf("NewBlockHeader: wrong prev hashes - got %v, want %v",
|
t.Errorf("NewBlockHeader: wrong parents - got %v, want %v",
|
||||||
spew.Sprint(bh.ParentHashes), spew.Sprint(hashes))
|
spew.Sprint(bh.Parents), spew.Sprint(parents))
|
||||||
}
|
}
|
||||||
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",
|
||||||
@@ -41,44 +46,20 @@ 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",
|
||||||
func TestIsGenesis(t *testing.T) {
|
bh.DAAScore, daaScore)
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
genesisBlockHdr := &MsgBlockHeader{
|
if bh.BlueScore != blueScore {
|
||||||
Version: 1,
|
t.Errorf("NewBlockHeader: wrong blueScore - got %v, want %v",
|
||||||
ParentHashes: []*externalapi.DomainHash{},
|
bh.BlueScore, blueScore)
|
||||||
HashMerkleRoot: mainnetGenesisMerkleRoot,
|
|
||||||
Timestamp: timestamp,
|
|
||||||
Bits: bits,
|
|
||||||
Nonce: nonce,
|
|
||||||
}
|
}
|
||||||
|
if bh.BlueWork != blueWork {
|
||||||
tests := []struct {
|
t.Errorf("NewBlockHeader: wrong blueWork - got %v, want %v",
|
||||||
in *MsgBlockHeader // Block header to encode
|
bh.BlueWork, blueWork)
|
||||||
isGenesis bool // Expected result for call of .IsGenesis
|
|
||||||
}{
|
|
||||||
{genesisBlockHdr, true},
|
|
||||||
{baseBlockHdr, false},
|
|
||||||
}
|
}
|
||||||
|
if !bh.PruningPoint.Equal(pruningPoint) {
|
||||||
t.Logf("Running %d tests", len(tests))
|
t.Errorf("NewBlockHeader: wrong pruningPoint - got %v, want %v",
|
||||||
for i, test := range tests {
|
bh.PruningPoint, pruningPoint)
|
||||||
isGenesis := test.in.IsGenesis()
|
|
||||||
if isGenesis != test.isGenesis {
|
|
||||||
t.Errorf("MsgBlockHeader.IsGenesis: #%d got: %t, want: %t",
|
|
||||||
i, isGenesis, test.isGenesis)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
app/appmessage/p2p_msgblockwithtrusteddata.go
Normal file
54
app/appmessage/p2p_msgblockwithtrusteddata.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
21
app/appmessage/p2p_msgdoneblockswithmetadata.go
Normal file
21
app/appmessage/p2p_msgdoneblockswithmetadata.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
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{}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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{}
|
||||||
|
}
|
||||||
@@ -1,65 +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 (
|
|
||||||
"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,23 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
app/appmessage/p2p_msgpruningpointproof.go
Normal file
20
app/appmessage/p2p_msgpruningpointproof.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/appmessage/p2p_msgpruningpoints.go
Normal file
20
app/appmessage/p2p_msgpruningpoints.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@ 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
|
||||||
}
|
}
|
||||||
@@ -24,9 +23,8 @@ 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(lowHash, highHash *externalapi.DomainHash, limit uint32) *MsgRequestBlockLocator {
|
func NewMsgRequestBlockLocator(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, &externalapi.DomainHash{}, 0)
|
msg := NewMsgRequestBlockLocator(highHash, 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 MsgRequestHeaders API.
|
// TestRequstIBDBlocks tests the MsgRequestIBDBlocks 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("NewMsgRequstHeaders: wrong high hash - got %v, want %v",
|
t.Errorf("NewMsgRequstIBDBlocks: 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("NewMsgRequstHeaders: wrong command - got %v want %v",
|
t.Errorf("NewMsgRequstIBDBlocks: wrong command - got %v want %v",
|
||||||
cmd, wantCmd)
|
cmd, wantCmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
app/appmessage/p2p_msgrequestpruningpointproof.go
Normal file
16
app/appmessage/p2p_msgrequestpruningpointproof.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgRequestPruningPointUTXOSetAndBlock represents a kaspa RequestPruningPointUTXOSetAndBlock message
|
// MsgRequestPruningPointUTXOSet represents a kaspa RequestPruningPointUTXOSet message
|
||||||
type MsgRequestPruningPointUTXOSetAndBlock struct {
|
type MsgRequestPruningPointUTXOSet 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 *MsgRequestPruningPointUTXOSetAndBlock) Command() MessageCommand {
|
func (msg *MsgRequestPruningPointUTXOSet) Command() MessageCommand {
|
||||||
return CmdRequestPruningPointUTXOSetAndBlock
|
return CmdRequestPruningPointUTXOSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMsgRequestPruningPointUTXOSetAndBlock returns a new MsgRequestPruningPointUTXOSetAndBlock
|
// NewMsgRequestPruningPointUTXOSet returns a new MsgRequestPruningPointUTXOSet
|
||||||
func NewMsgRequestPruningPointUTXOSetAndBlock(pruningPointHash *externalapi.DomainHash) *MsgRequestPruningPointUTXOSetAndBlock {
|
func NewMsgRequestPruningPointUTXOSet(pruningPointHash *externalapi.DomainHash) *MsgRequestPruningPointUTXOSet {
|
||||||
return &MsgRequestPruningPointUTXOSetAndBlock{
|
return &MsgRequestPruningPointUTXOSet{
|
||||||
PruningPointHash: pruningPointHash,
|
PruningPointHash: pruningPointHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,16 +90,18 @@ 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) *TxIn {
|
func NewTxIn(prevOut *Outpoint, signatureScript []byte, sequence uint64, sigOpCount byte) *TxIn {
|
||||||
return &TxIn{
|
return &TxIn{
|
||||||
PreviousOutpoint: *prevOut,
|
PreviousOutpoint: *prevOut,
|
||||||
SignatureScript: signatureScript,
|
SignatureScript: signatureScript,
|
||||||
Sequence: sequence,
|
Sequence: sequence,
|
||||||
|
SigOpCount: sigOpCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +208,7 @@ 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.
|
||||||
|
|||||||
@@ -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)
|
txIn := NewTxIn(prevOut, sigScript, constants.MaxTxInSequenceNum, 1)
|
||||||
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),
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
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{}
|
|
||||||
}
|
|
||||||
43
app/appmessage/rpc_estimate_network_hashes_per_second.go
Normal file
43
app/appmessage/rpc_estimate_network_hashes_per_second.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,8 @@ package appmessage
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetBlockRequestMessage struct {
|
type GetBlockRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Hash string
|
Hash string
|
||||||
IncludeTransactionVerboseData bool
|
IncludeTransactions 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, includeTransactionVerboseData bool) *GetBlockRequestMessage {
|
func NewGetBlockRequestMessage(hash string, includeTransactions bool) *GetBlockRequestMessage {
|
||||||
return &GetBlockRequestMessage{
|
return &GetBlockRequestMessage{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
IncludeTransactionVerboseData: includeTransactionVerboseData,
|
IncludeTransactions: includeTransactions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ type GetBlockDAGInfoResponseMessage struct {
|
|||||||
Difficulty float64
|
Difficulty float64
|
||||||
PastMedianTime int64
|
PastMedianTime int64
|
||||||
PruningPointHash string
|
PruningPointHash string
|
||||||
|
VirtualDAAScore uint64
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ package appmessage
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetBlocksRequestMessage struct {
|
type GetBlocksRequestMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
LowHash string
|
LowHash string
|
||||||
IncludeBlocks bool
|
IncludeBlocks bool
|
||||||
IncludeTransactionVerboseData bool
|
IncludeTransactions bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the protocol command string for the message
|
// Command returns the protocol command string for the message
|
||||||
@@ -16,11 +16,11 @@ 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, includeBlocks bool,
|
||||||
includeTransactionVerboseData bool) *GetBlocksRequestMessage {
|
includeTransactions bool) *GetBlocksRequestMessage {
|
||||||
return &GetBlocksRequestMessage{
|
return &GetBlocksRequestMessage{
|
||||||
LowHash: lowHash,
|
LowHash: lowHash,
|
||||||
IncludeBlocks: includeBlocks,
|
IncludeBlocks: includeBlocks,
|
||||||
IncludeTransactionVerboseData: includeTransactionVerboseData,
|
IncludeTransactions: includeTransactions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ func (msg *GetInfoRequestMessage) Command() MessageCommand {
|
|||||||
return CmdGetInfoRequestMessage
|
return CmdGetInfoRequestMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGeInfoRequestMessage returns a instance of the message
|
// NewGetInfoRequestMessage returns a instance of the message
|
||||||
func NewGeInfoRequestMessage() *GetInfoRequestMessage {
|
func NewGetInfoRequestMessage() *GetInfoRequestMessage {
|
||||||
return &GetInfoRequestMessage{}
|
return &GetInfoRequestMessage{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,8 +20,9 @@ func NewGeInfoRequestMessage() *GetInfoRequestMessage {
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetInfoResponseMessage struct {
|
type GetInfoResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
P2PID string
|
P2PID string
|
||||||
MempoolSize uint64
|
MempoolSize uint64
|
||||||
|
ServerVersion string
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
@@ -32,9 +33,10 @@ 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) *GetInfoResponseMessage {
|
func NewGetInfoResponseMessage(p2pID string, mempoolSize uint64, serverVersion string) *GetInfoResponseMessage {
|
||||||
return &GetInfoResponseMessage{
|
return &GetInfoResponseMessage{
|
||||||
P2PID: p2pID,
|
P2PID: p2pID,
|
||||||
MempoolSize: mempoolSize,
|
MempoolSize: mempoolSize,
|
||||||
|
ServerVersion: serverVersion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func NewGetVirtualSelectedParentChainFromBlockRequestMessage(startHash string) *
|
|||||||
type GetVirtualSelectedParentChainFromBlockResponseMessage struct {
|
type GetVirtualSelectedParentChainFromBlockResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
RemovedChainBlockHashes []string
|
RemovedChainBlockHashes []string
|
||||||
AddedChainBlocks []*ChainBlock
|
AddedChainBlockHashes []string
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
@@ -35,11 +35,11 @@ func (msg *GetVirtualSelectedParentChainFromBlockResponseMessage) Command() Mess
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetVirtualSelectedParentChainFromBlockResponseMessage returns a instance of the message
|
// NewGetVirtualSelectedParentChainFromBlockResponseMessage returns a instance of the message
|
||||||
func NewGetVirtualSelectedParentChainFromBlockResponseMessage(removedChainBlockHashes []string,
|
func NewGetVirtualSelectedParentChainFromBlockResponseMessage(removedChainBlockHashes,
|
||||||
addedChainBlocks []*ChainBlock) *GetVirtualSelectedParentChainFromBlockResponseMessage {
|
addedChainBlockHashes []string) *GetVirtualSelectedParentChainFromBlockResponseMessage {
|
||||||
|
|
||||||
return &GetVirtualSelectedParentChainFromBlockResponseMessage{
|
return &GetVirtualSelectedParentChainFromBlockResponseMessage{
|
||||||
RemovedChainBlockHashes: removedChainBlockHashes,
|
RemovedChainBlockHashes: removedChainBlockHashes,
|
||||||
AddedChainBlocks: addedChainBlocks,
|
AddedChainBlockHashes: addedChainBlockHashes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
app/appmessage/rpc_notify_virtual_daa_score_changed.go
Normal file
55
app/appmessage/rpc_notify_virtual_daa_score_changed.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,19 +38,7 @@ func NewNotifyVirtualSelectedParentChainChangedResponseMessage() *NotifyVirtualS
|
|||||||
type VirtualSelectedParentChainChangedNotificationMessage struct {
|
type VirtualSelectedParentChainChangedNotificationMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
RemovedChainBlockHashes []string
|
RemovedChainBlockHashes []string
|
||||||
AddedChainBlocks []*ChainBlock
|
AddedChainBlockHashes []string
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
@@ -59,11 +47,11 @@ func (msg *VirtualSelectedParentChainChangedNotificationMessage) Command() Messa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewVirtualSelectedParentChainChangedNotificationMessage returns a instance of the message
|
// NewVirtualSelectedParentChainChangedNotificationMessage returns a instance of the message
|
||||||
func NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes []string,
|
func NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes,
|
||||||
addedChainBlocks []*ChainBlock) *VirtualSelectedParentChainChangedNotificationMessage {
|
addedChainBlocks []string) *VirtualSelectedParentChainChangedNotificationMessage {
|
||||||
|
|
||||||
return &VirtualSelectedParentChainChangedNotificationMessage{
|
return &VirtualSelectedParentChainChangedNotificationMessage{
|
||||||
RemovedChainBlockHashes: removedChainBlockHashes,
|
RemovedChainBlockHashes: removedChainBlockHashes,
|
||||||
AddedChainBlocks: addedChainBlocks,
|
AddedChainBlockHashes: addedChainBlocks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (msg *SubmitBlockResponseMessage) Command() MessageCommand {
|
|||||||
return CmdSubmitBlockResponseMessage
|
return CmdSubmitBlockResponseMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubmitBlockResponseMessage returns a instance of the message
|
// NewSubmitBlockResponseMessage returns an instance of the message
|
||||||
func NewSubmitBlockResponseMessage() *SubmitBlockResponseMessage {
|
func NewSubmitBlockResponseMessage() *SubmitBlockResponseMessage {
|
||||||
return &SubmitBlockResponseMessage{}
|
return &SubmitBlockResponseMessage{}
|
||||||
}
|
}
|
||||||
@@ -70,13 +70,22 @@ type RPCBlock struct {
|
|||||||
// used over RPC
|
// used over RPC
|
||||||
type RPCBlockHeader struct {
|
type RPCBlockHeader struct {
|
||||||
Version uint32
|
Version uint32
|
||||||
ParentHashes []string
|
Parents []*RPCBlockLevelParents
|
||||||
HashMerkleRoot string
|
HashMerkleRoot string
|
||||||
AcceptedIDMerkleRoot string
|
AcceptedIDMerkleRoot string
|
||||||
UTXOCommitment string
|
UTXOCommitment string
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
Bits uint32
|
Bits uint32
|
||||||
Nonce uint64
|
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
|
// RPCBlockVerboseData holds verbose data about a block
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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
|
||||||
@@ -13,9 +14,10 @@ func (msg *SubmitTransactionRequestMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewSubmitTransactionRequestMessage returns a instance of the message
|
// NewSubmitTransactionRequestMessage returns a instance of the message
|
||||||
func NewSubmitTransactionRequestMessage(transaction *RPCTransaction) *SubmitTransactionRequestMessage {
|
func NewSubmitTransactionRequestMessage(transaction *RPCTransaction, allowOrphan bool) *SubmitTransactionRequestMessage {
|
||||||
return &SubmitTransactionRequestMessage{
|
return &SubmitTransactionRequestMessage{
|
||||||
Transaction: transaction,
|
Transaction: transaction,
|
||||||
|
AllowOrphan: allowOrphan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ type RPCTransactionInput struct {
|
|||||||
PreviousOutpoint *RPCOutpoint
|
PreviousOutpoint *RPCOutpoint
|
||||||
SignatureScript string
|
SignatureScript string
|
||||||
Sequence uint64
|
Sequence uint64
|
||||||
|
SigOpCount byte
|
||||||
VerboseData *RPCTransactionInputVerboseData
|
VerboseData *RPCTransactionInputVerboseData
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +99,7 @@ type RPCUTXOEntry struct {
|
|||||||
type RPCTransactionVerboseData struct {
|
type RPCTransactionVerboseData struct {
|
||||||
TransactionID string
|
TransactionID string
|
||||||
Hash string
|
Hash string
|
||||||
Size uint64
|
Mass uint64
|
||||||
BlockHash string
|
BlockHash string
|
||||||
BlockTime uint64
|
BlockTime uint64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,19 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,8 +46,6 @@ 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +76,16 @@ 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) {
|
||||||
|
|
||||||
domain, err := domain.New(cfg.ActiveNetParams, db, cfg.IsArchivalNode)
|
consensusConfig := consensus.Config{
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@@ -155,23 +158,6 @@ func setupRPC(
|
|||||||
return rpcManager
|
return rpcManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ComponentManager) maybeSeedFromDNS() {
|
|
||||||
if !a.cfg.DisableDNSSeed {
|
|
||||||
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, 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, 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()
|
||||||
|
|||||||
57
app/db_version.go
Normal file
57
app/db_version.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
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/app/protocol/protocolerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"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/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||||
@@ -71,8 +72,6 @@ func (f *FlowContext) OnPruningPointUTXOSetOverride() error {
|
|||||||
func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
||||||
addedBlocks []*externalapi.DomainBlock, transactionsAcceptedToMempool []*externalapi.DomainTransaction) error {
|
addedBlocks []*externalapi.DomainBlock, transactionsAcceptedToMempool []*externalapi.DomainTransaction) error {
|
||||||
|
|
||||||
f.updateTransactionsToRebroadcast(addedBlocks)
|
|
||||||
|
|
||||||
// Don't relay transactions when in IBD.
|
// Don't relay transactions when in IBD.
|
||||||
if f.IsIBDRunning() {
|
if f.IsIBDRunning() {
|
||||||
return nil
|
return nil
|
||||||
@@ -80,7 +79,12 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
|||||||
|
|
||||||
var txIDsToRebroadcast []*externalapi.DomainTransactionID
|
var txIDsToRebroadcast []*externalapi.DomainTransactionID
|
||||||
if f.shouldRebroadcastTransactions() {
|
if f.shouldRebroadcastTransactions() {
|
||||||
txIDsToRebroadcast = f.txIDsToRebroadcast()
|
txsToRebroadcast, err := f.Domain().MiningManager().RevalidateHighPriorityTransactions()
|
||||||
|
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))
|
||||||
@@ -91,15 +95,7 @@ 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
|
||||||
@@ -114,7 +110,7 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
|||||||
return protocolerrors.Errorf(false, "cannot add header only block")
|
return protocolerrors.Errorf(false, "cannot add header only block")
|
||||||
}
|
}
|
||||||
|
|
||||||
blockInsertionResult, err := f.Domain().Consensus().ValidateAndInsertBlock(block)
|
blockInsertionResult, 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)
|
||||||
@@ -161,7 +157,6 @@ 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
|
||||||
|
|||||||
@@ -29,3 +29,8 @@ func (*FlowContext) HandleError(err error, flowName string, isStopping *uint32,
|
|||||||
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,10 +1,11 @@
|
|||||||
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"
|
||||||
@@ -46,10 +47,8 @@ type FlowContext struct {
|
|||||||
onPruningPointUTXOSetOverrideHandler OnPruningPointUTXOSetOverrideHandler
|
onPruningPointUTXOSetOverrideHandler OnPruningPointUTXOSetOverrideHandler
|
||||||
onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler
|
onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler
|
||||||
|
|
||||||
transactionsToRebroadcastLock sync.Mutex
|
lastRebroadcastTime time.Time
|
||||||
transactionsToRebroadcast map[externalapi.DomainTransactionID]*externalapi.DomainTransaction
|
sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions
|
||||||
lastRebroadcastTime time.Time
|
|
||||||
sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions
|
|
||||||
|
|
||||||
sharedRequestedBlocks *blockrelay.SharedRequestedBlocks
|
sharedRequestedBlocks *blockrelay.SharedRequestedBlocks
|
||||||
|
|
||||||
@@ -62,6 +61,10 @@ 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{}
|
shutdownChan chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,18 +73,19 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage
|
|||||||
netAdapter *netadapter.NetAdapter, connectionManager *connmanager.ConnectionManager) *FlowContext {
|
netAdapter *netadapter.NetAdapter, connectionManager *connmanager.ConnectionManager) *FlowContext {
|
||||||
|
|
||||||
return &FlowContext{
|
return &FlowContext{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
netAdapter: netAdapter,
|
netAdapter: netAdapter,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
addressManager: addressManager,
|
addressManager: addressManager,
|
||||||
connectionManager: connectionManager,
|
connectionManager: connectionManager,
|
||||||
sharedRequestedTransactions: transactionrelay.NewSharedRequestedTransactions(),
|
sharedRequestedTransactions: transactionrelay.NewSharedRequestedTransactions(),
|
||||||
sharedRequestedBlocks: blockrelay.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{},
|
||||||
shutdownChan: make(chan struct{}),
|
lastTransactionIDPropagationTime: time.Now(),
|
||||||
|
shutdownChan: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,10 +73,10 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*Uno
|
|||||||
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.ParentHashes())
|
orphanHash, orphanBlock.Header.DirectParents())
|
||||||
|
|
||||||
canBeUnorphaned := true
|
canBeUnorphaned := true
|
||||||
for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes() {
|
for _, orphanBlockParentHash := range orphanBlock.Header.DirectParents() {
|
||||||
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
|
||||||
@@ -133,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.ParentHashes() {
|
for _, orphanBlockParentHash := range orphanBlock.Header.DirectParents() {
|
||||||
if orphanBlockParentHash.Equal(blockHash) {
|
if orphanBlockParentHash.Equal(blockHash) {
|
||||||
childOrphans = append(childOrphans, orphanHash)
|
childOrphans = append(childOrphans, orphanHash)
|
||||||
break
|
break
|
||||||
@@ -150,7 +150,7 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa
|
|||||||
}
|
}
|
||||||
delete(f.orphans, orphanHash)
|
delete(f.orphans, orphanHash)
|
||||||
|
|
||||||
blockInsertionResult, err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock)
|
blockInsertionResult, err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock, true)
|
||||||
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)
|
||||||
@@ -201,7 +201,7 @@ func (f *FlowContext) GetOrphanRoots(orphan *externalapi.DomainHash) ([]*externa
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, parent := range block.Header.ParentHashes() {
|
for _, parent := range block.Header.DirectParents() {
|
||||||
if !addedToQueueSet.Contains(parent) {
|
if !addedToQueueSet.Contains(parent) {
|
||||||
queue = append(queue, parent)
|
queue = append(queue, parent)
|
||||||
addedToQueueSet.Add(parent)
|
addedToQueueSet.Add(parent)
|
||||||
|
|||||||
@@ -9,34 +9,18 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddTransaction adds transaction to the mempool and propagates it.
|
// TransactionIDPropagationInterval is the interval between transaction IDs propagations
|
||||||
func (f *FlowContext) AddTransaction(tx *externalapi.DomainTransaction) error {
|
const TransactionIDPropagationInterval = 500 * time.Millisecond
|
||||||
f.transactionsToRebroadcastLock.Lock()
|
|
||||||
defer f.transactionsToRebroadcastLock.Unlock()
|
|
||||||
|
|
||||||
err := f.Domain().MiningManager().ValidateAndInsertTransaction(tx, false)
|
// AddTransaction adds transaction to the mempool and propagates it.
|
||||||
|
func (f *FlowContext) AddTransaction(tx *externalapi.DomainTransaction, allowOrphan bool) error {
|
||||||
|
acceptedTransactions, err := f.Domain().MiningManager().ValidateAndInsertTransaction(tx, true, allowOrphan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionID := consensushashing.TransactionID(tx)
|
acceptedTransactionIDs := consensushashing.TransactionIDs(acceptedTransactions)
|
||||||
f.transactionsToRebroadcast[*transactionID] = tx
|
return f.EnqueueTransactionIDsForPropagation(acceptedTransactionIDs)
|
||||||
inv := appmessage.NewMsgInvTransaction([]*externalapi.DomainTransactionID{transactionID})
|
|
||||||
return f.Broadcast(inv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlowContext) updateTransactionsToRebroadcast(addedBlocks []*externalapi.DomainBlock) {
|
|
||||||
f.transactionsToRebroadcastLock.Lock()
|
|
||||||
defer f.transactionsToRebroadcastLock.Unlock()
|
|
||||||
|
|
||||||
for _, block := range addedBlocks {
|
|
||||||
// Note: if a transaction is included in the DAG but not accepted,
|
|
||||||
// it won't be rebroadcast anymore, although it is not included in
|
|
||||||
// the UTXO set
|
|
||||||
for _, tx := range block.Transactions {
|
|
||||||
delete(f.transactionsToRebroadcast, *consensushashing.TransactionID(tx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlowContext) shouldRebroadcastTransactions() bool {
|
func (f *FlowContext) shouldRebroadcastTransactions() bool {
|
||||||
@@ -44,19 +28,6 @@ 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() *transactionrelay.SharedRequestedTransactions {
|
func (f *FlowContext) SharedRequestedTransactions() *transactionrelay.SharedRequestedTransactions {
|
||||||
@@ -70,3 +41,42 @@ 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) sendGetBlockLocator(lowHash *externalapi.DomainHash,
|
func (flow *handleRelayInvsFlow) sendGetBlockLocator(highHash *externalapi.DomainHash, limit uint32) error {
|
||||||
highHash *externalapi.DomainHash, limit uint32) error {
|
msgGetBlockLocator := appmessage.NewMsgRequestBlockLocator(highHash, limit)
|
||||||
|
|
||||||
msgGetBlockLocator := appmessage.NewMsgRequestBlockLocator(lowHash, highHash, limit)
|
|
||||||
return flow.outgoingRoute.Enqueue(msgGetBlockLocator)
|
return flow.outgoingRoute.Enqueue(msgGetBlockLocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/app/protocol/peer"
|
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,7 +45,9 @@ 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.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,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, len(msgRequestIBDBlocks.Hashes))
|
log.Debugf("sent %d out of %d", i+1, len(msgRequestIBDBlocks.Hashes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package blockrelay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PruningPointAndItsAnticoneRequestsContext is the interface for the context needed for the HandlePruningPointAndItsAnticoneRequests flow.
|
||||||
|
type PruningPointAndItsAnticoneRequestsContext interface {
|
||||||
|
Domain() domain.Domain
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlePruningPointAndItsAnticoneRequests listens to appmessage.MsgRequestPruningPointAndItsAnticone messages and sends
|
||||||
|
// the pruning point and its anticone to the requesting peer.
|
||||||
|
func HandlePruningPointAndItsAnticoneRequests(context PruningPointAndItsAnticoneRequestsContext, incomingRoute *router.Route,
|
||||||
|
outgoingRoute *router.Route, peer *peerpkg.Peer) error {
|
||||||
|
|
||||||
|
for {
|
||||||
|
_, err := incomingRoute.Dequeue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Got request for pruning point and its anticone from %s", peer)
|
||||||
|
|
||||||
|
pruningPointHeaders, err := context.Domain().Consensus().PruningPointHeaders()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msgPruningPointHeaders := make([]*appmessage.MsgBlockHeader, len(pruningPointHeaders))
|
||||||
|
for i, header := range pruningPointHeaders {
|
||||||
|
msgPruningPointHeaders[i] = appmessage.DomainBlockHeaderToBlockHeader(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = outgoingRoute.Enqueue(appmessage.NewMsgPruningPoints(msgPruningPointHeaders))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks, err := context.Domain().Consensus().PruningPointAndItsAnticoneWithTrustedData()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, block := range blocks {
|
||||||
|
err = outgoingRoute.Enqueue(appmessage.DomainBlockWithTrustedDataToBlockWithTrustedData(block))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = outgoingRoute.Enqueue(appmessage.NewMsgDoneBlocksWithTrustedData())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Sent pruning point and its anticone to %s", peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package blockrelay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PruningPointProofRequestsContext is the interface for the context needed for the HandlePruningPointProofRequests flow.
|
||||||
|
type PruningPointProofRequestsContext interface {
|
||||||
|
Domain() domain.Domain
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlePruningPointProofRequests listens to appmessage.MsgRequestPruningPointProof messages and sends
|
||||||
|
// the pruning point proof to the requesting peer.
|
||||||
|
func HandlePruningPointProofRequests(context PruningPointProofRequestsContext, incomingRoute *router.Route,
|
||||||
|
outgoingRoute *router.Route, peer *peerpkg.Peer) error {
|
||||||
|
|
||||||
|
for {
|
||||||
|
_, err := incomingRoute.Dequeue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Got request for pruning point proof from %s", peer)
|
||||||
|
|
||||||
|
pruningPointProof, err := context.Domain().Consensus().BuildPruningPointProof()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pruningPointProofMessage := appmessage.DomainPruningPointProofToMsgPruningPointProof(pruningPointProof)
|
||||||
|
err = outgoingRoute.Enqueue(pruningPointProofMessage)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Sent pruning point proof to %s", peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ type RelayInvsContext interface {
|
|||||||
IsIBDRunning() bool
|
IsIBDRunning() bool
|
||||||
TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool
|
TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool
|
||||||
UnsetIBDRunning()
|
UnsetIBDRunning()
|
||||||
|
IsRecoverableError(err error) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type handleRelayInvsFlow struct {
|
type handleRelayInvsFlow struct {
|
||||||
@@ -126,7 +127,7 @@ 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, missingParents)
|
err := flow.processOrphan(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -228,7 +229,7 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock,
|
|||||||
|
|
||||||
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) {
|
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) {
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
return nil, nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
return nil, nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
||||||
@@ -249,7 +250,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, missingParents []*externalapi.DomainHash) error {
|
func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock) 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
|
||||||
@@ -274,7 +275,7 @@ func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock, m
|
|||||||
// 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)
|
return flow.runIBDIfNotRunning(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isBlockInOrphanResolutionRange finds out whether the given blockHash should be
|
// isBlockInOrphanResolutionRange finds out whether the given blockHash should be
|
||||||
@@ -283,8 +284,7 @@ func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock, m
|
|||||||
// 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) {
|
||||||
lowHash := flow.Config().ActiveNetParams.GenesisHash
|
err := flow.sendGetBlockLocator(blockHash, orphanResolutionRange)
|
||||||
err := flow.sendGetBlockLocator(lowHash, blockHash, orphanResolutionRange)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,20 +32,19 @@ func HandleRequestBlockLocator(context RequestBlockLocatorContext, incomingRoute
|
|||||||
|
|
||||||
func (flow *handleRequestBlockLocatorFlow) start() error {
|
func (flow *handleRequestBlockLocatorFlow) start() error {
|
||||||
for {
|
for {
|
||||||
lowHash, highHash, limit, err := flow.receiveGetBlockLocator()
|
highHash, limit, err := flow.receiveGetBlockLocator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debugf("Received getBlockLocator with lowHash: %s, highHash: %s, limit: %d",
|
log.Debugf("Received getBlockLocator with highHash: %s, limit: %d", highHash, limit)
|
||||||
lowHash, highHash, limit)
|
|
||||||
|
|
||||||
locator, err := flow.Domain().Consensus().CreateBlockLocator(lowHash, highHash, limit)
|
locator, err := flow.Domain().Consensus().CreateBlockLocatorFromPruningPoint(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 CreateBlockLocator: %s", err)
|
log.Debugf("Received error from CreateBlockLocatorFromPruningPoint: %s", err)
|
||||||
}
|
}
|
||||||
return protocolerrors.Errorf(true, "couldn't build a block "+
|
return protocolerrors.Errorf(true, "couldn't build a block "+
|
||||||
"locator between blocks %s and %s", lowHash, highHash)
|
"locator between the pruning point and %s", highHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = flow.sendBlockLocator(locator)
|
err = flow.sendBlockLocator(locator)
|
||||||
@@ -55,16 +54,15 @@ func (flow *handleRequestBlockLocatorFlow) start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRequestBlockLocatorFlow) receiveGetBlockLocator() (lowHash *externalapi.DomainHash,
|
func (flow *handleRequestBlockLocatorFlow) receiveGetBlockLocator() (highHash *externalapi.DomainHash, limit uint32, err error) {
|
||||||
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, nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
msgGetBlockLocator := message.(*appmessage.MsgRequestBlockLocator)
|
msgGetBlockLocator := message.(*appmessage.MsgRequestBlockLocator)
|
||||||
|
|
||||||
return msgGetBlockLocator.LowHash, msgGetBlockLocator.HighHash, msgGetBlockLocator.Limit, nil
|
return msgGetBlockLocator.HighHash, msgGetBlockLocator.Limit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRequestBlockLocatorFlow) sendBlockLocator(locator externalapi.BlockLocator) error {
|
func (flow *handleRequestBlockLocatorFlow) sendBlockLocator(locator externalapi.BlockLocator) error {
|
||||||
|
|||||||
@@ -12,26 +12,26 @@ import (
|
|||||||
|
|
||||||
const ibdBatchSize = router.DefaultMaxMessages
|
const ibdBatchSize = router.DefaultMaxMessages
|
||||||
|
|
||||||
// RequestIBDBlocksContext is the interface for the context needed for the HandleRequestHeaders flow.
|
// RequestHeadersContext is the interface for the context needed for the HandleRequestHeaders flow.
|
||||||
type RequestIBDBlocksContext interface {
|
type RequestHeadersContext interface {
|
||||||
Domain() domain.Domain
|
Domain() domain.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
type handleRequestHeadersFlow struct {
|
type handleRequestHeadersFlow struct {
|
||||||
RequestIBDBlocksContext
|
RequestHeadersContext
|
||||||
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 RequestIBDBlocksContext, incomingRoute *router.Route,
|
func HandleRequestHeaders(context RequestHeadersContext, incomingRoute *router.Route,
|
||||||
outgoingRoute *router.Route, peer *peer.Peer) error {
|
outgoingRoute *router.Route, peer *peer.Peer) error {
|
||||||
|
|
||||||
flow := &handleRequestHeadersFlow{
|
flow := &handleRequestHeadersFlow{
|
||||||
RequestIBDBlocksContext: context,
|
RequestHeadersContext: context,
|
||||||
incomingRoute: incomingRoute,
|
incomingRoute: incomingRoute,
|
||||||
outgoingRoute: outgoingRoute,
|
outgoingRoute: outgoingRoute,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
}
|
}
|
||||||
return flow.start()
|
return flow.start()
|
||||||
}
|
}
|
||||||
@@ -49,8 +49,9 @@ func (flow *handleRequestHeadersFlow) start() error {
|
|||||||
|
|
||||||
// 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
|
||||||
const maxBlueScoreDifference = 1 << 10
|
// maxBlocks MUST be >= MergeSetSizeLimit + 1
|
||||||
blockHashes, _, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference)
|
const maxBlocks = 1 << 10
|
||||||
|
blockHashes, _, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleRequestPruningPointUTXOSetContext is the interface for the context needed for the HandleRequestPruningPointUTXOSet flow.
|
||||||
|
type HandleRequestPruningPointUTXOSetContext interface {
|
||||||
|
Domain() domain.Domain
|
||||||
|
}
|
||||||
|
|
||||||
|
type handleRequestPruningPointUTXOSetFlow struct {
|
||||||
|
HandleRequestPruningPointUTXOSetContext
|
||||||
|
incomingRoute, outgoingRoute *router.Route
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleRequestPruningPointUTXOSet listens to appmessage.MsgRequestPruningPointUTXOSet messages and sends
|
||||||
|
// the pruning point UTXO set and block body.
|
||||||
|
func HandleRequestPruningPointUTXOSet(context HandleRequestPruningPointUTXOSetContext, incomingRoute,
|
||||||
|
outgoingRoute *router.Route) error {
|
||||||
|
|
||||||
|
flow := &handleRequestPruningPointUTXOSetFlow{
|
||||||
|
HandleRequestPruningPointUTXOSetContext: context,
|
||||||
|
incomingRoute: incomingRoute,
|
||||||
|
outgoingRoute: outgoingRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetFlow) start() error {
|
||||||
|
for {
|
||||||
|
msgRequestPruningPointUTXOSet, err := flow.waitForRequestPruningPointUTXOSetMessages()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.handleRequestPruningPointUTXOSetMessage(msgRequestPruningPointUTXOSet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetFlow) handleRequestPruningPointUTXOSetMessage(
|
||||||
|
msgRequestPruningPointUTXOSet *appmessage.MsgRequestPruningPointUTXOSet) error {
|
||||||
|
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "handleRequestPruningPointUTXOSetFlow")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
|
log.Debugf("Got request for pruning point UTXO set")
|
||||||
|
|
||||||
|
return flow.sendPruningPointUTXOSet(msgRequestPruningPointUTXOSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetFlow) waitForRequestPruningPointUTXOSetMessages() (
|
||||||
|
*appmessage.MsgRequestPruningPointUTXOSet, error) {
|
||||||
|
|
||||||
|
message, err := flow.incomingRoute.Dequeue()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
msgRequestPruningPointUTXOSet, ok := message.(*appmessage.MsgRequestPruningPointUTXOSet)
|
||||||
|
if !ok {
|
||||||
|
return nil, protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdRequestPruningPointUTXOSet, message.Command())
|
||||||
|
}
|
||||||
|
return msgRequestPruningPointUTXOSet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRequestPruningPointUTXOSetFlow) sendPruningPointUTXOSet(
|
||||||
|
msgRequestPruningPointUTXOSet *appmessage.MsgRequestPruningPointUTXOSet) 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(
|
||||||
|
msgRequestPruningPointUTXOSet.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), msgRequestPruningPointUTXOSet.PruningPointHash)
|
||||||
|
|
||||||
|
outpointAndUTXOEntryPairs :=
|
||||||
|
appmessage.DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(pruningPointUTXOs)
|
||||||
|
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgPruningPointUTXOSetChunk(outpointAndUTXOEntryPairs))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
finished := len(pruningPointUTXOs) < step
|
||||||
|
if finished && chunksSent%ibdBatchSize != 0 {
|
||||||
|
log.Debugf("Finished sending UTXOs for pruning block %s",
|
||||||
|
msgRequestPruningPointUTXOSet.PruningPointHash)
|
||||||
|
|
||||||
|
return flow.outgoingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pruningPointUTXOs) > 0 {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
if finished {
|
||||||
|
log.Debugf("Finished sending UTXOs for pruning block %s",
|
||||||
|
msgRequestPruningPointUTXOSet.PruningPointHash)
|
||||||
|
|
||||||
|
return flow.outgoingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package blockrelay
|
package blockrelay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
@@ -17,78 +16,67 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.DomainHash) error {
|
func (flow *handleRelayInvsFlow) runIBDIfNotRunning(block *externalapi.DomainBlock) error {
|
||||||
wasIBDNotRunning := flow.TrySetIBDRunning(flow.peer)
|
wasIBDNotRunning := flow.TrySetIBDRunning(flow.peer)
|
||||||
if !wasIBDNotRunning {
|
if !wasIBDNotRunning {
|
||||||
log.Debugf("IBD is already running")
|
log.Debugf("IBD is already running")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer flow.UnsetIBDRunning()
|
|
||||||
|
|
||||||
|
isFinishedSuccessfully := false
|
||||||
|
defer func() {
|
||||||
|
flow.UnsetIBDRunning()
|
||||||
|
flow.logIBDFinished(isFinishedSuccessfully)
|
||||||
|
}()
|
||||||
|
|
||||||
|
highHash := consensushashing.BlockHash(block)
|
||||||
log.Debugf("IBD started with peer %s and highHash %s", flow.peer, highHash)
|
log.Debugf("IBD started with peer %s and highHash %s", flow.peer, highHash)
|
||||||
|
log.Debugf("Syncing blocks up to %s", highHash)
|
||||||
log.Debugf("Syncing headers up to %s", highHash)
|
log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash)
|
||||||
headersSynced, err := flow.syncHeaders(highHash)
|
highestSharedBlockHash, highestSharedBlockFound, err := flow.findHighestSharedBlockHash(highHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !headersSynced {
|
log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer)
|
||||||
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")
|
shouldDownloadHeadersProof, shouldSync, err := flow.shouldSyncAndShouldDownloadHeadersProof(block, highestSharedBlockFound)
|
||||||
syncedPruningPointUTXOSetSuccessfully, err := flow.syncPruningPointUTXOSet()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !syncedPruningPointUTXOSetSuccessfully {
|
|
||||||
log.Debugf("Aborting IBD because the pruning point UTXO set failed to sync")
|
if !shouldSync {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Debugf("Finished syncing the current pruning point UTXO set")
|
|
||||||
|
|
||||||
log.Debugf("Downloading block bodies up to %s", highHash)
|
if shouldDownloadHeadersProof {
|
||||||
|
log.Infof("Starting IBD with headers proof")
|
||||||
|
err := flow.ibdWithHeadersProof(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = flow.syncPruningPointFutureHeaders(flow.Domain().Consensus(), highestSharedBlockHash, highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = flow.syncMissingBlockBodies(highHash)
|
err = flow.syncMissingBlockBodies(highHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debugf("Finished downloading block bodies up to %s", highHash)
|
|
||||||
|
|
||||||
|
log.Debugf("Finished syncing blocks up to %s", highHash)
|
||||||
|
isFinishedSuccessfully = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncHeaders attempts to sync headers from the peer. This method may fail
|
func (flow *handleRelayInvsFlow) logIBDFinished(isFinishedSuccessfully bool) {
|
||||||
// because the peer and us have conflicting pruning points. In that case we
|
successString := "successfully"
|
||||||
// return (false, nil) so that we may stop IBD gracefully.
|
if !isFinishedSuccessfully {
|
||||||
func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) (bool, error) {
|
successString = "(interrupted)"
|
||||||
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 {
|
log.Infof("IBD finished %s", successString)
|
||||||
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
|
// findHighestSharedBlock attempts to find the highest shared block between the peer
|
||||||
@@ -208,20 +196,22 @@ func (flow *handleRelayInvsFlow) fetchHighestHash(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash,
|
func (flow *handleRelayInvsFlow) syncPruningPointFutureHeaders(consensus externalapi.Consensus, highestSharedBlockHash *externalapi.DomainHash,
|
||||||
highHash *externalapi.DomainHash) error {
|
highHash *externalapi.DomainHash) error {
|
||||||
|
|
||||||
|
log.Infof("Downloading headers from %s", flow.peer)
|
||||||
|
|
||||||
err := flow.sendRequestHeaders(highestSharedBlockHash, highHash)
|
err := flow.sendRequestHeaders(highestSharedBlockHash, highHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep a short queue of blockHeadersMessages so that there's
|
// Keep a short queue of BlockHeadersMessages so that there's
|
||||||
// never a moment when the node is not validating and inserting
|
// never a moment when the node is not validating and inserting
|
||||||
// headers
|
// headers
|
||||||
blockHeadersMessageChan := make(chan *appmessage.BlockHeadersMessage, 2)
|
blockHeadersMessageChan := make(chan *appmessage.BlockHeadersMessage, 2)
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
spawn("handleRelayInvsFlow-downloadHeaders", func() {
|
spawn("handleRelayInvsFlow-syncPruningPointFutureHeaders", func() {
|
||||||
for {
|
for {
|
||||||
blockHeadersMessage, doneIBD, err := flow.receiveHeaders()
|
blockHeadersMessage, doneIBD, err := flow.receiveHeaders()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -245,12 +235,21 @@ func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externa
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case blockHeadersMessage, ok := <-blockHeadersMessageChan:
|
case ibdBlocksMessage, ok := <-blockHeadersMessageChan:
|
||||||
if !ok {
|
if !ok {
|
||||||
|
// If the highHash has not been received, the peer is misbehaving
|
||||||
|
highHashBlockInfo, err := consensus.GetBlockInfo(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !highHashBlockInfo.Exists {
|
||||||
|
return protocolerrors.Errorf(true, "did not receive "+
|
||||||
|
"highHash block %s from peer %s during block download", highHash, flow.peer)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, header := range blockHeadersMessage.BlockHeaders {
|
for _, header := range ibdBlocksMessage.BlockHeaders {
|
||||||
err = flow.processHeader(header)
|
err = flow.processHeader(consensus, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -268,7 +267,7 @@ func (flow *handleRelayInvsFlow) sendRequestHeaders(highestSharedBlockHash *exte
|
|||||||
return flow.outgoingRoute.Enqueue(msgGetBlockInvs)
|
return flow.outgoingRoute.Enqueue(msgGetBlockInvs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) receiveHeaders() (msgIBDBlock *appmessage.BlockHeadersMessage, doneIBD bool, err error) {
|
func (flow *handleRelayInvsFlow) receiveHeaders() (msgIBDBlock *appmessage.BlockHeadersMessage, doneHeaders bool, err error) {
|
||||||
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@@ -281,11 +280,14 @@ func (flow *handleRelayInvsFlow) receiveHeaders() (msgIBDBlock *appmessage.Block
|
|||||||
default:
|
default:
|
||||||
return nil, false,
|
return nil, false,
|
||||||
protocolerrors.Errorf(true, "received unexpected message type. "+
|
protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
"expected: %s or %s, got: %s", appmessage.CmdHeader, appmessage.CmdDoneHeaders, message.Command())
|
"expected: %s or %s, got: %s",
|
||||||
|
appmessage.CmdBlockHeaders,
|
||||||
|
appmessage.CmdDoneHeaders,
|
||||||
|
message.Command())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlockHeader) error {
|
func (flow *handleRelayInvsFlow) processHeader(consensus externalapi.Consensus, msgBlockHeader *appmessage.MsgBlockHeader) error {
|
||||||
header := appmessage.BlockHeaderToDomainBlockHeader(msgBlockHeader)
|
header := appmessage.BlockHeaderToDomainBlockHeader(msgBlockHeader)
|
||||||
block := &externalapi.DomainBlock{
|
block := &externalapi.DomainBlock{
|
||||||
Header: header,
|
Header: header,
|
||||||
@@ -293,7 +295,7 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
|
|||||||
}
|
}
|
||||||
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
blockInfo, err := flow.Domain().Consensus().GetBlockInfo(blockHash)
|
blockInfo, err := consensus.GetBlockInfo(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -301,7 +303,7 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
|
|||||||
log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash)
|
log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
_, err = consensus.ValidateAndInsertBlock(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
return errors.Wrapf(err, "failed to process header %s during IBD", blockHash)
|
return errors.Wrapf(err, "failed to process header %s during IBD", blockHash)
|
||||||
@@ -318,129 +320,42 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet() (bool, error) {
|
func (flow *handleRelayInvsFlow) validatePruningPointFutureHeaderTimestamps() error {
|
||||||
log.Debugf("Checking if a new pruning point is available")
|
headerSelectedTipHash, err := flow.Domain().StagingConsensus().GetHeadersSelectedTip()
|
||||||
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointHashMessage())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
headerSelectedTipHeader, err := flow.Domain().StagingConsensus().GetBlockHeader(headerSelectedTipHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return 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())
|
|
||||||
}
|
}
|
||||||
|
headerSelectedTipTimestamp := headerSelectedTipHeader.TimeInMilliseconds()
|
||||||
|
|
||||||
blockInfo, err := flow.Domain().Consensus().GetBlockInfo(msgPruningPointHash.Hash)
|
currentSelectedTipHash, err := flow.Domain().Consensus().GetHeadersSelectedTip()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
|
currentSelectedTipHeader, err := flow.Domain().Consensus().GetBlockHeader(currentSelectedTipHash)
|
||||||
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 {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
|
}
|
||||||
|
currentSelectedTipTimestamp := currentSelectedTipHeader.TimeInMilliseconds()
|
||||||
|
|
||||||
|
if headerSelectedTipTimestamp < currentSelectedTipTimestamp {
|
||||||
|
return protocolerrors.Errorf(false, "the timestamp of the candidate selected "+
|
||||||
|
"tip is smaller than the current selected tip")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isValid {
|
minTimestampDifferenceInMilliseconds := (10 * time.Minute).Milliseconds()
|
||||||
log.Infof("The suggested pruning point %s is incompatible to this node DAG, so stopping IBD with this"+
|
if headerSelectedTipTimestamp-currentSelectedTipTimestamp < minTimestampDifferenceInMilliseconds {
|
||||||
" peer", msgPruningPointHash.Hash)
|
return protocolerrors.Errorf(false, "difference between the timestamps of "+
|
||||||
return false, nil
|
"the current pruning point and the candidate pruning point is too small. Aborting IBD...")
|
||||||
}
|
}
|
||||||
|
return 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")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = flow.OnPruningPointUTXOSetOverride()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
func (flow *handleRelayInvsFlow) receiveAndInsertPruningPointUTXOSet(
|
||||||
pruningPointHash *externalapi.DomainHash) (bool, error) {
|
consensus externalapi.Consensus, pruningPointHash *externalapi.DomainHash) (bool, error) {
|
||||||
|
|
||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "receiveAndInsertPruningPointUTXOSet")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "receiveAndInsertPruningPointUTXOSet")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
@@ -459,7 +374,7 @@ func (flow *handleRelayInvsFlow) receiveAndInsertPruningPointUTXOSet(
|
|||||||
domainOutpointAndUTXOEntryPairs :=
|
domainOutpointAndUTXOEntryPairs :=
|
||||||
appmessage.OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs(message.OutpointAndUTXOEntryPairs)
|
appmessage.OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs(message.OutpointAndUTXOEntryPairs)
|
||||||
|
|
||||||
err := flow.Domain().Consensus().AppendImportedPruningPointUTXOs(domainOutpointAndUTXOEntryPairs)
|
err := consensus.AppendImportedPruningPointUTXOs(domainOutpointAndUTXOEntryPairs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -543,7 +458,7 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
log.Debugf("Skipping IBD Block %s as it has already been added to the DAG", blockHash)
|
log.Debugf("Skipping IBD Block %s as it has already been added to the DAG", blockHash)
|
||||||
@@ -558,7 +473,7 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return flow.Domain().Consensus().ResolveVirtual()
|
||||||
}
|
}
|
||||||
|
|
||||||
// dequeueIncomingMessageAndSkipInvs is a convenience method to be used during
|
// dequeueIncomingMessageAndSkipInvs is a convenience method to be used during
|
||||||
|
|||||||
364
app/protocol/flows/blockrelay/ibd_with_headers_proof.go
Normal file
364
app/protocol/flows/blockrelay/ibd_with_headers_proof.go
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
package blockrelay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"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) ibdWithHeadersProof(highHash *externalapi.DomainHash) error {
|
||||||
|
err := flow.Domain().InitStagingConsensus()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.downloadHeadersAndPruningUTXOSet(highHash)
|
||||||
|
if err != nil {
|
||||||
|
if !flow.IsRecoverableError(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteStagingConsensusErr := flow.Domain().DeleteStagingConsensus()
|
||||||
|
if deleteStagingConsensusErr != nil {
|
||||||
|
return deleteStagingConsensusErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.Domain().CommitStagingConsensus()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) shouldSyncAndShouldDownloadHeadersProof(highBlock *externalapi.DomainBlock,
|
||||||
|
highestSharedBlockFound bool) (shouldDownload, shouldSync bool, err error) {
|
||||||
|
|
||||||
|
if !highestSharedBlockFound {
|
||||||
|
hasMoreBlueWorkThanSelectedTipAndPruningDepthMoreBlueScore, err := flow.checkIfHighHashHasMoreBlueWorkThanSelectedTipAndPruningDepthMoreBlueScore(highBlock)
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasMoreBlueWorkThanSelectedTipAndPruningDepthMoreBlueScore {
|
||||||
|
return true, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) checkIfHighHashHasMoreBlueWorkThanSelectedTipAndPruningDepthMoreBlueScore(highBlock *externalapi.DomainBlock) (bool, error) {
|
||||||
|
headersSelectedTip, err := flow.Domain().Consensus().GetHeadersSelectedTip()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
headersSelectedTipInfo, err := flow.Domain().Consensus().GetBlockInfo(headersSelectedTip)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if highBlock.Header.BlueScore() < headersSelectedTipInfo.BlueScore+flow.Config().NetParams().PruningDepth() {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return highBlock.Header.BlueWork().Cmp(headersSelectedTipInfo.BlueWork) > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) syncAndValidatePruningPointProof() (*externalapi.DomainHash, error) {
|
||||||
|
log.Infof("Downloading the pruning point proof from %s", flow.peer)
|
||||||
|
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointProof())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pruningPointProofMessage, ok := message.(*appmessage.MsgPruningPointProof)
|
||||||
|
if !ok {
|
||||||
|
return nil, protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdPruningPointProof, message.Command())
|
||||||
|
}
|
||||||
|
pruningPointProof := appmessage.MsgPruningPointProofToDomainPruningPointProof(pruningPointProofMessage)
|
||||||
|
err = flow.Domain().Consensus().ValidatePruningPointProof(pruningPointProof)
|
||||||
|
if err != nil {
|
||||||
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
|
return nil, protocolerrors.Wrapf(true, err, "pruning point proof validation failed")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.Domain().StagingConsensus().ApplyPruningPointProof(pruningPointProof)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return consensushashing.HeaderHash(pruningPointProof.Headers[0][len(pruningPointProof.Headers[0])-1]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) downloadHeadersAndPruningUTXOSet(highHash *externalapi.DomainHash) error {
|
||||||
|
proofPruningPoint, err := flow.syncAndValidatePruningPointProof()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.syncPruningPointsAndPruningPointAnticone(proofPruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this condition once there's more proper way to check finality violation
|
||||||
|
// in the headers proof.
|
||||||
|
if proofPruningPoint.Equal(flow.Config().NetParams().GenesisHash) {
|
||||||
|
return protocolerrors.Errorf(true, "the genesis pruning point violates finality")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.syncPruningPointFutureHeaders(flow.Domain().StagingConsensus(), proofPruningPoint, highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Headers downloaded from peer %s", flow.peer)
|
||||||
|
|
||||||
|
highHashInfo, err := flow.Domain().StagingConsensus().GetBlockInfo(highHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !highHashInfo.Exists {
|
||||||
|
return protocolerrors.Errorf(true, "the triggering IBD block was not sent")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.validatePruningPointFutureHeaderTimestamps()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Syncing the current pruning point UTXO set")
|
||||||
|
syncedPruningPointUTXOSetSuccessfully, err := flow.syncPruningPointUTXOSet(flow.Domain().StagingConsensus(), proofPruningPoint)
|
||||||
|
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")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) syncPruningPointsAndPruningPointAnticone(proofPruningPoint *externalapi.DomainHash) error {
|
||||||
|
log.Infof("Downloading the past pruning points and the pruning point anticone from %s", flow.peer)
|
||||||
|
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointAndItsAnticone())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.validateAndInsertPruningPoints(proofPruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pruningPointWithMetaData, done, err := flow.receiveBlockWithTrustedData()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if done {
|
||||||
|
return protocolerrors.Errorf(true, "got `done` message before receiving the pruning point")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pruningPointWithMetaData.Block.Header.BlockHash().Equal(proofPruningPoint) {
|
||||||
|
return protocolerrors.Errorf(true, "first block with trusted data is not the pruning point")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.processBlockWithTrustedData(flow.Domain().StagingConsensus(), pruningPointWithMetaData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
blockWithTrustedData, done, err := flow.receiveBlockWithTrustedData()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if done {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.processBlockWithTrustedData(flow.Domain().StagingConsensus(), blockWithTrustedData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Finished downloading pruning point and its anticone from %s", flow.peer)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) processBlockWithTrustedData(
|
||||||
|
consensus externalapi.Consensus, block *appmessage.MsgBlockWithTrustedData) error {
|
||||||
|
|
||||||
|
_, err := consensus.ValidateAndInsertBlockWithTrustedData(appmessage.BlockWithTrustedDataToDomainBlockWithTrustedData(block), false)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) receiveBlockWithTrustedData() (*appmessage.MsgBlockWithTrustedData, bool, error) {
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch downCastedMessage := message.(type) {
|
||||||
|
case *appmessage.MsgBlockWithTrustedData:
|
||||||
|
return downCastedMessage, false, nil
|
||||||
|
case *appmessage.MsgDoneBlocksWithTrustedData:
|
||||||
|
return nil, true, nil
|
||||||
|
default:
|
||||||
|
return nil, false,
|
||||||
|
protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s or %s, got: %s",
|
||||||
|
(&appmessage.MsgBlockWithTrustedData{}).Command(),
|
||||||
|
(&appmessage.MsgDoneBlocksWithTrustedData{}).Command(),
|
||||||
|
downCastedMessage.Command())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) receivePruningPoints() (*appmessage.MsgPruningPoints, error) {
|
||||||
|
message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msgPruningPoints, ok := message.(*appmessage.MsgPruningPoints)
|
||||||
|
if !ok {
|
||||||
|
return nil,
|
||||||
|
protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||||
|
"expected: %s, got: %s", appmessage.CmdPruningPoints, message.Command())
|
||||||
|
}
|
||||||
|
|
||||||
|
return msgPruningPoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) validateAndInsertPruningPoints(proofPruningPoint *externalapi.DomainHash) error {
|
||||||
|
currentPruningPoint, err := flow.Domain().Consensus().PruningPoint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentPruningPoint.Equal(proofPruningPoint) {
|
||||||
|
return protocolerrors.Errorf(true, "the proposed pruning point is the same as the current pruning point")
|
||||||
|
}
|
||||||
|
|
||||||
|
pruningPoints, err := flow.receivePruningPoints()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := make([]externalapi.BlockHeader, len(pruningPoints.Headers))
|
||||||
|
for i, header := range pruningPoints.Headers {
|
||||||
|
headers[i] = appmessage.BlockHeaderToDomainBlockHeader(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
arePruningPointsViolatingFinality, err := flow.Domain().Consensus().ArePruningPointsViolatingFinality(headers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if arePruningPointsViolatingFinality {
|
||||||
|
// TODO: Find a better way to deal with finality conflicts.
|
||||||
|
return protocolerrors.Errorf(false, "pruning points are violating finality")
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPruningPoint := consensushashing.HeaderHash(headers[len(headers)-1])
|
||||||
|
if !lastPruningPoint.Equal(proofPruningPoint) {
|
||||||
|
return protocolerrors.Errorf(true, "the proof pruning point is not equal to the last pruning "+
|
||||||
|
"point in the list")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.Domain().StagingConsensus().ImportPruningPoints(headers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet(consensus externalapi.Consensus,
|
||||||
|
pruningPoint *externalapi.DomainHash) (bool, error) {
|
||||||
|
|
||||||
|
log.Infof("Checking if the suggested pruning point %s is compatible to the node DAG", pruningPoint)
|
||||||
|
isValid, err := flow.Domain().StagingConsensus().IsValidPruningPoint(pruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isValid {
|
||||||
|
return false, protocolerrors.Errorf(true, "invalid pruning point %s", pruningPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetching the pruning point UTXO set")
|
||||||
|
isSuccessful, err := flow.fetchMissingUTXOSet(consensus, pruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isSuccessful {
|
||||||
|
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(consensus externalapi.Consensus, pruningPointHash *externalapi.DomainHash) (succeed bool, err error) {
|
||||||
|
defer func() {
|
||||||
|
err := flow.Domain().StagingConsensus().ClearImportedPruningPointData()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to clear imported pruning point data: %s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointUTXOSet(pruningPointHash))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receivedAll, err := flow.receiveAndInsertPruningPointUTXOSet(consensus, pruningPointHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !receivedAll {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.Domain().StagingConsensus().ValidateAndInsertImportedPruningPoint(pruningPointHash)
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = flow.OnPruningPointUTXOSetOverride()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
@@ -4,12 +4,14 @@ 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
|
||||||
@@ -21,6 +23,11 @@ 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)
|
||||||
|
|||||||
@@ -33,10 +33,5 @@ func (flow *handleRejectsFlow) start() error {
|
|||||||
}
|
}
|
||||||
rejectMessage := message.(*appmessage.MsgReject)
|
rejectMessage := message.(*appmessage.MsgReject)
|
||||||
|
|
||||||
const maxReasonLength = 255
|
|
||||||
if len(rejectMessage.Reason) > maxReasonLength {
|
|
||||||
return protocolerrors.Errorf(false, "got reject message longer than %d", maxReasonLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
return protocolerrors.Errorf(false, "got reject message: `%s`", rejectMessage.Reason)
|
return protocolerrors.Errorf(false, "got reject message: `%s`", rejectMessage.Reason)
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,16 @@
|
|||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/flows/addressexchange"
|
"github.com/kaspanet/kaspad/app/protocol/flows/addressexchange"
|
||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakeReceiveAddressesContext struct{}
|
type fakeReceiveAddressesContext struct{}
|
||||||
@@ -19,9 +20,9 @@ func (f fakeReceiveAddressesContext) AddressManager() *addressmanager.AddressMan
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReceiveAddressesErrors(t *testing.T) {
|
func TestReceiveAddressesErrors(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
incomingRoute := router.NewRoute()
|
incomingRoute := router.NewRoute("incoming")
|
||||||
outgoingRoute := router.NewRoute()
|
outgoingRoute := router.NewRoute("outgoing")
|
||||||
peer := peerpkg.New(nil)
|
peer := peerpkg.New(nil)
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ type TransactionsRelayContext interface {
|
|||||||
NetAdapter() *netadapter.NetAdapter
|
NetAdapter() *netadapter.NetAdapter
|
||||||
Domain() domain.Domain
|
Domain() domain.Domain
|
||||||
SharedRequestedTransactions() *SharedRequestedTransactions
|
SharedRequestedTransactions() *SharedRequestedTransactions
|
||||||
Broadcast(message appmessage.Message) error
|
|
||||||
OnTransactionAddedToMempool()
|
OnTransactionAddedToMempool()
|
||||||
|
EnqueueTransactionIDsForPropagation(transactionIDs []*externalapi.DomainTransactionID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type handleRelayedTransactionsFlow struct {
|
type handleRelayedTransactionsFlow struct {
|
||||||
@@ -119,8 +119,7 @@ func (flow *handleRelayedTransactionsFlow) readInv() (*appmessage.MsgInvTransact
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayedTransactionsFlow) broadcastAcceptedTransactions(acceptedTxIDs []*externalapi.DomainTransactionID) error {
|
func (flow *handleRelayedTransactionsFlow) broadcastAcceptedTransactions(acceptedTxIDs []*externalapi.DomainTransactionID) error {
|
||||||
inv := appmessage.NewMsgInvTransaction(acceptedTxIDs)
|
return flow.EnqueueTransactionIDsForPropagation(acceptedTxIDs)
|
||||||
return flow.Broadcast(inv)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// readMsgTxOrNotFound returns the next msgTx or msgTransactionNotFound in incomingRoute,
|
// readMsgTxOrNotFound returns the next msgTx or msgTransactionNotFound in incomingRoute,
|
||||||
@@ -173,17 +172,18 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact
|
|||||||
expectedID, txID)
|
expectedID, txID)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = flow.Domain().MiningManager().ValidateAndInsertTransaction(tx, true)
|
acceptedTransactions, err :=
|
||||||
|
flow.Domain().MiningManager().ValidateAndInsertTransaction(tx, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ruleErr := &mempool.RuleError{}
|
ruleErr := &mempool.RuleError{}
|
||||||
if !errors.As(err, ruleErr) {
|
if !errors.As(err, ruleErr) {
|
||||||
return errors.Wrapf(err, "failed to process transaction %s", txID)
|
return errors.Wrapf(err, "failed to process transaction %s", txID)
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldBan := true
|
shouldBan := false
|
||||||
if txRuleErr := (&mempool.TxRuleError{}); errors.As(ruleErr.Err, txRuleErr) {
|
if txRuleErr := (&mempool.TxRuleError{}); errors.As(ruleErr.Err, txRuleErr) {
|
||||||
if txRuleErr.RejectCode != mempool.RejectInvalid {
|
if txRuleErr.RejectCode == mempool.RejectInvalid {
|
||||||
shouldBan = false
|
shouldBan = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact
|
|||||||
|
|
||||||
return protocolerrors.Errorf(true, "rejected transaction %s: %s", txID, ruleErr)
|
return protocolerrors.Errorf(true, "rejected transaction %s: %s", txID, ruleErr)
|
||||||
}
|
}
|
||||||
err = flow.broadcastAcceptedTransactions([]*externalapi.DomainTransactionID{txID})
|
err = flow.broadcastAcceptedTransactions(consensushashing.TransactionIDs(acceptedTransactions))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,191 @@
|
|||||||
|
package transactionrelay_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||||
|
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mocTransactionsRelayContext struct {
|
||||||
|
netAdapter *netadapter.NetAdapter
|
||||||
|
domain domain.Domain
|
||||||
|
sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mocTransactionsRelayContext) NetAdapter() *netadapter.NetAdapter {
|
||||||
|
return m.netAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mocTransactionsRelayContext) Domain() domain.Domain {
|
||||||
|
return m.domain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mocTransactionsRelayContext) SharedRequestedTransactions() *transactionrelay.SharedRequestedTransactions {
|
||||||
|
return m.sharedRequestedTransactions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mocTransactionsRelayContext) EnqueueTransactionIDsForPropagation(transactionIDs []*externalapi.DomainTransactionID) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mocTransactionsRelayContext) OnTransactionAddedToMempool() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestHandleRelayedTransactionsNotFound tests the flow of HandleRelayedTransactions when the peer doesn't
|
||||||
|
// have the requested transactions in the mempool.
|
||||||
|
func TestHandleRelayedTransactionsNotFound(t *testing.T) {
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
|
||||||
|
var log = logger.RegisterSubSystem("PROT")
|
||||||
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestHandleRelayedTransactionsNotFound")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up test consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
sharedRequestedTransactions := transactionrelay.NewSharedRequestedTransactions()
|
||||||
|
adapter, err := netadapter.NewNetAdapter(config.DefaultConfig())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create a NetAdapter: %v", err)
|
||||||
|
}
|
||||||
|
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to set up a domain instance: %v", err)
|
||||||
|
}
|
||||||
|
context := &mocTransactionsRelayContext{
|
||||||
|
netAdapter: adapter,
|
||||||
|
domain: domainInstance,
|
||||||
|
sharedRequestedTransactions: sharedRequestedTransactions,
|
||||||
|
}
|
||||||
|
incomingRoute := router.NewRoute("incoming")
|
||||||
|
defer incomingRoute.Close()
|
||||||
|
peerIncomingRoute := router.NewRoute("outgoing")
|
||||||
|
defer peerIncomingRoute.Close()
|
||||||
|
|
||||||
|
txID1 := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
|
||||||
|
txID2 := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})
|
||||||
|
txIDs := []*externalapi.DomainTransactionID{txID1, txID2}
|
||||||
|
invMessage := appmessage.NewMsgInvTransaction(txIDs)
|
||||||
|
err = incomingRoute.Enqueue(invMessage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
||||||
|
}
|
||||||
|
// The goroutine is representing the peer's actions.
|
||||||
|
spawn("peerResponseToTheTransactionsRequest", func() {
|
||||||
|
msg, err := peerIncomingRoute.Dequeue()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Dequeue: %v", err)
|
||||||
|
}
|
||||||
|
inv := msg.(*appmessage.MsgRequestTransactions)
|
||||||
|
|
||||||
|
if len(txIDs) != len(inv.IDs) {
|
||||||
|
t.Fatalf("TestHandleRelayedTransactions: expected %d transactions ID, but got %d", len(txIDs), len(inv.IDs))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, id := range inv.IDs {
|
||||||
|
if txIDs[i].String() != id.String() {
|
||||||
|
t.Fatalf("TestHandleRelayedTransactions: expected equal txID: expected %s, but got %s", txIDs[i].String(), id.String())
|
||||||
|
}
|
||||||
|
err = incomingRoute.Enqueue(appmessage.NewMsgTransactionNotFound(txIDs[i]))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Insert an unexpected message type to stop the infinity loop.
|
||||||
|
err = incomingRoute.Enqueue(&appmessage.MsgAddresses{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
err = transactionrelay.HandleRelayedTransactions(context, incomingRoute, peerIncomingRoute)
|
||||||
|
// Since we inserted an unexpected message type to stop the infinity loop,
|
||||||
|
// we expect the error will be infected from this specific message and also the
|
||||||
|
// error will count as a protocol message.
|
||||||
|
if protocolErr := (protocolerrors.ProtocolError{}); err == nil || !errors.As(err, &protocolErr) {
|
||||||
|
t.Fatalf("Expected to protocol error")
|
||||||
|
} else {
|
||||||
|
if !protocolErr.ShouldBan {
|
||||||
|
t.Fatalf("Exepcted shouldBan true, but got false.")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "unexpected Addresses [code 3] message in the block relay flow while expecting an inv message") {
|
||||||
|
t.Fatalf("Unexpected error: expected: an error due to existence of an Addresses message "+
|
||||||
|
"in the block relay flow, but got: %v", protocolErr.Cause)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestOnClosedIncomingRoute verifies that an appropriate error message will be returned when
|
||||||
|
// trying to dequeue a message from a closed route.
|
||||||
|
func TestOnClosedIncomingRoute(t *testing.T) {
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestOnClosedIncomingRoute")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up test consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
sharedRequestedTransactions := transactionrelay.NewSharedRequestedTransactions()
|
||||||
|
adapter, err := netadapter.NewNetAdapter(config.DefaultConfig())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to creat a NetAdapter : %v", err)
|
||||||
|
}
|
||||||
|
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to set up a domain instance: %v", err)
|
||||||
|
}
|
||||||
|
context := &mocTransactionsRelayContext{
|
||||||
|
netAdapter: adapter,
|
||||||
|
domain: domainInstance,
|
||||||
|
sharedRequestedTransactions: sharedRequestedTransactions,
|
||||||
|
}
|
||||||
|
incomingRoute := router.NewRoute("incoming")
|
||||||
|
outgoingRoute := router.NewRoute("outgoing")
|
||||||
|
defer outgoingRoute.Close()
|
||||||
|
|
||||||
|
txID := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
|
||||||
|
txIDs := []*externalapi.DomainTransactionID{txID}
|
||||||
|
|
||||||
|
err = incomingRoute.Enqueue(&appmessage.MsgInvTransaction{TxIDs: txIDs})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
||||||
|
}
|
||||||
|
incomingRoute.Close()
|
||||||
|
err = transactionrelay.HandleRelayedTransactions(context, incomingRoute, outgoingRoute)
|
||||||
|
if err == nil || !errors.Is(err, router.ErrRouteClosed) {
|
||||||
|
t.Fatalf("Unexpected error: expected: %v, got : %v", router.ErrRouteClosed, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package transactionrelay_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
||||||
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||||
|
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
"github.com/kaspanet/kaspad/util/panics"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestHandleRequestedTransactionsNotFound tests the flow of HandleRequestedTransactions
|
||||||
|
// when the requested transactions don't found in the mempool.
|
||||||
|
func TestHandleRequestedTransactionsNotFound(t *testing.T) {
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
var log = logger.RegisterSubSystem("PROT")
|
||||||
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestHandleRequestedTransactionsNotFound")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up test Consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
sharedRequestedTransactions := transactionrelay.NewSharedRequestedTransactions()
|
||||||
|
adapter, err := netadapter.NewNetAdapter(config.DefaultConfig())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create a NetAdapter: %v", err)
|
||||||
|
}
|
||||||
|
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to set up a domain Instance: %v", err)
|
||||||
|
}
|
||||||
|
context := &mocTransactionsRelayContext{
|
||||||
|
netAdapter: adapter,
|
||||||
|
domain: domainInstance,
|
||||||
|
sharedRequestedTransactions: sharedRequestedTransactions,
|
||||||
|
}
|
||||||
|
incomingRoute := router.NewRoute("incoming")
|
||||||
|
outgoingRoute := router.NewRoute("outgoing")
|
||||||
|
defer outgoingRoute.Close()
|
||||||
|
|
||||||
|
txID1 := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
|
||||||
|
txID2 := externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})
|
||||||
|
txIDs := []*externalapi.DomainTransactionID{txID1, txID2}
|
||||||
|
msg := appmessage.NewMsgRequestTransactions(txIDs)
|
||||||
|
err = incomingRoute.Enqueue(msg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error from incomingRoute.Enqueue: %v", err)
|
||||||
|
}
|
||||||
|
// The goroutine is representing the peer's actions.
|
||||||
|
spawn("peerResponseToTheTransactionsMessages", func() {
|
||||||
|
for i, id := range txIDs {
|
||||||
|
msg, err := outgoingRoute.Dequeue()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Dequeue: %s", err)
|
||||||
|
}
|
||||||
|
outMsg := msg.(*appmessage.MsgTransactionNotFound)
|
||||||
|
if txIDs[i].String() != outMsg.ID.String() {
|
||||||
|
t.Fatalf("TestHandleRelayedTransactions: expected equal txID: expected %s, but got %s", txIDs[i].String(), id.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Closed the incomingRoute for stop the infinity loop.
|
||||||
|
incomingRoute.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
err = transactionrelay.HandleRequestedTransactions(context, incomingRoute, outgoingRoute)
|
||||||
|
// Make sure the error is due to the closed route.
|
||||||
|
if err == nil || !errors.Is(err, router.ErrRouteClosed) {
|
||||||
|
t.Fatalf("Unexpected error: expected: %v, got : %v", router.ErrRouteClosed, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -2,10 +2,11 @@ package protocol
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain"
|
"github.com/kaspanet/kaspad/domain"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
@@ -61,8 +62,8 @@ func (m *Manager) IBDPeer() *peerpkg.Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddTransaction adds transaction to the mempool and propagates it.
|
// AddTransaction adds transaction to the mempool and propagates it.
|
||||||
func (m *Manager) AddTransaction(tx *externalapi.DomainTransaction) error {
|
func (m *Manager) AddTransaction(tx *externalapi.DomainTransaction, allowOrphan bool) error {
|
||||||
return m.context.AddTransaction(tx)
|
return m.context.AddTransaction(tx, allowOrphan)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddBlock adds the given block to the DAG and propagates it.
|
// AddBlock adds the given block to the DAG and propagates it.
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package protocol
|
package protocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/protocol/flows/rejects"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
@@ -11,10 +9,12 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/flows/handshake"
|
"github.com/kaspanet/kaspad/app/protocol/flows/handshake"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/flows/ping"
|
"github.com/kaspanet/kaspad/app/protocol/flows/ping"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/flows/rejects"
|
||||||
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
"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/app/protocol/protocolerrors"
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -106,7 +106,7 @@ func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection
|
|||||||
log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause)
|
log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause)
|
||||||
|
|
||||||
err := m.context.ConnectionManager().Ban(netConnection)
|
err := m.context.ConnectionManager().Ban(netConnection)
|
||||||
if !errors.Is(err, connmanager.ErrCannotBanPermanent) {
|
if err != nil && !errors.Is(err, connmanager.ErrCannotBanPermanent) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,10 +168,13 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping *
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{
|
m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{
|
||||||
appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock,
|
appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator,
|
||||||
appmessage.CmdDoneHeaders, appmessage.CmdUnexpectedPruningPoint, appmessage.CmdPruningPointUTXOSetChunk,
|
appmessage.CmdDoneHeaders, appmessage.CmdUnexpectedPruningPoint, appmessage.CmdPruningPointUTXOSetChunk,
|
||||||
appmessage.CmdBlockHeaders, appmessage.CmdPruningPointHash, appmessage.CmdIBDBlockLocatorHighestHash,
|
appmessage.CmdBlockHeaders, appmessage.CmdIBDBlockLocatorHighestHash, appmessage.CmdBlockWithTrustedData,
|
||||||
appmessage.CmdIBDBlockLocatorHighestHashNotFound, appmessage.CmdDonePruningPointUTXOSetChunks},
|
appmessage.CmdDoneBlocksWithTrustedData, appmessage.CmdIBDBlockLocatorHighestHashNotFound,
|
||||||
|
appmessage.CmdDonePruningPointUTXOSetChunks, appmessage.CmdIBDBlock, appmessage.CmdPruningPoints,
|
||||||
|
appmessage.CmdPruningPointProof,
|
||||||
|
},
|
||||||
isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||||
return blockrelay.HandleRelayInvs(m.context, incomingRoute,
|
return blockrelay.HandleRelayInvs(m.context, incomingRoute,
|
||||||
outgoingRoute, peer)
|
outgoingRoute, peer)
|
||||||
@@ -198,14 +201,6 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping *
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
m.registerFlow("HandleRequestPruningPointUTXOSetAndBlock", router,
|
|
||||||
[]appmessage.MessageCommand{appmessage.CmdRequestPruningPointUTXOSetAndBlock,
|
|
||||||
appmessage.CmdRequestNextPruningPointUTXOSetChunk}, isStopping, errChan,
|
|
||||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
|
||||||
return blockrelay.HandleRequestPruningPointUTXOSetAndBlock(m.context, incomingRoute, outgoingRoute)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
m.registerFlow("HandleIBDBlockRequests", router,
|
m.registerFlow("HandleIBDBlockRequests", router,
|
||||||
[]appmessage.MessageCommand{appmessage.CmdRequestIBDBlocks}, isStopping, errChan,
|
[]appmessage.MessageCommand{appmessage.CmdRequestIBDBlocks}, isStopping, errChan,
|
||||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||||
@@ -213,10 +208,18 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping *
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
m.registerFlow("HandlePruningPointHashRequests", router,
|
m.registerFlow("HandleRequestPruningPointUTXOSet", router,
|
||||||
[]appmessage.MessageCommand{appmessage.CmdRequestPruningPointHash}, isStopping, errChan,
|
[]appmessage.MessageCommand{appmessage.CmdRequestPruningPointUTXOSet,
|
||||||
|
appmessage.CmdRequestNextPruningPointUTXOSetChunk}, isStopping, errChan,
|
||||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||||
return blockrelay.HandlePruningPointHashRequests(m.context, incomingRoute, outgoingRoute)
|
return blockrelay.HandleRequestPruningPointUTXOSet(m.context, incomingRoute, outgoingRoute)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
m.registerFlow("HandlePruningPointAndItsAnticoneRequests", router,
|
||||||
|
[]appmessage.MessageCommand{appmessage.CmdRequestPruningPointAndItsAnticone}, isStopping, errChan,
|
||||||
|
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||||
|
return blockrelay.HandlePruningPointAndItsAnticoneRequests(m.context, incomingRoute, outgoingRoute, peer)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -226,6 +229,13 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping *
|
|||||||
return blockrelay.HandleIBDBlockLocator(m.context, incomingRoute, outgoingRoute, peer)
|
return blockrelay.HandleIBDBlockLocator(m.context, incomingRoute, outgoingRoute, peer)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
|
m.registerFlow("HandlePruningPointProofRequests", router,
|
||||||
|
[]appmessage.MessageCommand{appmessage.CmdRequestPruningPointProof}, isStopping, errChan,
|
||||||
|
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||||
|
return blockrelay.HandlePruningPointProofRequests(m.context, incomingRoute, outgoingRoute, peer)
|
||||||
|
},
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +292,7 @@ func (m *Manager) registerRejectsFlow(router *routerpkg.Router, isStopping *uint
|
|||||||
func (m *Manager) registerFlow(name string, router *routerpkg.Router, messageTypes []appmessage.MessageCommand, isStopping *uint32,
|
func (m *Manager) registerFlow(name string, router *routerpkg.Router, messageTypes []appmessage.MessageCommand, isStopping *uint32,
|
||||||
errChan chan error, initializeFunc flowInitializeFunc) *flow {
|
errChan chan error, initializeFunc flowInitializeFunc) *flow {
|
||||||
|
|
||||||
route, err := router.AddIncomingRoute(messageTypes)
|
route, err := router.AddIncomingRoute(name, messageTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -294,7 +304,7 @@ func (m *Manager) registerFlowWithCapacity(name string, capacity int, router *ro
|
|||||||
messageTypes []appmessage.MessageCommand, isStopping *uint32,
|
messageTypes []appmessage.MessageCommand, isStopping *uint32,
|
||||||
errChan chan error, initializeFunc flowInitializeFunc) *flow {
|
errChan chan error, initializeFunc flowInitializeFunc) *flow {
|
||||||
|
|
||||||
route, err := router.AddIncomingRouteWithCapacity(capacity, messageTypes)
|
route, err := router.AddIncomingRouteWithCapacity(name, capacity, messageTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -320,7 +330,7 @@ func (m *Manager) registerFlowForRoute(route *routerpkg.Route, name string, isSt
|
|||||||
func (m *Manager) registerOneTimeFlow(name string, router *routerpkg.Router, messageTypes []appmessage.MessageCommand,
|
func (m *Manager) registerOneTimeFlow(name string, router *routerpkg.Router, messageTypes []appmessage.MessageCommand,
|
||||||
isStopping *uint32, stopChan chan error, initializeFunc flowInitializeFunc) *flow {
|
isStopping *uint32, stopChan chan error, initializeFunc flowInitializeFunc) *flow {
|
||||||
|
|
||||||
route, err := router.AddIncomingRoute(messageTypes)
|
route, err := router.AddIncomingRoute(name, messageTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -346,12 +356,12 @@ func (m *Manager) registerOneTimeFlow(name string, router *routerpkg.Router, mes
|
|||||||
|
|
||||||
func registerHandshakeRoutes(router *routerpkg.Router) (
|
func registerHandshakeRoutes(router *routerpkg.Router) (
|
||||||
receiveVersionRoute *routerpkg.Route, sendVersionRoute *routerpkg.Route) {
|
receiveVersionRoute *routerpkg.Route, sendVersionRoute *routerpkg.Route) {
|
||||||
receiveVersionRoute, err := router.AddIncomingRoute([]appmessage.MessageCommand{appmessage.CmdVersion})
|
receiveVersionRoute, err := router.AddIncomingRoute("recieveVersion - incoming", []appmessage.MessageCommand{appmessage.CmdVersion})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendVersionRoute, err = router.AddIncomingRoute([]appmessage.MessageCommand{appmessage.CmdVerAck})
|
sendVersionRoute, err = router.AddIncomingRoute("sendVersion - incoming", []appmessage.MessageCommand{appmessage.CmdVerAck})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,11 @@ func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock, blockIns
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = m.notifyVirtualDaaScoreChanged()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = m.notifyVirtualSelectedParentChainChanged(blockInsertionResult)
|
err = m.notifyVirtualSelectedParentChainChanged(blockInsertionResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -153,6 +158,19 @@ func (m *Manager) notifyVirtualSelectedParentBlueScoreChanged() error {
|
|||||||
return m.context.NotificationManager.NotifyVirtualSelectedParentBlueScoreChanged(notification)
|
return m.context.NotificationManager.NotifyVirtualSelectedParentBlueScoreChanged(notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) notifyVirtualDaaScoreChanged() error {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualDaaScoreChanged")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
|
virtualDAAScore, err := m.context.Domain.Consensus().GetVirtualDAAScore()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := appmessage.NewVirtualDaaScoreChangedNotificationMessage(virtualDAAScore)
|
||||||
|
return m.context.NotificationManager.NotifyVirtualDaaScoreChanged(notification)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) notifyVirtualSelectedParentChainChanged(blockInsertionResult *externalapi.BlockInsertionResult) error {
|
func (m *Manager) notifyVirtualSelectedParentChainChanged(blockInsertionResult *externalapi.BlockInsertionResult) error {
|
||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualSelectedParentChainChanged")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualSelectedParentChainChanged")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ var handlers = map[appmessage.MessageCommand]handler{
|
|||||||
appmessage.CmdGetInfoRequestMessage: rpchandlers.HandleGetInfo,
|
appmessage.CmdGetInfoRequestMessage: rpchandlers.HandleGetInfo,
|
||||||
appmessage.CmdNotifyPruningPointUTXOSetOverrideRequestMessage: rpchandlers.HandleNotifyPruningPointUTXOSetOverrideRequest,
|
appmessage.CmdNotifyPruningPointUTXOSetOverrideRequestMessage: rpchandlers.HandleNotifyPruningPointUTXOSetOverrideRequest,
|
||||||
appmessage.CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage: rpchandlers.HandleStopNotifyingPruningPointUTXOSetOverrideRequest,
|
appmessage.CmdStopNotifyingPruningPointUTXOSetOverrideRequestMessage: rpchandlers.HandleStopNotifyingPruningPointUTXOSetOverrideRequest,
|
||||||
|
appmessage.CmdEstimateNetworkHashesPerSecondRequestMessage: rpchandlers.HandleEstimateNetworkHashesPerSecond,
|
||||||
|
appmessage.CmdNotifyVirtualDaaScoreChangedRequestMessage: rpchandlers.HandleNotifyVirtualDaaScoreChanged,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) {
|
func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) {
|
||||||
@@ -51,7 +53,7 @@ func (m *Manager) routerInitializer(router *router.Router, netConnection *netada
|
|||||||
for messageType := range handlers {
|
for messageType := range handlers {
|
||||||
messageTypes = append(messageTypes, messageType)
|
messageTypes = append(messageTypes, messageType)
|
||||||
}
|
}
|
||||||
incomingRoute, err := router.AddIncomingRoute(messageTypes)
|
incomingRoute, err := router.AddIncomingRoute("rpc router", messageTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package rpccontext
|
|||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage converts
|
// ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage converts
|
||||||
@@ -16,29 +15,9 @@ func (ctx *Context) ConvertVirtualSelectedParentChainChangesToChainChangedNotifi
|
|||||||
removedChainBlockHashes[i] = removed.String()
|
removedChainBlockHashes[i] = removed.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
addedChainBlocks := make([]*appmessage.ChainBlock, len(selectedParentChainChanges.Added))
|
addedChainBlocks := make([]string, len(selectedParentChainChanges.Added))
|
||||||
for i, added := range selectedParentChainChanges.Added {
|
for i, added := range selectedParentChainChanges.Added {
|
||||||
acceptanceData, err := ctx.Domain.Consensus().GetBlockAcceptanceData(added)
|
addedChainBlocks[i] = added.String()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
acceptedBlocks := make([]*appmessage.AcceptedBlock, len(acceptanceData))
|
|
||||||
for j, acceptedBlock := range acceptanceData {
|
|
||||||
acceptedTransactionIDs := make([]string, len(acceptedBlock.TransactionAcceptanceData))
|
|
||||||
for k, transaction := range acceptedBlock.TransactionAcceptanceData {
|
|
||||||
transactionID := consensushashing.TransactionID(transaction.Transaction)
|
|
||||||
acceptedTransactionIDs[k] = transactionID.String()
|
|
||||||
}
|
|
||||||
acceptedBlocks[j] = &appmessage.AcceptedBlock{
|
|
||||||
Hash: acceptedBlock.BlockHash.String(),
|
|
||||||
AcceptedTransactionIDs: acceptedTransactionIDs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addedChainBlocks[i] = &appmessage.ChainBlock{
|
|
||||||
Hash: added.String(),
|
|
||||||
AcceptedBlocks: acceptedBlocks,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return appmessage.NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes, addedChainBlocks), nil
|
return appmessage.NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes, addedChainBlocks), nil
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type NotificationListener struct {
|
|||||||
propagateFinalityConflictResolvedNotifications bool
|
propagateFinalityConflictResolvedNotifications bool
|
||||||
propagateUTXOsChangedNotifications bool
|
propagateUTXOsChangedNotifications bool
|
||||||
propagateVirtualSelectedParentBlueScoreChangedNotifications bool
|
propagateVirtualSelectedParentBlueScoreChangedNotifications bool
|
||||||
|
propagateVirtualDaaScoreChangedNotifications bool
|
||||||
propagatePruningPointUTXOSetOverrideNotifications bool
|
propagatePruningPointUTXOSetOverrideNotifications bool
|
||||||
|
|
||||||
propagateUTXOsChangedNotificationAddresses map[utxoindex.ScriptPublicKeyString]*UTXOsChangedNotificationAddress
|
propagateUTXOsChangedNotificationAddresses map[utxoindex.ScriptPublicKeyString]*UTXOsChangedNotificationAddress
|
||||||
@@ -181,6 +182,25 @@ func (nm *NotificationManager) NotifyVirtualSelectedParentBlueScoreChanged(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyVirtualDaaScoreChanged notifies the notification manager that the DAG's
|
||||||
|
// virtual DAA score has changed
|
||||||
|
func (nm *NotificationManager) NotifyVirtualDaaScoreChanged(
|
||||||
|
notification *appmessage.VirtualDaaScoreChangedNotificationMessage) error {
|
||||||
|
|
||||||
|
nm.RLock()
|
||||||
|
defer nm.RUnlock()
|
||||||
|
|
||||||
|
for router, listener := range nm.listeners {
|
||||||
|
if listener.propagateVirtualDaaScoreChangedNotifications {
|
||||||
|
err := router.OutgoingRoute().Enqueue(notification)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyPruningPointUTXOSetOverride notifies the notification manager that the UTXO index
|
// NotifyPruningPointUTXOSetOverride notifies the notification manager that the UTXO index
|
||||||
// reset due to pruning point change via IBD.
|
// reset due to pruning point change via IBD.
|
||||||
func (nm *NotificationManager) NotifyPruningPointUTXOSetOverride() error {
|
func (nm *NotificationManager) NotifyPruningPointUTXOSetOverride() error {
|
||||||
@@ -308,6 +328,12 @@ func (nl *NotificationListener) PropagateVirtualSelectedParentBlueScoreChangedNo
|
|||||||
nl.propagateVirtualSelectedParentBlueScoreChangedNotifications = true
|
nl.propagateVirtualSelectedParentBlueScoreChangedNotifications = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PropagateVirtualDaaScoreChangedNotifications instructs the listener to send
|
||||||
|
// virtual DAA score notifications to the remote listener
|
||||||
|
func (nl *NotificationListener) PropagateVirtualDaaScoreChangedNotifications() {
|
||||||
|
nl.propagateVirtualDaaScoreChangedNotifications = true
|
||||||
|
}
|
||||||
|
|
||||||
// PropagatePruningPointUTXOSetOverrideNotifications instructs the listener to send pruning point UTXO set override notifications
|
// PropagatePruningPointUTXOSetOverrideNotifications instructs the listener to send pruning point UTXO set override notifications
|
||||||
// to the remote listener.
|
// to the remote listener.
|
||||||
func (nl *NotificationListener) PropagatePruningPointUTXOSetOverrideNotifications() {
|
func (nl *NotificationListener) PropagatePruningPointUTXOSetOverrideNotifications() {
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package rpccontext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
difficultyPackage "github.com/kaspanet/kaspad/util/difficulty"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
difficultyPackage "github.com/kaspanet/kaspad/util/difficulty"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
@@ -62,12 +62,15 @@ func (ctx *Context) PopulateBlockWithVerboseData(block *appmessage.RPCBlock, dom
|
|||||||
}
|
}
|
||||||
|
|
||||||
block.VerboseData = &appmessage.RPCBlockVerboseData{
|
block.VerboseData = &appmessage.RPCBlockVerboseData{
|
||||||
Hash: blockHash.String(),
|
Hash: blockHash.String(),
|
||||||
Difficulty: ctx.GetDifficultyRatio(domainBlockHeader.Bits(), ctx.Config.ActiveNetParams),
|
Difficulty: ctx.GetDifficultyRatio(domainBlockHeader.Bits(), ctx.Config.ActiveNetParams),
|
||||||
ChildrenHashes: hashes.ToStrings(childrenHashes),
|
ChildrenHashes: hashes.ToStrings(childrenHashes),
|
||||||
SelectedParentHash: selectedParentHash.String(),
|
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
|
||||||
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
|
BlueScore: blockInfo.BlueScore,
|
||||||
BlueScore: blockInfo.BlueScore,
|
}
|
||||||
|
// selectedParentHash will be nil in the genesis block
|
||||||
|
if selectedParentHash != nil {
|
||||||
|
block.VerboseData.SelectedParentHash = selectedParentHash.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
|
if blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
|
||||||
@@ -76,7 +79,7 @@ func (ctx *Context) PopulateBlockWithVerboseData(block *appmessage.RPCBlock, dom
|
|||||||
|
|
||||||
// Get the block if we didn't receive it previously
|
// Get the block if we didn't receive it previously
|
||||||
if domainBlock == nil {
|
if domainBlock == nil {
|
||||||
domainBlock, err = ctx.Domain.Consensus().GetBlock(blockHash)
|
domainBlock, err = ctx.Domain.Consensus().GetBlockEvenIfHeaderOnly(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -110,10 +113,11 @@ func (ctx *Context) PopulateTransactionWithVerboseData(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.Domain.Consensus().PopulateMass(domainTransaction)
|
||||||
transaction.VerboseData = &appmessage.RPCTransactionVerboseData{
|
transaction.VerboseData = &appmessage.RPCTransactionVerboseData{
|
||||||
TransactionID: consensushashing.TransactionID(domainTransaction).String(),
|
TransactionID: consensushashing.TransactionID(domainTransaction).String(),
|
||||||
Hash: consensushashing.TransactionHash(domainTransaction).String(),
|
Hash: consensushashing.TransactionHash(domainTransaction).String(),
|
||||||
Size: estimatedsize.TransactionEstimatedSerializedSize(domainTransaction),
|
Mass: domainTransaction.Mass,
|
||||||
}
|
}
|
||||||
if domainBlockHeader != nil {
|
if domainBlockHeader != nil {
|
||||||
transaction.VerboseData.BlockHash = consensushashing.HeaderHash(domainBlockHeader).String()
|
transaction.VerboseData.BlockHash = consensushashing.HeaderHash(domainBlockHeader).String()
|
||||||
|
|||||||
@@ -12,8 +12,12 @@ func HandleBan(context *rpccontext.Context, _ *router.Router, request appmessage
|
|||||||
banRequest := request.(*appmessage.BanRequestMessage)
|
banRequest := request.(*appmessage.BanRequestMessage)
|
||||||
ip := net.ParseIP(banRequest.IP)
|
ip := net.ParseIP(banRequest.IP)
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
|
hint := ""
|
||||||
|
if banRequest.IP[0] == '[' {
|
||||||
|
hint = " (try to remove “[” and “]” symbols)"
|
||||||
|
}
|
||||||
errorMessage := &appmessage.BanResponseMessage{}
|
errorMessage := &appmessage.BanResponseMessage{}
|
||||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse IP %s", banRequest.IP)
|
errorMessage.Error = appmessage.RPCErrorf("Could not parse IP%s: %s", hint, banRequest.IP)
|
||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
39
app/rpc/rpchandlers/estimate_network_hashes_per_second.go
Normal file
39
app/rpc/rpchandlers/estimate_network_hashes_per_second.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package rpchandlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleEstimateNetworkHashesPerSecond handles the respectively named RPC command
|
||||||
|
func HandleEstimateNetworkHashesPerSecond(
|
||||||
|
context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||||
|
|
||||||
|
estimateNetworkHashesPerSecondRequest := request.(*appmessage.EstimateNetworkHashesPerSecondRequestMessage)
|
||||||
|
|
||||||
|
windowSize := int(estimateNetworkHashesPerSecondRequest.WindowSize)
|
||||||
|
startHash := model.VirtualBlockHash
|
||||||
|
if estimateNetworkHashesPerSecondRequest.StartHash != "" {
|
||||||
|
var err error
|
||||||
|
startHash, err = externalapi.NewDomainHashFromString(estimateNetworkHashesPerSecondRequest.StartHash)
|
||||||
|
if err != nil {
|
||||||
|
response := &appmessage.EstimateNetworkHashesPerSecondResponseMessage{}
|
||||||
|
response.Error = appmessage.RPCErrorf("StartHash '%s' is not a valid block hash",
|
||||||
|
estimateNetworkHashesPerSecondRequest.StartHash)
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
networkHashesPerSecond, err := context.Domain.Consensus().EstimateNetworkHashesPerSecond(startHash, windowSize)
|
||||||
|
if err != nil {
|
||||||
|
response := &appmessage.EstimateNetworkHashesPerSecondResponseMessage{}
|
||||||
|
response.Error = appmessage.RPCErrorf("could not resolve network hashes per "+
|
||||||
|
"second for startHash %s and window size %d: %s", startHash, windowSize, err)
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return appmessage.NewEstimateNetworkHashesPerSecondResponseMessage(networkHashesPerSecond), nil
|
||||||
|
}
|
||||||
@@ -20,18 +20,22 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme
|
|||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header, err := context.Domain.Consensus().GetBlockHeader(hash)
|
block, err := context.Domain.Consensus().GetBlockEvenIfHeaderOnly(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||||
errorMessage.Error = appmessage.RPCErrorf("Block %s not found", hash)
|
errorMessage.Error = appmessage.RPCErrorf("Block %s not found", hash)
|
||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
block := &externalapi.DomainBlock{Header: header}
|
|
||||||
|
|
||||||
response := appmessage.NewGetBlockResponseMessage()
|
response := appmessage.NewGetBlockResponseMessage()
|
||||||
response.Block = appmessage.DomainBlockToRPCBlock(block)
|
|
||||||
|
|
||||||
err = context.PopulateBlockWithVerboseData(response.Block, header, nil, getBlockRequest.IncludeTransactionVerboseData)
|
if getBlockRequest.IncludeTransactions {
|
||||||
|
response.Block = appmessage.DomainBlockToRPCBlock(block)
|
||||||
|
} else {
|
||||||
|
response.Block = appmessage.DomainBlockToRPCBlock(&externalapi.DomainBlock{Header: block.Header})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = context.PopulateBlockWithVerboseData(response.Block, block.Header, block, getBlockRequest.IncludeTransactions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, rpccontext.ErrBuildBlockVerboseDataInvalidBlock) {
|
if errors.Is(err, rpccontext.ErrBuildBlockVerboseDataInvalidBlock) {
|
||||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ func HandleGetBlockDAGInfo(context *rpccontext.Context, _ *router.Router, _ appm
|
|||||||
response.VirtualParentHashes = hashes.ToStrings(virtualInfo.ParentHashes)
|
response.VirtualParentHashes = hashes.ToStrings(virtualInfo.ParentHashes)
|
||||||
response.Difficulty = context.GetDifficultyRatio(virtualInfo.Bits, context.Config.ActiveNetParams)
|
response.Difficulty = context.GetDifficultyRatio(virtualInfo.Bits, context.Config.ActiveNetParams)
|
||||||
response.PastMedianTime = virtualInfo.PastMedianTime
|
response.PastMedianTime = virtualInfo.PastMedianTime
|
||||||
|
response.VirtualDAAScore = virtualInfo.DAAScore
|
||||||
|
|
||||||
pruningPoint, err := context.Domain.Consensus().PruningPoint()
|
pruningPoint, err := context.Domain.Consensus().PruningPoint()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -8,21 +8,15 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// maxBlocksInGetBlocksResponse is the max amount of blocks that are
|
|
||||||
// allowed in a GetBlocksResult.
|
|
||||||
maxBlocksInGetBlocksResponse = 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandleGetBlocks handles the respectively named RPC command
|
// HandleGetBlocks handles the respectively named RPC command
|
||||||
func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||||
getBlocksRequest := request.(*appmessage.GetBlocksRequestMessage)
|
getBlocksRequest := request.(*appmessage.GetBlocksRequestMessage)
|
||||||
|
|
||||||
// Validate that user didn't set IncludeTransactionVerboseData without setting IncludeBlocks
|
// Validate that user didn't set IncludeTransactions without setting IncludeBlocks
|
||||||
if !getBlocksRequest.IncludeBlocks && getBlocksRequest.IncludeTransactionVerboseData {
|
if !getBlocksRequest.IncludeBlocks && getBlocksRequest.IncludeTransactions {
|
||||||
return &appmessage.GetBlocksResponseMessage{
|
return &appmessage.GetBlocksResponseMessage{
|
||||||
Error: appmessage.RPCErrorf(
|
Error: appmessage.RPCErrorf(
|
||||||
"If includeTransactionVerboseData is set, then includeBlockVerboseData must be set as well"),
|
"If includeTransactions is set, then includeBlockVerboseData must be set as well"),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +49,11 @@ func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appm
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
blockHashes, highHash, err := context.Domain.Consensus().GetHashesBetween(lowHash, virtualSelectedParent, maxBlocksInGetBlocksResponse)
|
|
||||||
|
// We use +1 because lowHash is also returned
|
||||||
|
// maxBlocks MUST be >= MergeSetSizeLimit + 1
|
||||||
|
maxBlocks := context.Config.NetParams().MergeSetSizeLimit + 1
|
||||||
|
blockHashes, highHash, err := context.Domain.Consensus().GetHashesBetween(lowHash, virtualSelectedParent, maxBlocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -74,29 +72,28 @@ func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appm
|
|||||||
blockHashes = append(blockHashes, virtualSelectedParentAnticone...)
|
blockHashes = append(blockHashes, virtualSelectedParentAnticone...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both GetHashesBetween and Anticone might return more then the allowed number of blocks, so
|
|
||||||
// trim any extra blocks.
|
|
||||||
if len(blockHashes) > maxBlocksInGetBlocksResponse {
|
|
||||||
blockHashes = blockHashes[:maxBlocksInGetBlocksResponse]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare the response
|
// Prepare the response
|
||||||
response := appmessage.NewGetBlocksResponseMessage()
|
response := appmessage.NewGetBlocksResponseMessage()
|
||||||
response.BlockHashes = hashes.ToStrings(blockHashes)
|
response.BlockHashes = hashes.ToStrings(blockHashes)
|
||||||
if getBlocksRequest.IncludeBlocks {
|
if getBlocksRequest.IncludeBlocks {
|
||||||
blocks := make([]*appmessage.RPCBlock, len(blockHashes))
|
rpcBlocks := make([]*appmessage.RPCBlock, len(blockHashes))
|
||||||
for i, blockHash := range blockHashes {
|
for i, blockHash := range blockHashes {
|
||||||
blockHeader, err := context.Domain.Consensus().GetBlockHeader(blockHash)
|
block, err := context.Domain.Consensus().GetBlockEvenIfHeaderOnly(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
block := &externalapi.DomainBlock{Header: blockHeader}
|
|
||||||
blocks[i] = appmessage.DomainBlockToRPCBlock(block)
|
if getBlocksRequest.IncludeTransactions {
|
||||||
err = context.PopulateBlockWithVerboseData(blocks[i], blockHeader, nil, getBlocksRequest.IncludeTransactionVerboseData)
|
rpcBlocks[i] = appmessage.DomainBlockToRPCBlock(block)
|
||||||
|
} else {
|
||||||
|
rpcBlocks[i] = appmessage.DomainBlockToRPCBlock(&externalapi.DomainBlock{Header: block.Header})
|
||||||
|
}
|
||||||
|
err = context.PopulateBlockWithVerboseData(rpcBlocks[i], block.Header, nil, getBlocksRequest.IncludeTransactions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
response.Blocks = rpcBlocks
|
||||||
}
|
}
|
||||||
|
|
||||||
return response, nil
|
return response, nil
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
|
||||||
"github.com/kaspanet/kaspad/domain/miningmanager"
|
"github.com/kaspanet/kaspad/domain/miningmanager"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
)
|
)
|
||||||
@@ -24,22 +23,38 @@ type fakeDomain struct {
|
|||||||
testapi.TestConsensus
|
testapi.TestConsensus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d fakeDomain) DeleteStagingConsensus() error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fakeDomain) StagingConsensus() externalapi.Consensus {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fakeDomain) InitStagingConsensus() error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fakeDomain) CommitStagingConsensus() error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
func (d fakeDomain) Consensus() externalapi.Consensus { return d }
|
func (d fakeDomain) Consensus() externalapi.Consensus { return d }
|
||||||
func (d fakeDomain) MiningManager() miningmanager.MiningManager { return nil }
|
func (d fakeDomain) MiningManager() miningmanager.MiningManager { return nil }
|
||||||
|
|
||||||
func TestHandleGetBlocks(t *testing.T) {
|
func TestHandleGetBlocks(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
stagingArea := model.NewStagingArea()
|
stagingArea := model.NewStagingArea()
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestHandleGetBlocks")
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestHandleGetBlocks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error setting up consensus: %+v", err)
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
}
|
}
|
||||||
defer teardown(false)
|
defer teardown(false)
|
||||||
|
|
||||||
fakeContext := rpccontext.Context{
|
fakeContext := rpccontext.Context{
|
||||||
Config: &config.Config{Flags: &config.Flags{NetworkFlags: config.NetworkFlags{ActiveNetParams: params}}},
|
Config: &config.Config{Flags: &config.Flags{NetworkFlags: config.NetworkFlags{ActiveNetParams: &consensusConfig.Params}}},
|
||||||
Domain: fakeDomain{tc},
|
Domain: fakeDomain{tc},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +96,7 @@ func TestHandleGetBlocks(t *testing.T) {
|
|||||||
// \ | /
|
// \ | /
|
||||||
// etc.
|
// etc.
|
||||||
expectedOrder := make([]*externalapi.DomainHash, 0, 40)
|
expectedOrder := make([]*externalapi.DomainHash, 0, 40)
|
||||||
mergingBlock := params.GenesisHash
|
mergingBlock := consensusConfig.GenesisHash
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
splitBlocks := make([]*externalapi.DomainHash, 0, 3)
|
splitBlocks := make([]*externalapi.DomainHash, 0, 3)
|
||||||
for j := 0; j < 3; j++ {
|
for j := 0; j < 3; j++ {
|
||||||
@@ -134,13 +149,13 @@ func TestHandleGetBlocks(t *testing.T) {
|
|||||||
virtualSelectedParent, actualBlocks.BlockHashes)
|
virtualSelectedParent, actualBlocks.BlockHashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedOrder = append([]*externalapi.DomainHash{params.GenesisHash}, expectedOrder...)
|
expectedOrder = append([]*externalapi.DomainHash{consensusConfig.GenesisHash}, expectedOrder...)
|
||||||
actualOrder := getBlocks(nil)
|
actualOrder := getBlocks(nil)
|
||||||
if !reflect.DeepEqual(actualOrder.BlockHashes, hashes.ToStrings(expectedOrder)) {
|
if !reflect.DeepEqual(actualOrder.BlockHashes, hashes.ToStrings(expectedOrder)) {
|
||||||
t.Fatalf("TestHandleGetBlocks \nexpected: %v \nactual:\n%v", expectedOrder, actualOrder.BlockHashes)
|
t.Fatalf("TestHandleGetBlocks \nexpected: %v \nactual:\n%v", expectedOrder, actualOrder.BlockHashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
requestAllExplictly := getBlocks(params.GenesisHash)
|
requestAllExplictly := getBlocks(consensusConfig.GenesisHash)
|
||||||
if !reflect.DeepEqual(requestAllExplictly.BlockHashes, hashes.ToStrings(expectedOrder)) {
|
if !reflect.DeepEqual(requestAllExplictly.BlockHashes, hashes.ToStrings(expectedOrder)) {
|
||||||
t.Fatalf("TestHandleGetBlocks \nexpected: \n%v\n. actual:\n%v", expectedOrder, requestAllExplictly.BlockHashes)
|
t.Fatalf("TestHandleGetBlocks \nexpected: \n%v\n. actual:\n%v", expectedOrder, requestAllExplictly.BlockHashes)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
"github.com/kaspanet/kaspad/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleGetInfo handles the respectively named RPC command
|
// HandleGetInfo handles the respectively named RPC command
|
||||||
@@ -11,6 +12,7 @@ func HandleGetInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.M
|
|||||||
response := appmessage.NewGetInfoResponseMessage(
|
response := appmessage.NewGetInfoResponseMessage(
|
||||||
context.NetAdapter.ID().String(),
|
context.NetAdapter.ID().String(),
|
||||||
uint64(context.Domain.MiningManager().TransactionCount()),
|
uint64(context.Domain.MiningManager().TransactionCount()),
|
||||||
|
version.Version(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return response, nil
|
return response, nil
|
||||||
|
|||||||
@@ -8,9 +8,14 @@ import (
|
|||||||
|
|
||||||
// HandleGetVirtualSelectedParentBlueScore handles the respectively named RPC command
|
// HandleGetVirtualSelectedParentBlueScore handles the respectively named RPC command
|
||||||
func HandleGetVirtualSelectedParentBlueScore(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
func HandleGetVirtualSelectedParentBlueScore(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||||
virtualInfo, err := context.Domain.Consensus().GetVirtualInfo()
|
c := context.Domain.Consensus()
|
||||||
|
selectedParent, err := c.GetVirtualSelectedParent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return appmessage.NewGetVirtualSelectedParentBlueScoreResponseMessage(virtualInfo.BlueScore), nil
|
blockInfo, err := c.GetBlockInfo(selectedParent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return appmessage.NewGetVirtualSelectedParentBlueScoreResponseMessage(blockInfo.BlueScore), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ func HandleGetVirtualSelectedParentChainFromBlock(context *rpccontext.Context, _
|
|||||||
}
|
}
|
||||||
|
|
||||||
response := appmessage.NewGetVirtualSelectedParentChainFromBlockResponseMessage(
|
response := appmessage.NewGetVirtualSelectedParentChainFromBlockResponseMessage(
|
||||||
chainChangedNotification.RemovedChainBlockHashes, chainChangedNotification.AddedChainBlocks)
|
chainChangedNotification.RemovedChainBlockHashes, chainChangedNotification.AddedChainBlockHashes)
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|||||||
19
app/rpc/rpchandlers/notify_virtual_daa_score_changed.go
Normal file
19
app/rpc/rpchandlers/notify_virtual_daa_score_changed.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package rpchandlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleNotifyVirtualDaaScoreChanged handles the respectively named RPC command
|
||||||
|
func HandleNotifyVirtualDaaScoreChanged(context *rpccontext.Context, router *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||||
|
listener, err := context.NotificationManager.Listener(router)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
listener.PropagateVirtualDaaScoreChangedNotifications()
|
||||||
|
|
||||||
|
response := appmessage.NewNotifyVirtualDaaScoreChangedResponseMessage()
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ func HandleSubmitTransaction(context *rpccontext.Context, _ *router.Router, requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
transactionID := consensushashing.TransactionID(domainTransaction)
|
transactionID := consensushashing.TransactionID(domainTransaction)
|
||||||
err = context.ProtocolManager.AddTransaction(domainTransaction)
|
err = context.ProtocolManager.AddTransaction(domainTransaction, submitTransactionRequest.AllowOrphan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.As(err, &mempool.RuleError{}) {
|
if !errors.As(err, &mempool.RuleError{}) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -12,8 +12,12 @@ func HandleUnban(context *rpccontext.Context, _ *router.Router, request appmessa
|
|||||||
unbanRequest := request.(*appmessage.UnbanRequestMessage)
|
unbanRequest := request.(*appmessage.UnbanRequestMessage)
|
||||||
ip := net.ParseIP(unbanRequest.IP)
|
ip := net.ParseIP(unbanRequest.IP)
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
|
hint := ""
|
||||||
|
if unbanRequest.IP[0] == '[' {
|
||||||
|
hint = " (try to remove “[” and “]” symbols)"
|
||||||
|
}
|
||||||
errorMessage := &appmessage.UnbanResponseMessage{}
|
errorMessage := &appmessage.UnbanResponseMessage{}
|
||||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse IP %s", unbanRequest.IP)
|
errorMessage.Error = appmessage.RPCErrorf("Could not parse IP%s: %s", hint, unbanRequest.IP)
|
||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
err := context.AddressManager.Unban(appmessage.NewNetAddressIPPort(ip, 0))
|
err := context.AddressManager.Unban(appmessage.NewNetAddressIPPort(ip, 0))
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ go build $FLAGS -o kaspad .
|
|||||||
|
|
||||||
if [ -n "${NO_PARALLEL}" ]
|
if [ -n "${NO_PARALLEL}" ]
|
||||||
then
|
then
|
||||||
go test -parallel=1 $FLAGS ./...
|
go test -timeout 20m -parallel=1 $FLAGS ./...
|
||||||
else
|
else
|
||||||
go test $FLAGS ./...
|
go test -timeout 20m $FLAGS ./...
|
||||||
fi
|
fi
|
||||||
112
changelog.txt
112
changelog.txt
@@ -1,11 +1,107 @@
|
|||||||
|
Kaspad v0.11.2 - 2021-11-11
|
||||||
|
===========================
|
||||||
|
Bug fixes:
|
||||||
|
* Enlarge p2p max message size to 1gb
|
||||||
|
* Fix UTXO chunks logic
|
||||||
|
* Increase tests timeout to 20 minutes
|
||||||
|
|
||||||
|
Kaspad v0.11.1 - 2021-11-09
|
||||||
|
===========================
|
||||||
|
Non-breaking changes:
|
||||||
|
* Cache the miner state
|
||||||
|
|
||||||
|
Kaspad v0.10.2 - 2021-05-18
|
||||||
|
===========================
|
||||||
|
Non-breaking changes:
|
||||||
|
* Fix getBlock and getBlocks RPC commands to return blocks and transactions properly (#1716)
|
||||||
|
* serializeAddress should always serialize as IPv6, since it assumes the IP size is 16 bytes (#1720)
|
||||||
|
* Add VirtualDaaScore to GetBlockDagInfo (#1719)
|
||||||
|
* Fix calcTxSequenceLockFromReferencedUTXOEntries for loop break condition (#1723)
|
||||||
|
* Fix overflow when checking coinbase maturity and don't ban peers that send transactions with immature spend (#1722)
|
||||||
|
|
||||||
|
Kaspad v0.10.1 - 2021-05-11
|
||||||
|
===========================
|
||||||
|
* Calculate virtual's acceptance data and multiset after importing a new pruning point (#1700)
|
||||||
|
|
||||||
|
Kaspad v0.10.0 - 2021-04-26
|
||||||
|
===========================
|
||||||
|
Major changes include:
|
||||||
|
* Implementing a signature hashing scheme similar to BIP-143
|
||||||
|
* Replacing HASH160 with BLAKE2B
|
||||||
|
* Replacing ECMH with MuHash
|
||||||
|
* Removing RIPEMD160 and SHA1 from the codebase entirely
|
||||||
|
* Making P2PKH transactions non-standard
|
||||||
|
* Vastly enhancing the CLI wallet
|
||||||
|
* Restructuring kaspad's app/home directory
|
||||||
|
* Modifying block and transaction types in the RPC to be easier to consume clientside
|
||||||
|
|
||||||
|
A partial list of the more-important commits is as follows:
|
||||||
|
* Fix data race in GetBlockChildren (#1579)
|
||||||
|
* Remove payload hash (#1583)
|
||||||
|
* Add the mempool size to getInfo RPC command (#1584)
|
||||||
|
* Change the difficulty to be calculated based on the same block instead of its selected parent (#1591)
|
||||||
|
* Adjust the difficulty in the first difficultyAdjustmentWindowSize blocks (#1592)
|
||||||
|
* Adding DAA score (#1596)
|
||||||
|
* Use DAA score where needed (#1602)
|
||||||
|
* Remove the Services field from NetAddress. (#1610)
|
||||||
|
* Fix getBlocks to not add the anticone when some blocks were filtered by GetHashesBetween (#1611)
|
||||||
|
* Restructure the default ~/.kaspad directory layout (#1613)
|
||||||
|
* Replace the HomeDir flag with a AppDir flag (#1615)
|
||||||
|
* Implement BIP-143-like sighash (#1598)
|
||||||
|
* Change --datadir to --appdir and remove symmetrical connection in stability tests (#1617)
|
||||||
|
* Use BLAKE2B instead of HASH160, and get rid of any usage of RIPEMD160 and SHA1 (#1618)
|
||||||
|
* Replace ECMH with Muhash (#1624)
|
||||||
|
* Add support for multiple staging areas (#1633)
|
||||||
|
* Make sure the ghostdagDataStore cache is at least DifficultyAdjustmentBlockWindow sized (#1635)
|
||||||
|
* Resolve each block status in it's own staging area (#1634)
|
||||||
|
* Add mass limit to mempool (#1627)
|
||||||
|
* In RPC, use RPCTransactions and RPCBlocks instead of TransactionMessages and BlockMessages (#1609)
|
||||||
|
* Use go-secp256k1 v0.0.5 (#1640)
|
||||||
|
* Add a show-address subcommand to kaspawallet (#1653)
|
||||||
|
* Replace p2pkh with p2pk (#1650)
|
||||||
|
* Implement importing private keys into the wallet (#1655)
|
||||||
|
* Add dump unencrypted data sub command to the wallet (#1661)
|
||||||
|
* Add ECDSA support (#1657)
|
||||||
|
* Add OpCheckMultiSigECDSA (#1663)
|
||||||
|
* Add ECDSA support to the wallet (#1664)
|
||||||
|
* Make moving the pruning point faster (#1660)
|
||||||
|
* Implement new mechanism for updating UTXO Diffs (#1671)
|
||||||
|
|
||||||
|
Kaspad v0.9.2 - 2021-03-31
|
||||||
|
===========================
|
||||||
|
* Increase the route capacity of InvTransaction messages. (#1603) (#1637)
|
||||||
|
|
||||||
|
Kaspad v0.9.1 - 2021-03-14
|
||||||
|
===========================
|
||||||
|
* Testnet network reset
|
||||||
|
|
||||||
|
Kaspad v0.9.0 - 2021-03-04
|
||||||
|
===========================
|
||||||
|
|
||||||
|
* Merge big subdags in pick virtual parents (#1574)
|
||||||
|
* Write in the reject message the tx rejection reason (#1573)
|
||||||
|
* Add nil checks for protowire (#1570)
|
||||||
|
* Increase getBlocks limit to 1000 (#1572)
|
||||||
|
* Return RPC error if getBlock's lowHash doesn't exist (#1569)
|
||||||
|
* Add default dns-seeder to testnet (#1568)
|
||||||
|
* Fix utxoindex deserialization (#1566)
|
||||||
|
* Add pruning point hash to GetBlockDagInfo response (#1565)
|
||||||
|
* Use EmitUnpopulated so that kaspactl prints all fields, even the default ones (#1561)
|
||||||
|
* Stop logging an error whenever an RPC/P2P connection is canceled (#1562)
|
||||||
|
* Cleanup the logger and make it asynchronous (#1524)
|
||||||
|
* Close all iterators (#1542)
|
||||||
|
* Add childrenHashes to GetBlock/s RPC commands (#1560)
|
||||||
|
* Add ScriptPublicKey.Version to RPC (#1559)
|
||||||
|
* Fix the target block rate to create less bursty mining (#1554)
|
||||||
|
|
||||||
Kaspad v0.8.10 - 2021-02-25
|
Kaspad v0.8.10 - 2021-02-25
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
[*] Fix bug where invalid mempool transactions were not removed (#1551)
|
* Fix bug where invalid mempool transactions were not removed (#1551)
|
||||||
[*] Add RPC reconnection to the miner (#1552)
|
* Add RPC reconnection to the miner (#1552)
|
||||||
[*] Remove virtual diff parents - only selectedTip is virtualDiffParent now (#1550)
|
* Remove virtual diff parents - only selectedTip is virtualDiffParent now (#1550)
|
||||||
[*] Fix UTXO index (#1548)
|
* Fix UTXO index (#1548)
|
||||||
[*] Prevent fast failing (#1545)
|
* Prevent fast failing (#1545)
|
||||||
[*] Increase the sleep time in kaspaminer when the node is not synced (#1544)
|
* Increase the sleep time in kaspaminer when the node is not synced (#1544)
|
||||||
[*] Disallow header only blocks on RPC, relay and when requesting IBD full blocks (#1537)
|
* Disallow header only blocks on RPC, relay and when requesting IBD full blocks (#1537)
|
||||||
[*] Make templateManager hold a DomainBlock and isSynced bool instead of a GetBlockTemplateResponseMessage (#1538)
|
* Make templateManager hold a DomainBlock and isSynced bool instead of a GetBlockTemplateResponseMessage (#1538)
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ func setField(commandValue reflect.Value, parameterValue reflect.Value, paramete
|
|||||||
}
|
}
|
||||||
|
|
||||||
func stringToValue(parameterDesc *parameterDescription, valueStr string) (reflect.Value, error) {
|
func stringToValue(parameterDesc *parameterDescription, valueStr string) (reflect.Value, error) {
|
||||||
|
if valueStr == "-" {
|
||||||
|
return reflect.Zero(parameterDesc.typeof), nil
|
||||||
|
}
|
||||||
|
|
||||||
var value interface{}
|
var value interface{}
|
||||||
var err error
|
var err error
|
||||||
switch parameterDesc.typeof.Kind() {
|
switch parameterDesc.typeof.Kind() {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ var commandTypes = []reflect.Type{
|
|||||||
reflect.TypeOf(protowire.KaspadMessage_GetVirtualSelectedParentBlueScoreRequest{}),
|
reflect.TypeOf(protowire.KaspadMessage_GetVirtualSelectedParentBlueScoreRequest{}),
|
||||||
reflect.TypeOf(protowire.KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest{}),
|
reflect.TypeOf(protowire.KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest{}),
|
||||||
reflect.TypeOf(protowire.KaspadMessage_ResolveFinalityConflictRequest{}),
|
reflect.TypeOf(protowire.KaspadMessage_ResolveFinalityConflictRequest{}),
|
||||||
|
reflect.TypeOf(protowire.KaspadMessage_EstimateNetworkHashesPerSecondRequest{}),
|
||||||
|
|
||||||
reflect.TypeOf(protowire.KaspadMessage_GetBlockTemplateRequest{}),
|
reflect.TypeOf(protowire.KaspadMessage_GetBlockTemplateRequest{}),
|
||||||
reflect.TypeOf(protowire.KaspadMessage_SubmitBlockRequest{}),
|
reflect.TypeOf(protowire.KaspadMessage_SubmitBlockRequest{}),
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ func parseConfig() (*configFlags, error) {
|
|||||||
}
|
}
|
||||||
parser := flags.NewParser(cfg, flags.HelpFlag)
|
parser := flags.NewParser(cfg, flags.HelpFlag)
|
||||||
parser.Usage = "kaspactl [OPTIONS] [COMMAND] [COMMAND PARAMETERS].\n\nCommand can be supplied only if --json is not used." +
|
parser.Usage = "kaspactl [OPTIONS] [COMMAND] [COMMAND PARAMETERS].\n\nCommand can be supplied only if --json is not used." +
|
||||||
"\n\nUse `kaspactl --list-commands` to get a list of all commands and their parameters"
|
"\n\nUse `kaspactl --list-commands` to get a list of all commands and their parameters." +
|
||||||
|
"\nFor optional parameters- use '-' without quotes to not pass the parameter.\n"
|
||||||
remainingArgs, err := parser.Parse()
|
remainingArgs, err := parser.Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/kaspanet/kaspad/version"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -33,6 +34,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer client.Disconnect()
|
defer client.Disconnect()
|
||||||
|
|
||||||
|
kaspadMessage, err := client.Post(&protowire.KaspadMessage{Payload: &protowire.KaspadMessage_GetInfoRequest{GetInfoRequest: &protowire.GetInfoRequestMessage{}}})
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(fmt.Sprintf("Cannot post GetInfo message: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
localVersion := version.Version()
|
||||||
|
remoteVersion := kaspadMessage.GetGetInfoResponse().ServerVersion
|
||||||
|
|
||||||
|
if localVersion != remoteVersion {
|
||||||
|
printErrorAndExit(fmt.Sprintf("Server version mismatch, expect: %s, got: %s", localVersion, remoteVersion))
|
||||||
|
}
|
||||||
|
|
||||||
responseChan := make(chan string)
|
responseChan := make(chan string)
|
||||||
|
|
||||||
if cfg.RequestJSON != "" {
|
if cfg.RequestJSON != "" {
|
||||||
|
|||||||
@@ -6,17 +6,12 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspaminer/templatemanager"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspaminer/templatemanager"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -147,20 +142,20 @@ func mineNextBlock(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
|||||||
// In the rare case where the nonce space is exhausted for a specific
|
// In the rare case where the nonce space is exhausted for a specific
|
||||||
// block, it'll keep looping the nonce until a new block template
|
// block, it'll keep looping the nonce until a new block template
|
||||||
// is discovered.
|
// is discovered.
|
||||||
block := getBlockForMining(mineWhenNotSynced)
|
block, state := getBlockForMining(mineWhenNotSynced)
|
||||||
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
|
state.Nonce = nonce
|
||||||
headerForMining := block.Header.ToMutable()
|
|
||||||
headerForMining.SetNonce(nonce)
|
|
||||||
atomic.AddUint64(&hashesTried, 1)
|
atomic.AddUint64(&hashesTried, 1)
|
||||||
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
|
if state.CheckProofOfWork() {
|
||||||
block.Header = headerForMining.ToImmutable()
|
mutHeader := block.Header.ToMutable()
|
||||||
log.Infof("Found block %s with parents %s", consensushashing.BlockHash(block), block.Header.ParentHashes())
|
mutHeader.SetNonce(nonce)
|
||||||
|
block.Header = mutHeader.ToImmutable()
|
||||||
|
log.Infof("Found block %s with parents %s", consensushashing.BlockHash(block), block.Header.DirectParents())
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
func getBlockForMining(mineWhenNotSynced bool) (*externalapi.DomainBlock, *pow.State) {
|
||||||
tryCount := 0
|
tryCount := 0
|
||||||
|
|
||||||
const sleepTime = 500 * time.Millisecond
|
const sleepTime = 500 * time.Millisecond
|
||||||
@@ -170,7 +165,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
|||||||
tryCount++
|
tryCount++
|
||||||
|
|
||||||
shouldLog := (tryCount-1)%10 == 0
|
shouldLog := (tryCount-1)%10 == 0
|
||||||
template, isSynced := templatemanager.Get()
|
template, state, isSynced := templatemanager.Get()
|
||||||
if template == nil {
|
if template == nil {
|
||||||
if shouldLog {
|
if shouldLog {
|
||||||
log.Info("Waiting for the initial template")
|
log.Info("Waiting for the initial template")
|
||||||
@@ -186,7 +181,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return template
|
return template, state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,26 @@ package templatemanager
|
|||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var currentTemplate *externalapi.DomainBlock
|
var currentTemplate *externalapi.DomainBlock
|
||||||
|
var currentState *pow.State
|
||||||
var isSynced bool
|
var isSynced bool
|
||||||
var lock = &sync.Mutex{}
|
var lock = &sync.Mutex{}
|
||||||
|
|
||||||
// Get returns the template to work on
|
// Get returns the template to work on
|
||||||
func Get() (*externalapi.DomainBlock, bool) {
|
func Get() (*externalapi.DomainBlock, *pow.State, bool) {
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
// Shallow copy the block so when the user replaces the header it won't affect the template here.
|
// Shallow copy the block so when the user replaces the header it won't affect the template here.
|
||||||
if currentTemplate == nil {
|
if currentTemplate == nil {
|
||||||
return nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
block := *currentTemplate
|
block := *currentTemplate
|
||||||
return &block, isSynced
|
state := *currentState
|
||||||
|
return &block, &state, isSynced
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the current template to work on
|
// Set sets the current template to work on
|
||||||
@@ -31,6 +34,7 @@ func Set(template *appmessage.GetBlockTemplateResponseMessage) error {
|
|||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
currentTemplate = block
|
currentTemplate = block
|
||||||
|
currentState = pow.NewState(block.Header.ToMutable())
|
||||||
isSynced = template.IsSynced
|
isSynced = template.IsSynced
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +1,30 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func balance(conf *balanceConfig) error {
|
func balance(conf *balanceConfig) error {
|
||||||
client, err := connectToRPC(conf.NetParams(), conf.RPCServer)
|
daemonClient, tearDown, err := client.Connect(conf.DaemonAddress)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||||
|
defer cancel()
|
||||||
|
response, err := daemonClient.GetBalance(ctx, &pb.GetBalanceRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
fmt.Printf("Balance:\t\tKAS %f\n", float64(response.Available)/constants.SompiPerKaspa)
|
||||||
if err != nil {
|
if response.Pending > 0 {
|
||||||
return err
|
fmt.Printf("Pending balance:\tKAS %f\n", float64(response.Pending)/constants.SompiPerKaspa)
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := libkaspawallet.Address(conf.NetParams(), keysFile.PublicKeys, keysFile.MinimumSignatures, keysFile.ECDSA)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
getUTXOsByAddressesResponse, err := client.GetUTXOsByAddresses([]string{addr.String()})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
virtualSelectedParentBlueScoreResponse, err := client.GetVirtualSelectedParentBlueScore()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
virtualSelectedParentBlueScore := virtualSelectedParentBlueScoreResponse.BlueScore
|
|
||||||
|
|
||||||
var availableBalance, pendingBalance uint64
|
|
||||||
for _, entry := range getUTXOsByAddressesResponse.Entries {
|
|
||||||
if isUTXOSpendable(entry, virtualSelectedParentBlueScore, conf.ActiveNetParams.BlockCoinbaseMaturity) {
|
|
||||||
availableBalance += entry.UTXOEntry.Amount
|
|
||||||
} else {
|
|
||||||
pendingBalance += entry.UTXOEntry.Amount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Balance:\t\tKAS %f\n", float64(availableBalance)/util.SompiPerKaspa)
|
|
||||||
if pendingBalance > 0 {
|
|
||||||
fmt.Printf("Pending balance:\tKAS %f\n", float64(pendingBalance)/util.SompiPerKaspa)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,34 +1,35 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client"
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func broadcast(conf *broadcastConfig) error {
|
func broadcast(conf *broadcastConfig) error {
|
||||||
client, err := connectToRPC(conf.NetParams(), conf.RPCServer)
|
daemonClient, tearDown, err := client.Connect(conf.DaemonAddress)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
transaction, err := hex.DecodeString(conf.Transaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
psTxBytes, err := hex.DecodeString(conf.Transaction)
|
response, err := daemonClient.Broadcast(ctx, &pb.BroadcastRequest{Transaction: transaction})
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := libkaspawallet.ExtractTransaction(psTxBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
transactionID, err := sendTransaction(client, tx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Transaction was sent successfully")
|
fmt.Println("Transaction was sent successfully")
|
||||||
fmt.Printf("Transaction ID: \t%s\n", transactionID)
|
fmt.Printf("Transaction ID: \t%s\n", response.TxID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,31 +2,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
|
||||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isUTXOSpendable(entry *appmessage.UTXOsByAddressesEntry, virtualSelectedParentBlueScore uint64, coinbaseMaturity uint64) bool {
|
const daemonTimeout = 2 * time.Minute
|
||||||
if !entry.UTXOEntry.IsCoinbase {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
blockBlueScore := entry.UTXOEntry.BlockDAAScore
|
|
||||||
// TODO: Check for a better alternative than virtualSelectedParentBlueScore
|
|
||||||
return blockBlueScore+coinbaseMaturity < virtualSelectedParentBlueScore
|
|
||||||
}
|
|
||||||
|
|
||||||
func printErrorAndExit(err error) {
|
func printErrorAndExit(err error) {
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func connectToRPC(params *dagconfig.Params, rpcServer string) (*rpcclient.RPCClient, error) {
|
|
||||||
rpcAddress, err := params.NormalizeRPCServerAddress(rpcServer)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return rpcclient.NewRPCClient(rpcAddress)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ const (
|
|||||||
broadcastSubCmd = "broadcast"
|
broadcastSubCmd = "broadcast"
|
||||||
showAddressSubCmd = "show-address"
|
showAddressSubCmd = "show-address"
|
||||||
dumpUnencryptedDataSubCmd = "dump-unencrypted-data"
|
dumpUnencryptedDataSubCmd = "dump-unencrypted-data"
|
||||||
|
startDaemonSubCmd = "start-daemon"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultListen = "localhost:8082"
|
||||||
|
defaultRPCServer = "localhost"
|
||||||
)
|
)
|
||||||
|
|
||||||
type configFlags struct {
|
type configFlags struct {
|
||||||
@@ -25,6 +31,8 @@ type configFlags struct {
|
|||||||
|
|
||||||
type createConfig struct {
|
type createConfig struct {
|
||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
||||||
|
Password string `long:"password" short:"p" description:"Wallet password"`
|
||||||
|
Yes bool `long:"yes" short:"y" description:"Assume \"yes\" to all questions"`
|
||||||
MinimumSignatures uint32 `long:"min-signatures" short:"m" description:"Minimum required signatures" default:"1"`
|
MinimumSignatures uint32 `long:"min-signatures" short:"m" description:"Minimum required signatures" default:"1"`
|
||||||
NumPrivateKeys uint32 `long:"num-private-keys" short:"k" description:"Number of private keys" default:"1"`
|
NumPrivateKeys uint32 `long:"num-private-keys" short:"k" description:"Number of private keys" default:"1"`
|
||||||
NumPublicKeys uint32 `long:"num-public-keys" short:"n" description:"Total number of keys" default:"1"`
|
NumPublicKeys uint32 `long:"num-public-keys" short:"n" description:"Total number of keys" default:"1"`
|
||||||
@@ -34,46 +42,56 @@ type createConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type balanceConfig struct {
|
type balanceConfig struct {
|
||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"`
|
||||||
RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"`
|
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
type sendConfig struct {
|
type sendConfig struct {
|
||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
||||||
RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"`
|
Password string `long:"password" short:"p" description:"Wallet password"`
|
||||||
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
|
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"`
|
||||||
SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"`
|
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
|
||||||
|
SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
type createUnsignedTransactionConfig struct {
|
type createUnsignedTransactionConfig struct {
|
||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"`
|
||||||
RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"`
|
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
|
||||||
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
|
SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"`
|
||||||
SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"`
|
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
type signConfig struct {
|
type signConfig struct {
|
||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
||||||
|
Password string `long:"password" short:"p" description:"Wallet password"`
|
||||||
Transaction string `long:"transaction" short:"t" description:"The unsigned transaction to sign on (encoded in hex)" required:"true"`
|
Transaction string `long:"transaction" short:"t" description:"The unsigned transaction to sign on (encoded in hex)" required:"true"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
type broadcastConfig struct {
|
type broadcastConfig struct {
|
||||||
RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"`
|
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"`
|
||||||
Transaction string `long:"transaction" short:"t" description:"The signed transaction to broadcast (encoded in hex)" required:"true"`
|
Transaction string `long:"transaction" short:"t" description:"The signed transaction to broadcast (encoded in hex)" required:"true"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
type showAddressConfig struct {
|
type showAddressConfig struct {
|
||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"`
|
||||||
|
config.NetworkFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
type startDaemonConfig struct {
|
||||||
|
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
||||||
|
Password string `long:"password" short:"p" description:"Wallet password"`
|
||||||
|
RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"`
|
||||||
|
Listen string `short:"l" long:"listen" description:"Address to listen on (default: 0.0.0.0:8082)"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
type dumpUnencryptedDataConfig struct {
|
type dumpUnencryptedDataConfig struct {
|
||||||
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"`
|
||||||
|
Password string `long:"password" short:"p" description:"Wallet password"`
|
||||||
|
Yes bool `long:"yes" short:"y" description:"Assume \"yes\" to all questions"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,15 +103,15 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
|||||||
parser.AddCommand(createSubCmd, "Creates a new wallet",
|
parser.AddCommand(createSubCmd, "Creates a new wallet",
|
||||||
"Creates a private key and 3 public addresses, one for each of MainNet, TestNet and DevNet", createConf)
|
"Creates a private key and 3 public addresses, one for each of MainNet, TestNet and DevNet", createConf)
|
||||||
|
|
||||||
balanceConf := &balanceConfig{}
|
balanceConf := &balanceConfig{DaemonAddress: defaultListen}
|
||||||
parser.AddCommand(balanceSubCmd, "Shows the balance of a public address",
|
parser.AddCommand(balanceSubCmd, "Shows the balance of a public address",
|
||||||
"Shows the balance for a public address in Kaspa", balanceConf)
|
"Shows the balance for a public address in Kaspa", balanceConf)
|
||||||
|
|
||||||
sendConf := &sendConfig{}
|
sendConf := &sendConfig{DaemonAddress: defaultListen}
|
||||||
parser.AddCommand(sendSubCmd, "Sends a Kaspa transaction to a public address",
|
parser.AddCommand(sendSubCmd, "Sends a Kaspa transaction to a public address",
|
||||||
"Sends a Kaspa transaction to a public address", sendConf)
|
"Sends a Kaspa transaction to a public address", sendConf)
|
||||||
|
|
||||||
createUnsignedTransactionConf := &createUnsignedTransactionConfig{}
|
createUnsignedTransactionConf := &createUnsignedTransactionConfig{DaemonAddress: defaultListen}
|
||||||
parser.AddCommand(createUnsignedTransactionSubCmd, "Create an unsigned Kaspa transaction",
|
parser.AddCommand(createUnsignedTransactionSubCmd, "Create an unsigned Kaspa transaction",
|
||||||
"Create an unsigned Kaspa transaction", createUnsignedTransactionConf)
|
"Create an unsigned Kaspa transaction", createUnsignedTransactionConf)
|
||||||
|
|
||||||
@@ -101,11 +119,11 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
|||||||
parser.AddCommand(signSubCmd, "Sign the given partially signed transaction",
|
parser.AddCommand(signSubCmd, "Sign the given partially signed transaction",
|
||||||
"Sign the given partially signed transaction", signConf)
|
"Sign the given partially signed transaction", signConf)
|
||||||
|
|
||||||
broadcastConf := &broadcastConfig{}
|
broadcastConf := &broadcastConfig{DaemonAddress: defaultListen}
|
||||||
parser.AddCommand(broadcastSubCmd, "Broadcast the given transaction",
|
parser.AddCommand(broadcastSubCmd, "Broadcast the given transaction",
|
||||||
"Broadcast the given transaction", broadcastConf)
|
"Broadcast the given transaction", broadcastConf)
|
||||||
|
|
||||||
showAddressConf := &showAddressConfig{}
|
showAddressConf := &showAddressConfig{DaemonAddress: defaultListen}
|
||||||
parser.AddCommand(showAddressSubCmd, "Shows the public address of the current wallet",
|
parser.AddCommand(showAddressSubCmd, "Shows the public address of the current wallet",
|
||||||
"Shows the public address of the current wallet", showAddressConf)
|
"Shows the public address of the current wallet", showAddressConf)
|
||||||
|
|
||||||
@@ -114,6 +132,12 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
|||||||
"Prints the unencrypted wallet data including its private keys. Anyone that sees it can access "+
|
"Prints the unencrypted wallet data including its private keys. Anyone that sees it can access "+
|
||||||
"the funds. Use only on safe environment.", dumpUnencryptedDataConf)
|
"the funds. Use only on safe environment.", dumpUnencryptedDataConf)
|
||||||
|
|
||||||
|
startDaemonConf := &startDaemonConfig{
|
||||||
|
RPCServer: defaultRPCServer,
|
||||||
|
Listen: defaultListen,
|
||||||
|
}
|
||||||
|
parser.AddCommand(startDaemonSubCmd, "Start the wallet daemon", "Start the wallet daemon", startDaemonConf)
|
||||||
|
|
||||||
_, err := parser.Parse()
|
_, err := parser.Parse()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -183,6 +207,13 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
|||||||
printErrorAndExit(err)
|
printErrorAndExit(err)
|
||||||
}
|
}
|
||||||
config = dumpUnencryptedDataConf
|
config = dumpUnencryptedDataConf
|
||||||
|
case startDaemonSubCmd:
|
||||||
|
combineNetworkFlags(&startDaemonConf.NetworkFlags, &cfg.NetworkFlags)
|
||||||
|
err := startDaemonConf.ResolveNetwork(parser)
|
||||||
|
if err != nil {
|
||||||
|
printErrorAndExit(err)
|
||||||
|
}
|
||||||
|
config = startDaemonConf
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser.Command.Active.Name, config
|
return parser.Command.Active.Name, config
|
||||||
|
|||||||
@@ -2,68 +2,77 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/bip32"
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/utils"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
func create(conf *createConfig) error {
|
func create(conf *createConfig) error {
|
||||||
var encryptedPrivateKeys []*keys.EncryptedPrivateKey
|
var encryptedMnemonics []*keys.EncryptedMnemonic
|
||||||
var publicKeys [][]byte
|
var signerExtendedPublicKeys []string
|
||||||
var err error
|
var err error
|
||||||
|
isMultisig := conf.NumPublicKeys > 1
|
||||||
if !conf.Import {
|
if !conf.Import {
|
||||||
encryptedPrivateKeys, publicKeys, err = keys.CreateKeyPairs(conf.NumPrivateKeys, conf.ECDSA)
|
encryptedMnemonics, signerExtendedPublicKeys, err = keys.CreateMnemonics(conf.NetParams(), conf.NumPrivateKeys, conf.Password, isMultisig)
|
||||||
} else {
|
} else {
|
||||||
encryptedPrivateKeys, publicKeys, err = keys.ImportKeyPairs(conf.NumPrivateKeys)
|
encryptedMnemonics, signerExtendedPublicKeys, err = keys.ImportMnemonics(conf.NetParams(), conf.NumPrivateKeys, conf.Password, isMultisig)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, publicKey := range publicKeys {
|
for i, extendedPublicKey := range signerExtendedPublicKeys {
|
||||||
fmt.Printf("Public key of private key #%d:\n%x\n\n", i+1, publicKey)
|
fmt.Printf("Extended public key of mnemonic #%d:\n%s\n\n", i+1, extendedPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extendedPublicKeys := make([]string, conf.NumPrivateKeys, conf.NumPublicKeys)
|
||||||
|
copy(extendedPublicKeys, signerExtendedPublicKeys)
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
for i := conf.NumPrivateKeys; i < conf.NumPublicKeys; i++ {
|
for i := conf.NumPrivateKeys; i < conf.NumPublicKeys; i++ {
|
||||||
fmt.Printf("Enter public key #%d here:\n", i+1)
|
fmt.Printf("Enter public key #%d here:\n", i+1)
|
||||||
line, isPrefix, err := reader.ReadLine()
|
extendedPublicKey, err := utils.ReadLine(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = bip32.DeserializeExtendedKey(string(extendedPublicKey))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "%s is invalid extended public key", string(extendedPublicKey))
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
if isPrefix {
|
extendedPublicKeys = append(extendedPublicKeys, string(extendedPublicKey))
|
||||||
return errors.Errorf("Public key is too long")
|
|
||||||
}
|
|
||||||
|
|
||||||
publicKey, err := hex.DecodeString(string(line))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
publicKeys = append(publicKeys, publicKey)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = keys.WriteKeysFile(conf.KeysFile, encryptedPrivateKeys, publicKeys, conf.MinimumSignatures, conf.ECDSA)
|
cosignerIndex, err := libkaspawallet.MinimumCosignerIndex(signerExtendedPublicKeys, extendedPublicKeys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
file := keys.File{
|
||||||
|
EncryptedMnemonics: encryptedMnemonics,
|
||||||
|
ExtendedPublicKeys: extendedPublicKeys,
|
||||||
|
MinimumSignatures: conf.MinimumSignatures,
|
||||||
|
CosignerIndex: cosignerIndex,
|
||||||
|
ECDSA: conf.ECDSA,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = file.SetPath(conf.NetParams(), conf.KeysFile, conf.Yes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := libkaspawallet.Address(conf.NetParams(), keysFile.PublicKeys, keysFile.MinimumSignatures, keysFile.ECDSA)
|
err = file.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("The wallet address is:\n%s\n", addr)
|
fmt.Printf("Wrote the keys into %s\n", file.Path())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,34 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createUnsignedTransaction(conf *createUnsignedTransactionConfig) error {
|
func createUnsignedTransaction(conf *createUnsignedTransactionConfig) error {
|
||||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
daemonClient, tearDown, err := client.Connect(conf.DaemonAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
toAddress, err := util.DecodeAddress(conf.ToAddress, conf.NetParams().Prefix)
|
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||||
if err != nil {
|
defer cancel()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fromAddress, err := libkaspawallet.Address(conf.NetParams(), keysFile.PublicKeys, keysFile.MinimumSignatures, keysFile.ECDSA)
|
sendAmountSompi := uint64(conf.SendAmount * constants.SompiPerKaspa)
|
||||||
if err != nil {
|
response, err := daemonClient.CreateUnsignedTransaction(ctx, &pb.CreateUnsignedTransactionRequest{
|
||||||
return err
|
Address: conf.ToAddress,
|
||||||
}
|
Amount: sendAmountSompi,
|
||||||
|
})
|
||||||
client, err := connectToRPC(conf.NetParams(), conf.RPCServer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
utxos, err := fetchSpendableUTXOs(conf.NetParams(), client, fromAddress.String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAmountSompi := uint64(conf.SendAmount * util.SompiPerKaspa)
|
|
||||||
|
|
||||||
const feePerInput = 1000
|
|
||||||
selectedUTXOs, changeSompi, err := selectUTXOs(utxos, sendAmountSompi, feePerInput)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
psTx, err := libkaspawallet.CreateUnsignedTransaction(keysFile.PublicKeys,
|
|
||||||
keysFile.MinimumSignatures,
|
|
||||||
keysFile.ECDSA,
|
|
||||||
[]*libkaspawallet.Payment{{
|
|
||||||
Address: toAddress,
|
|
||||||
Amount: sendAmountSompi,
|
|
||||||
}, {
|
|
||||||
Address: fromAddress,
|
|
||||||
Amount: changeSompi,
|
|
||||||
}}, selectedUTXOs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Created unsigned transaction")
|
fmt.Println("Created unsigned transaction")
|
||||||
fmt.Println(hex.EncodeToString(psTx))
|
fmt.Println(hex.EncodeToString(response.UnsignedTransaction))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
30
cmd/kaspawallet/daemon/client/client.go
Normal file
30
cmd/kaspawallet/daemon/client/client.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Connect connects to the kaspawalletd server, and returns the client instance
|
||||||
|
func Connect(address string) (pb.KaspawalletdClient, func(), error) {
|
||||||
|
// Connection is local, so 1 second timeout is sufficient
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
conn, err := grpc.DialContext(ctx, address, grpc.WithInsecure(), grpc.WithBlock())
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
return nil, nil, errors.New("kaspawallet daemon is not running, start it with `kaspawallet start-daemon`")
|
||||||
|
}
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb.NewKaspawalletdClient(conn), func() {
|
||||||
|
conn.Close()
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
3
cmd/kaspawallet/daemon/pb/generate.go
Normal file
3
cmd/kaspawallet/daemon/pb/generate.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
//go:generate protoc --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative kaspawalletd.proto
|
||||||
|
|
||||||
|
package pb
|
||||||
730
cmd/kaspawallet/daemon/pb/kaspawalletd.pb.go
Normal file
730
cmd/kaspawallet/daemon/pb/kaspawalletd.pb.go
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.25.0
|
||||||
|
// protoc v3.12.3
|
||||||
|
// source: kaspawalletd.proto
|
||||||
|
|
||||||
|
package pb
|
||||||
|
|
||||||
|
import (
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||||
|
// of the legacy proto package is being used.
|
||||||
|
const _ = proto.ProtoPackageIsVersion4
|
||||||
|
|
||||||
|
type GetBalanceRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalanceRequest) Reset() {
|
||||||
|
*x = GetBalanceRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalanceRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetBalanceRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetBalanceRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetBalanceRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetBalanceRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetBalanceResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Available uint64 `protobuf:"varint,1,opt,name=available,proto3" json:"available,omitempty"`
|
||||||
|
Pending uint64 `protobuf:"varint,2,opt,name=pending,proto3" json:"pending,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalanceResponse) Reset() {
|
||||||
|
*x = GetBalanceResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalanceResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetBalanceResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetBalanceResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetBalanceResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetBalanceResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalanceResponse) GetAvailable() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Available
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetBalanceResponse) GetPending() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Pending
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateUnsignedTransactionRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
||||||
|
Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionRequest) Reset() {
|
||||||
|
*x = CreateUnsignedTransactionRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CreateUnsignedTransactionRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CreateUnsignedTransactionRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CreateUnsignedTransactionRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionRequest) GetAddress() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Address
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionRequest) GetAmount() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Amount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateUnsignedTransactionResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
UnsignedTransaction []byte `protobuf:"bytes,1,opt,name=unsignedTransaction,proto3" json:"unsignedTransaction,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionResponse) Reset() {
|
||||||
|
*x = CreateUnsignedTransactionResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CreateUnsignedTransactionResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CreateUnsignedTransactionResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CreateUnsignedTransactionResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateUnsignedTransactionResponse) GetUnsignedTransaction() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.UnsignedTransaction
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetReceiveAddressRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetReceiveAddressRequest) Reset() {
|
||||||
|
*x = GetReceiveAddressRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetReceiveAddressRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetReceiveAddressRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetReceiveAddressRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetReceiveAddressRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetReceiveAddressRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetReceiveAddressResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetReceiveAddressResponse) Reset() {
|
||||||
|
*x = GetReceiveAddressResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetReceiveAddressResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetReceiveAddressResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetReceiveAddressResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[5]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetReceiveAddressResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetReceiveAddressResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetReceiveAddressResponse) GetAddress() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Address
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type BroadcastRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Transaction []byte `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BroadcastRequest) Reset() {
|
||||||
|
*x = BroadcastRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BroadcastRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*BroadcastRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *BroadcastRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[6]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use BroadcastRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*BroadcastRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BroadcastRequest) GetTransaction() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Transaction
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type BroadcastResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
TxID string `protobuf:"bytes,1,opt,name=txID,proto3" json:"txID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BroadcastResponse) Reset() {
|
||||||
|
*x = BroadcastResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BroadcastResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*BroadcastResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *BroadcastResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[7]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use BroadcastResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*BroadcastResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *BroadcastResponse) GetTxID() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.TxID
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShutdownRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ShutdownRequest) Reset() {
|
||||||
|
*x = ShutdownRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ShutdownRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ShutdownRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ShutdownRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[8]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ShutdownRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ShutdownRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{8}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShutdownResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ShutdownResponse) Reset() {
|
||||||
|
*x = ShutdownResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ShutdownResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ShutdownResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ShutdownResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[9]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ShutdownResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ShutdownResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{9}
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_kaspawalletd_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_kaspawalletd_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x12, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x22, 0x13, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||||
|
0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4c, 0x0a, 0x12, 0x47, 0x65, 0x74,
|
||||||
|
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
|
0x1c, 0x0a, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x04, 0x52, 0x09, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a,
|
||||||
|
0x07, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07,
|
||||||
|
0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x54, 0x0a, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||||
|
0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61,
|
||||||
|
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,
|
||||||
|
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18,
|
||||||
|
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x55, 0x0a,
|
||||||
|
0x21, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54,
|
||||||
|
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
|
0x73, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72,
|
||||||
|
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||||
|
0x13, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69,
|
||||||
|
0x76, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x22, 0x35, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x64,
|
||||||
|
0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a,
|
||||||
|
0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||||
|
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x34, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, 0x64,
|
||||||
|
0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x74,
|
||||||
|
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
|
||||||
|
0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x27, 0x0a,
|
||||||
|
0x11, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
|
0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
0x52, 0x04, 0x74, 0x78, 0x49, 0x44, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f,
|
||||||
|
0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x68, 0x75,
|
||||||
|
0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xe4, 0x02,
|
||||||
|
0x0a, 0x0c, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x12, 0x37,
|
||||||
|
0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x2e, 0x47,
|
||||||
|
0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x1a, 0x13, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73,
|
||||||
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||||
|
0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73,
|
||||||
|
0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||||
|
0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
||||||
|
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a,
|
||||||
|
0x11, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65,
|
||||||
|
0x73, 0x73, 0x12, 0x19, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41,
|
||||||
|
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e,
|
||||||
|
0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||||
|
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x08, 0x53,
|
||||||
|
0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x10, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f,
|
||||||
|
0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x53, 0x68, 0x75, 0x74,
|
||||||
|
0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x34,
|
||||||
|
0x0a, 0x09, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x11, 0x2e, 0x42, 0x72,
|
||||||
|
0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12,
|
||||||
|
0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
|
0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||||
|
0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70,
|
||||||
|
0x61, 0x64, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c,
|
||||||
|
0x65, 0x74, 0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_kaspawalletd_proto_rawDescOnce sync.Once
|
||||||
|
file_kaspawalletd_proto_rawDescData = file_kaspawalletd_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_kaspawalletd_proto_rawDescGZIP() []byte {
|
||||||
|
file_kaspawalletd_proto_rawDescOnce.Do(func() {
|
||||||
|
file_kaspawalletd_proto_rawDescData = protoimpl.X.CompressGZIP(file_kaspawalletd_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_kaspawalletd_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_kaspawalletd_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||||
|
var file_kaspawalletd_proto_goTypes = []interface{}{
|
||||||
|
(*GetBalanceRequest)(nil), // 0: GetBalanceRequest
|
||||||
|
(*GetBalanceResponse)(nil), // 1: GetBalanceResponse
|
||||||
|
(*CreateUnsignedTransactionRequest)(nil), // 2: CreateUnsignedTransactionRequest
|
||||||
|
(*CreateUnsignedTransactionResponse)(nil), // 3: CreateUnsignedTransactionResponse
|
||||||
|
(*GetReceiveAddressRequest)(nil), // 4: GetReceiveAddressRequest
|
||||||
|
(*GetReceiveAddressResponse)(nil), // 5: GetReceiveAddressResponse
|
||||||
|
(*BroadcastRequest)(nil), // 6: BroadcastRequest
|
||||||
|
(*BroadcastResponse)(nil), // 7: BroadcastResponse
|
||||||
|
(*ShutdownRequest)(nil), // 8: ShutdownRequest
|
||||||
|
(*ShutdownResponse)(nil), // 9: ShutdownResponse
|
||||||
|
}
|
||||||
|
var file_kaspawalletd_proto_depIdxs = []int32{
|
||||||
|
0, // 0: kaspawalletd.GetBalance:input_type -> GetBalanceRequest
|
||||||
|
2, // 1: kaspawalletd.CreateUnsignedTransaction:input_type -> CreateUnsignedTransactionRequest
|
||||||
|
4, // 2: kaspawalletd.GetReceiveAddress:input_type -> GetReceiveAddressRequest
|
||||||
|
8, // 3: kaspawalletd.Shutdown:input_type -> ShutdownRequest
|
||||||
|
6, // 4: kaspawalletd.Broadcast:input_type -> BroadcastRequest
|
||||||
|
1, // 5: kaspawalletd.GetBalance:output_type -> GetBalanceResponse
|
||||||
|
3, // 6: kaspawalletd.CreateUnsignedTransaction:output_type -> CreateUnsignedTransactionResponse
|
||||||
|
5, // 7: kaspawalletd.GetReceiveAddress:output_type -> GetReceiveAddressResponse
|
||||||
|
9, // 8: kaspawalletd.Shutdown:output_type -> ShutdownResponse
|
||||||
|
7, // 9: kaspawalletd.Broadcast:output_type -> BroadcastResponse
|
||||||
|
5, // [5:10] is the sub-list for method output_type
|
||||||
|
0, // [0:5] is the sub-list for method input_type
|
||||||
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_kaspawalletd_proto_init() }
|
||||||
|
func file_kaspawalletd_proto_init() {
|
||||||
|
if File_kaspawalletd_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_kaspawalletd_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetBalanceRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetBalanceResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CreateUnsignedTransactionRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CreateUnsignedTransactionResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetReceiveAddressRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetReceiveAddressResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*BroadcastRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*BroadcastResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ShutdownRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ShutdownResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_kaspawalletd_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 10,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_kaspawalletd_proto_goTypes,
|
||||||
|
DependencyIndexes: file_kaspawalletd_proto_depIdxs,
|
||||||
|
MessageInfos: file_kaspawalletd_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_kaspawalletd_proto = out.File
|
||||||
|
file_kaspawalletd_proto_rawDesc = nil
|
||||||
|
file_kaspawalletd_proto_goTypes = nil
|
||||||
|
file_kaspawalletd_proto_depIdxs = nil
|
||||||
|
}
|
||||||
49
cmd/kaspawallet/daemon/pb/kaspawalletd.proto
Normal file
49
cmd/kaspawallet/daemon/pb/kaspawalletd.proto
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option go_package = "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb";
|
||||||
|
|
||||||
|
service kaspawalletd {
|
||||||
|
rpc GetBalance (GetBalanceRequest) returns (GetBalanceResponse) {}
|
||||||
|
rpc CreateUnsignedTransaction (CreateUnsignedTransactionRequest) returns (CreateUnsignedTransactionResponse) {}
|
||||||
|
rpc GetReceiveAddress (GetReceiveAddressRequest) returns (GetReceiveAddressResponse) {}
|
||||||
|
rpc Shutdown (ShutdownRequest) returns (ShutdownResponse) {}
|
||||||
|
rpc Broadcast (BroadcastRequest) returns (BroadcastResponse) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetBalanceRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetBalanceResponse {
|
||||||
|
uint64 available = 1;
|
||||||
|
uint64 pending = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateUnsignedTransactionRequest {
|
||||||
|
string address = 1;
|
||||||
|
uint64 amount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateUnsignedTransactionResponse {
|
||||||
|
bytes unsignedTransaction = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetReceiveAddressRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetReceiveAddressResponse {
|
||||||
|
string address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BroadcastRequest {
|
||||||
|
bytes transaction = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BroadcastResponse {
|
||||||
|
string txID = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ShutdownRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message ShutdownResponse {
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user