Compare commits

..

35 Commits

Author SHA1 Message Date
Ori Newman
7be3f41aa7 Avoid sending transactions with no funds (#2193) 2023-03-06 12:20:42 +02:00
Ori Newman
26c4c73624 Update changelog.txt and version.go (#2192) 2023-02-28 18:14:01 +02:00
D-Stacks
880d917e58 Rename last references to blockheight - closes #1036 (#2089)
* Rename references of blockheight - closes #1036

* Update tx_invalid.json

* bluescore -> DAAScore

---------

Co-authored-by: Ori Newman <orinewman1@gmail.com>
2023-02-27 17:14:41 +02:00
Eyal Yablonka
3c53c6d8cd Eyal (#2183)
* Create CODE_OF_CONDUCT.md

Code of conduct added

* changed discord to google form

* Update CODE_OF_CONDUCT.md

Updated code of conduct to match community project.

* Update CODE_OF_CONDUCT.md

Updated code of conduct to match community project.
Added google form.

---------

Co-authored-by: Ori Newman <orinewman1@gmail.com>
2023-02-27 16:10:27 +02:00
Ori Newman
3c4b973090 Extend TestGetPreciseSigOps with more tests (#2188) 2023-02-27 15:58:10 +02:00
Ori Newman
8aee8f81c5 Add Dockerfile to kaspawallet (#2187) 2023-02-27 13:11:52 +02:00
Svarog
ec3441e63f Add --send-all to kaspawallet send command (#2181)
* Allow to send --all

* Fix a typo

---------

Co-authored-by: Ori Newman <orinewman1@gmail.com>
2023-02-27 12:39:01 +02:00
dependabot[bot]
e3ba1ca07e Bump golang.org/x/text from 0.3.5 to 0.3.8 (#2190)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.5 to 0.3.8.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.5...v0.3.8)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ori Newman <orinewman1@gmail.com>
2023-02-27 12:26:52 +02:00
Ori Newman
27fdbd9c88 Upgrade to go 1.19 (#2191)
* Upgrade to go 1.19

* fmt
2023-02-27 10:03:11 +02:00
Michael Sutton
377d9aaaeb Update changelog.txt for v0.12.11 (#2176) 2022-12-01 12:33:48 +02:00
Ori Newman
beee947dda Fix IBD sync conditions (#2174)
* Fix IBD sync conditions

* Fix syntax

* Fix Sprintf

* Bump version

* On negotiation check only blocks in future of PP

* Only log error and add comment

* Fix comment
2022-11-29 17:18:07 +02:00
Ori Newman
d4a27bf1c1 Update changelog.txt for v0.12.10 (#2172) 2022-11-23 12:26:47 +02:00
Ori Newman
eec6eb9669 Check rule errors when validating blocks with trusted data (#2171) 2022-11-21 23:06:00 +02:00
Ori Newman
d5c10832c2 Update README.md (#2163) 2022-11-20 14:50:47 +02:00
Ori Newman
9fbfba17b6 Compare blue score with selected tip when checking if a pruning point… (#2169)
* Compare blue score with selected tip when checking if a pruning point proof is needed

* Don't redeclare err

Co-authored-by: Michael Sutton <mikisiton2@gmail.com>
2022-11-20 13:35:00 +02:00
Ori Newman
09d698dd0e Add note about change addresses to 'show-addresses' (#2170)
* Add note about change addresses to 'show-addresses'

* Use stdout
2022-11-20 12:12:09 +02:00
Ori Newman
ec51c6926a Use one of the From addresses as a change address (#2164)
* Use one of the From addresses as a change address

* Use change address from fromAddress only if useExisting is set to true

* Change FromAddresses description
2022-11-17 15:31:18 +02:00
Ori Newman
7d44275eb1 Add found to GetBlock (#2165) 2022-11-16 23:48:05 +02:00
Ori Newman
a3387a56b3 Increase devnet's initial difficulty (#2167) 2022-11-13 14:01:29 +02:00
Ori Newman
c2ae03fc89 Fix nativeTx to be actually native (#2166) 2022-11-13 13:15:18 +02:00
Ori Newman
6c774c966b Changelog for v0.12.9 (#2161) 2022-10-24 00:50:38 +03:00
Ori Newman
2d54c9693b Create directory before locking lock file (#2160) 2022-10-24 00:41:59 +03:00
Ori Newman
d8350d62b0 v0.12.8 changelog.txt (#2159) 2022-10-23 16:29:26 +03:00
Ori Newman
26c7db251f Make more checks if status is invalid even if the block exists (#2158)
* Make more checks if status is invalid even if the block exists

* Use HasHeader
2022-10-13 19:22:00 +03:00
Michael Sutton
4d435f2b3a Use utxo diff algo for pruning point move and use acceptance data method only as a fall-back (#2157)
Co-authored-by: Ori Newman <orinewman1@gmail.com>
2022-10-12 12:37:13 +03:00
Tiram
067688f549 Add a new testnet dnsseeder (#2156)
* Add a new testnet dnsseeder

* Apply code format

Co-authored-by: Ori Newman <orinewman1@gmail.com>
2022-10-05 09:23:35 +03:00
Ori Newman
3a3fa0d3f0 Add lock file to kaspawallet (#2154)
* Add lock file to kaspawallet

* Add a possible explanation to password error

Co-authored-by: msutton <mikisiton2@gmail.com>
2022-10-02 23:42:14 +03:00
Ori Newman
cf4073b773 Remove HF activation code (#2152)
* Remove HF activation code

* Remove unused var totalInputs
2022-10-02 19:17:33 +03:00
Michael Sutton
6a5e7c9e3f Add IBD error details to the log (#2150) 2022-09-30 13:23:54 +03:00
Ori Newman
7e9b5b9010 Security Patch + HF (#2142)
* HF

* Fix lint
2022-09-21 18:58:32 +03:00
D-Stacks
953838e0d8 Allow mismatched versioning connections with rpc_client, with a warning. (#2137) 2022-09-14 09:53:30 +03:00
Ori Newman
a1dcb34c29 Update changelog for v0.12.6 (#2136) 2022-09-09 15:57:43 +03:00
Ori Newman
23764e1b0b Optionally show serialized transactions on send (#2135)
* Optionally show serialized transactions on send

* Explain more about serialized transactions

* Increase grpc server send message size
2022-09-09 15:51:20 +03:00
Ori Newman
0838cc8e32 Update virtual on IBD if nearly synced (#2134)
* Update virtual on IBD if nearly synced

* Don't resolve virtual if updateVirtual
2022-09-09 00:52:08 +03:00
Ori Newman
9f51330f38 Remove tests from docker files (#2133)
* Remove tests from docker files

* Remove unused interface method
2022-09-01 14:14:37 +03:00
108 changed files with 1291 additions and 794 deletions

View File

@@ -23,7 +23,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.18
go-version: 1.19
- name: Build on Linux
if: runner.os == 'Linux'

View File

@@ -22,7 +22,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.18
go-version: 1.19
- name: Set scheduled branch name
shell: bash

View File

@@ -33,7 +33,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.18
go-version: 1.19
# Source: https://github.com/actions/cache/blob/main/examples.md#go---modules
@@ -58,7 +58,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.18
go-version: 1.19
- name: Checkout
uses: actions/checkout@v2
@@ -86,7 +86,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.18
go-version: 1.19
- name: Delete the stability tests from coverage
run: rm -r stability-tests

43
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,43 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainers on this [Google form][gform]. The project maintainers will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[gform]: https://forms.gle/dnKXMJL7VxdUjt3x5
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -7,8 +7,6 @@ Kaspad
Kaspad is the reference full node Kaspa implementation written in Go (golang).
This project is currently under active development and is in Beta state.
## What is kaspa
Kaspa is an attempt at a proof-of-work cryptocurrency with instant confirmations and sub-second block times. It is based on [the PHANTOM protocol](https://eprint.iacr.org/2018/104.pdf), a generalization of Nakamoto consensus.

View File

@@ -6,7 +6,7 @@ supported kaspa messages to and from the appmessage. This package does not deal
with the specifics of message handling such as what to do when a message is
received. This provides the caller with a high level of flexibility.
Kaspa Message Overview
# Kaspa Message Overview
The kaspa protocol consists of exchanging messages between peers. Each
message is preceded by a header which identifies information about it such as
@@ -22,7 +22,7 @@ messages, all of the details of marshalling and unmarshalling to and from the
appmessage using kaspa encoding are handled so the caller doesn't have to concern
themselves with the specifics.
Message Interaction
# Message Interaction
The following provides a quick summary of how the kaspa messages are intended
to interact with one another. As stated above, these interactions are not
@@ -45,13 +45,13 @@ interactions in no particular order.
notfound message (MsgNotFound)
ping message (MsgPing) pong message (MsgPong)
Common Parameters
# Common Parameters
There are several common parameters that arise when using this package to read
and write kaspa messages. The following sections provide a quick overview of
these parameters so the next sections can build on them.
Protocol Version
# Protocol Version
The protocol version should be negotiated with the remote peer at a higher
level than this package via the version (MsgVersion) message exchange, however,
@@ -60,18 +60,18 @@ latest protocol version this package supports and is typically the value to use
for all outbound connections before a potentially lower protocol version is
negotiated.
Kaspa Network
# Kaspa Network
The kaspa network is a magic number which is used to identify the start of a
message and which kaspa network the message applies to. This package provides
the following constants:
appmessage.Mainnet
appmessage.Testnet (Test network)
appmessage.Simnet (Simulation test network)
appmessage.Devnet (Development network)
appmessage.Mainnet
appmessage.Testnet (Test network)
appmessage.Simnet (Simulation test network)
appmessage.Devnet (Development network)
Determining Message Type
# Determining Message Type
As discussed in the kaspa message overview section, this package reads
and writes kaspa messages using a generic interface named Message. In
@@ -89,7 +89,7 @@ switch or type assertion. An example of a type switch follows:
fmt.Printf("Number of tx in block: %d", msg.Header.TxnCount)
}
Reading Messages
# Reading Messages
In order to unmarshall kaspa messages from the appmessage, use the ReadMessage
function. It accepts any io.Reader, but typically this will be a net.Conn to
@@ -104,7 +104,7 @@ a remote node running a kaspa peer. Example syntax is:
// Log and handle the error
}
Writing Messages
# Writing Messages
In order to marshall kaspa messages to the appmessage, use the WriteMessage
function. It accepts any io.Writer, but typically this will be a net.Conn to
@@ -122,7 +122,7 @@ from a remote peer is:
// Log and handle the error
}
Errors
# Errors
Errors returned by this package are either the raw errors provided by underlying
calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and

View File

@@ -132,7 +132,7 @@ func TestConvertToPartial(t *testing.T) {
}
}
//blockOne is the first block in the mainnet block DAG.
// blockOne is the first block in the mainnet block DAG.
var blockOne = MsgBlock{
Header: MsgBlockHeader{
Version: 0,

View File

@@ -133,8 +133,8 @@ func TestTx(t *testing.T) {
// TestTxHash tests the ability to generate the hash of a transaction accurately.
func TestTxHashAndID(t *testing.T) {
txHash1Str := "93663e597f6c968d32d229002f76408edf30d6a0151ff679fc729812d8cb2acc"
txID1Str := "24079c6d2bdf602fc389cc307349054937744a9c8dc0f07c023e6af0e949a4e7"
txHash1Str := "b06f8b650115b5cf4d59499e10764a9312742930cb43c9b4ff6495d76f332ed7"
txID1Str := "e20225c3d065ee41743607ee627db44d01ef396dc9779b05b2caf55bac50e12d"
wantTxID1, err := transactionid.FromString(txID1Str)
if err != nil {
t.Fatalf("NewTxIDFromStr: %v", err)
@@ -185,7 +185,7 @@ func TestTxHashAndID(t *testing.T) {
spew.Sprint(tx1ID), spew.Sprint(wantTxID1))
}
hash2Str := "8dafd1bec24527d8e3b443ceb0a3b92fffc0d60026317f890b2faf5e9afc177a"
hash2Str := "fa16a8ce88d52ca1ff45187bbba0d33044e9f5fe309e8d0b22d4812dcf1782b7"
wantHash2, err := externalapi.NewDomainHashFromString(hash2Str)
if err != nil {
t.Errorf("NewTxIDFromStr: %v", err)

View File

@@ -27,18 +27,15 @@ func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute
log.Debugf("Got request for %d ibd blocks", len(msgRequestIBDBlocks.Hashes))
for i, hash := range msgRequestIBDBlocks.Hashes {
// Fetch the block from the database.
blockInfo, err := context.Domain().Consensus().GetBlockInfo(hash)
if err != nil {
return err
}
if !blockInfo.HasBody() {
return protocolerrors.Errorf(true, "block %s not found (v5)", hash)
}
block, err := context.Domain().Consensus().GetBlock(hash)
block, found, err := context.Domain().Consensus().GetBlock(hash)
if err != nil {
return errors.Wrapf(err, "unable to fetch requested block hash %s", hash)
}
if !found {
return protocolerrors.Errorf(false, "IBD block %s not found", hash)
}
// TODO (Partial nodes): Convert block to partial block if needed
blockMessage := appmessage.DomainBlockToMsgBlock(block)

View File

@@ -119,11 +119,15 @@ func HandlePruningPointAndItsAnticoneRequests(context PruningPointAndItsAnticone
}
for i, blockHash := range pointAndItsAnticone {
block, err := context.Domain().Consensus().GetBlock(blockHash)
block, found, err := context.Domain().Consensus().GetBlock(blockHash)
if err != nil {
return err
}
if !found {
return protocolerrors.Errorf(false, "pruning point anticone block %s not found", blockHash)
}
err = outgoingRoute.Enqueue(appmessage.DomainBlockWithTrustedDataToBlockWithTrustedDataV4(block, trustedDataDAABlockIndexes[*blockHash], trustedDataGHOSTDAGDataIndexes[*blockHash]))
if err != nil {
return err

View File

@@ -28,18 +28,15 @@ func HandleRelayBlockRequests(context RelayBlockRequestsContext, incomingRoute *
log.Debugf("Got request for relay blocks with hashes %s", getRelayBlocksMessage.Hashes)
for _, hash := range getRelayBlocksMessage.Hashes {
// Fetch the block from the database.
blockInfo, err := context.Domain().Consensus().GetBlockInfo(hash)
if err != nil {
return err
}
if !blockInfo.HasBody() {
return protocolerrors.Errorf(true, "block %s not found", hash)
}
block, err := context.Domain().Consensus().GetBlock(hash)
block, found, err := context.Domain().Consensus().GetBlock(hash)
if err != nil {
return errors.Wrapf(err, "unable to fetch requested block hash %s", hash)
}
if !found {
return protocolerrors.Errorf(false, "Relay block %s not found", hash)
}
// TODO (Partial nodes): Convert block to partial block if needed
err = outgoingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(block))

View File

@@ -211,10 +211,14 @@ func (flow *handleRelayInvsFlow) start() error {
continue
}
virtualHasNewParents = true
block, err := flow.Domain().Consensus().GetBlock(parent)
block, found, err := flow.Domain().Consensus().GetBlock(parent)
if err != nil {
return err
}
if !found {
return protocolerrors.Errorf(false, "Virtual parent %s not found", parent)
}
blockHash := consensushashing.BlockHash(block)
log.Debugf("Relaying block %s", blockHash)
err = flow.relayBlock(block)

View File

@@ -1,6 +1,7 @@
package blockrelay
import (
"fmt"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/app/protocol/common"
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
@@ -70,16 +71,17 @@ func (flow *handleIBDFlow) runIBDIfNotRunning(block *externalapi.DomainBlock) er
}
isFinishedSuccessfully := false
var err error
defer func() {
flow.UnsetIBDRunning()
flow.logIBDFinished(isFinishedSuccessfully)
flow.logIBDFinished(isFinishedSuccessfully, err)
}()
relayBlockHash := consensushashing.BlockHash(block)
log.Debugf("IBD started with peer %s and relayBlockHash %s", flow.peer, relayBlockHash)
log.Debugf("Syncing blocks up to %s", relayBlockHash)
log.Debugf("Trying to find highest known syncer chain block from peer %s with relay hash %s", flow.peer, relayBlockHash)
log.Infof("IBD started with peer %s and relayBlockHash %s", flow.peer, relayBlockHash)
log.Infof("Syncing blocks up to %s", relayBlockHash)
log.Infof("Trying to find highest known syncer chain block from peer %s with relay hash %s", flow.peer, relayBlockHash)
syncerHeaderSelectedTipHash, highestKnownSyncerChainHash, err := flow.negotiateMissingSyncerChainSegment()
if err != nil {
@@ -98,7 +100,7 @@ func (flow *handleIBDFlow) runIBDIfNotRunning(block *externalapi.DomainBlock) er
if shouldDownloadHeadersProof {
log.Infof("Starting IBD with headers proof")
err := flow.ibdWithHeadersProof(syncerHeaderSelectedTipHash, relayBlockHash, block.Header.DAAScore())
err = flow.ibdWithHeadersProof(syncerHeaderSelectedTipHash, relayBlockHash, block.Header.DAAScore())
if err != nil {
return err
}
@@ -173,6 +175,11 @@ func (flow *handleIBDFlow) negotiateMissingSyncerChainSegment() (*externalapi.Do
chainNegotiationRestartCounter := 0
chainNegotiationZoomCounts := 0
initialLocatorLen := len(locatorHashes)
pruningPoint, err := flow.Domain().Consensus().PruningPoint()
if err != nil {
return nil, nil, err
}
for {
var lowestUnknownSyncerChainHash, currentHighestKnownSyncerChainHash *externalapi.DomainHash
for _, syncerChainHash := range locatorHashes {
@@ -181,8 +188,25 @@ func (flow *handleIBDFlow) negotiateMissingSyncerChainSegment() (*externalapi.Do
return nil, nil, err
}
if info.Exists {
currentHighestKnownSyncerChainHash = syncerChainHash
break
if info.BlockStatus == externalapi.StatusInvalid {
return nil, nil, protocolerrors.Errorf(true, "Sent invalid chain block %s", syncerChainHash)
}
isPruningPointOnSyncerChain, err := flow.Domain().Consensus().IsInSelectedParentChainOf(pruningPoint, syncerChainHash)
if err != nil {
log.Errorf("Error checking isPruningPointOnSyncerChain: %s", err)
}
// We're only interested in syncer chain blocks that have our pruning
// point in their selected chain. Otherwise, it means one of the following:
// 1) We will not switch the virtual selected chain to the syncers chain since it will violate finality
// (hence we can ignore it unless merged by others).
// 2) syncerChainHash is actually in the past of our pruning point so there's no
// point in syncing from it.
if err == nil && isPruningPointOnSyncerChain {
currentHighestKnownSyncerChainHash = syncerChainHash
break
}
}
lowestUnknownSyncerChainHash = syncerChainHash
}
@@ -261,7 +285,7 @@ func (flow *handleIBDFlow) negotiateMissingSyncerChainSegment() (*externalapi.Do
}
}
log.Debugf("Found highest known syncer chain block %s from peer %s",
log.Infof("Found highest known syncer chain block %s from peer %s",
highestKnownSyncerChainHash, flow.peer)
return syncerHeaderSelectedTipHash, highestKnownSyncerChainHash, nil
@@ -276,10 +300,14 @@ func (flow *handleIBDFlow) isGenesisVirtualSelectedParent() (bool, error) {
return virtualSelectedParent.Equal(flow.Config().NetParams().GenesisHash), nil
}
func (flow *handleIBDFlow) logIBDFinished(isFinishedSuccessfully bool) {
func (flow *handleIBDFlow) logIBDFinished(isFinishedSuccessfully bool, err error) {
successString := "successfully"
if !isFinishedSuccessfully {
successString = "(interrupted)"
if err != nil {
successString = fmt.Sprintf("(interrupted: %s)", err)
} else {
successString = fmt.Sprintf("(interrupted)")
}
}
log.Infof("IBD with peer %s finished %s", flow.peer, successString)
}
@@ -618,6 +646,12 @@ func (flow *handleIBDFlow) syncMissingBlockBodies(highHash *externalapi.DomainHa
progressReporter := newIBDProgressReporter(lowBlockHeader.DAAScore(), highBlockHeader.DAAScore(), "blocks")
highestProcessedDAAScore := lowBlockHeader.DAAScore()
// If the IBD is small, we want to update the virtual after each block in order to avoid complications and possible bugs.
updateVirtual, err := flow.Domain().Consensus().IsNearlySynced()
if err != nil {
return err
}
for offset := 0; offset < len(hashes); offset += ibdBatchSize {
var hashesToRequest []*externalapi.DomainHash
if offset+ibdBatchSize < len(hashes) {
@@ -654,7 +688,7 @@ func (flow *handleIBDFlow) syncMissingBlockBodies(highHash *externalapi.DomainHa
return err
}
err = flow.Domain().Consensus().ValidateAndInsertBlock(block, false)
err = flow.Domain().Consensus().ValidateAndInsertBlock(block, updateVirtual)
if err != nil {
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
log.Debugf("Skipping IBD Block %s as it has already been added to the DAG", blockHash)
@@ -673,7 +707,15 @@ func (flow *handleIBDFlow) syncMissingBlockBodies(highHash *externalapi.DomainHa
progressReporter.reportProgress(len(hashesToRequest), highestProcessedDAAScore)
}
return flow.resolveVirtual(highestProcessedDAAScore)
// We need to resolve virtual only if it wasn't updated while syncing block bodies
if !updateVirtual {
err := flow.resolveVirtual(highestProcessedDAAScore)
if err != nil {
return err
}
}
return flow.OnNewBlockTemplate()
}
func (flow *handleIBDFlow) banIfBlockIsHeaderOnly(block *externalapi.DomainBlock) error {
@@ -705,9 +747,5 @@ func (flow *handleIBDFlow) resolveVirtual(estimatedVirtualDAAScoreTarget uint64)
}
log.Infof("Resolved virtual")
err = flow.OnNewBlockTemplate()
if err != nil {
return err
}
return nil
}

View File

@@ -25,7 +25,7 @@ func (flow *handleIBDFlow) ibdWithHeadersProof(
return err
}
log.Infof("IBD with pruning proof from %s was unsuccessful. Deleting the staging consensus.", flow.peer)
log.Infof("IBD with pruning proof from %s was unsuccessful. Deleting the staging consensus. (%s)", flow.peer, err)
deleteStagingConsensusErr := flow.Domain().DeleteStagingConsensus()
if deleteStagingConsensusErr != nil {
return deleteStagingConsensusErr
@@ -55,7 +55,12 @@ func (flow *handleIBDFlow) shouldSyncAndShouldDownloadHeadersProof(
var highestSharedBlockFound, isPruningPointInSharedBlockChain bool
if highestKnownSyncerChainHash != nil {
highestSharedBlockFound = true
blockInfo, err := flow.Domain().Consensus().GetBlockInfo(highestKnownSyncerChainHash)
if err != nil {
return false, false, err
}
highestSharedBlockFound = blockInfo.HasBody()
pruningPoint, err := flow.Domain().Consensus().PruningPoint()
if err != nil {
return false, false, err
@@ -80,28 +85,33 @@ func (flow *handleIBDFlow) shouldSyncAndShouldDownloadHeadersProof(
return true, true, nil
}
return false, false, nil
if highestKnownSyncerChainHash == nil {
log.Infof("Stopping IBD since IBD from this node will cause a finality conflict")
return false, false, nil
}
return false, true, nil
}
return false, true, nil
}
func (flow *handleIBDFlow) checkIfHighHashHasMoreBlueWorkThanSelectedTipAndPruningDepthMoreBlueScore(relayBlock *externalapi.DomainBlock) (bool, error) {
headersSelectedTip, err := flow.Domain().Consensus().GetHeadersSelectedTip()
virtualSelectedParent, err := flow.Domain().Consensus().GetVirtualSelectedParent()
if err != nil {
return false, err
}
headersSelectedTipInfo, err := flow.Domain().Consensus().GetBlockInfo(headersSelectedTip)
virtualSelectedTipInfo, err := flow.Domain().Consensus().GetBlockInfo(virtualSelectedParent)
if err != nil {
return false, err
}
if relayBlock.Header.BlueScore() < headersSelectedTipInfo.BlueScore+flow.Config().NetParams().PruningDepth() {
if relayBlock.Header.BlueScore() < virtualSelectedTipInfo.BlueScore+flow.Config().NetParams().PruningDepth() {
return false, nil
}
return relayBlock.Header.BlueWork().Cmp(headersSelectedTipInfo.BlueWork) > 0, nil
return relayBlock.Header.BlueWork().Cmp(virtualSelectedTipInfo.BlueWork) > 0, nil
}
func (flow *handleIBDFlow) syncAndValidatePruningPointProof() (*externalapi.DomainHash, error) {
@@ -281,7 +291,13 @@ func (flow *handleIBDFlow) processBlockWithTrustedData(
}
err := consensus.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
return err
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
return protocolerrors.Wrapf(true, err, "failed validating block with trusted data")
}
return err
}
return nil
}
func (flow *handleIBDFlow) receiveBlockWithTrustedData() (*appmessage.MsgBlockWithTrustedDataV4, bool, error) {

View File

@@ -122,6 +122,7 @@ func (ctx *Context) PopulateTransactionWithVerboseData(
}
ctx.Domain.Consensus().PopulateMass(domainTransaction)
transaction.VerboseData = &appmessage.RPCTransactionVerboseData{
TransactionID: consensushashing.TransactionID(domainTransaction).String(),
Hash: consensushashing.TransactionHash(domainTransaction).String(),

View File

@@ -37,7 +37,7 @@ func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appm
return nil, err
}
if !blockInfo.Exists {
if !blockInfo.HasHeader() {
return &appmessage.GetBlocksResponseMessage{
Error: appmessage.RPCErrorf("Could not find lowHash %s", getBlocksRequest.LowHash),
}, nil

View File

@@ -1,3 +1,63 @@
Kaspad v0.12.12 - 2023-02-28
===========================
* Rename last references to blockheight (#2089)
* Add code of conduct (#2183)
* Extend TestGetPreciseSigOps with more tests (#2188)
* Add Dockerfile to kaspawallet (#2187)
* Add `--send-all` to `kaspawallet send` command (#2181)
* Bump golang.org/x/text from 0.3.5 to 0.3.8 (#2190)
* Upgrade to go 1.19 (#2191)
Kaspad v0.12.11 - 2022-12-1
===========================
* Fix IBD sync conditions (#2174)
Kaspad v0.12.10 - 2022-11-23
===========================
* Increase devnet's initial difficulty (#2167)
Bug fixes:
* Check rule errors when validating blocks with trusted data (#2171)
* Compare blue score with selected tip when checking if a pruning point proof is needed (#2169)
* Add found to GetBlock (#2165)
Wallet new features:
* Use one of the From addresses as a change address (#2164)
Kaspad v0.12.9 - 2022-10-23
===========================
* Create directory before locking lock file (#2160)
Kaspad v0.12.8 - 2022-10-23
===========================
* Remove hard fork activation rules (#2152)
* Add lock file to kaspawallet (#2154)
* Add a new testnet DNS seeder (#2156)
* Use utxo diff algo for pruning point move and use acceptance data method only as a fall-back (#2157)
* Make more checks if status is invalid even if the block exists (#2158)
Kaspad v0.12.7 - 2022-09-21
===========================
* Security Fix + Hard fork - Full details can be seen here: https://medium.com/@michaelsuttonil/kaspa-security-patch-and-hard-fork-september-2022-12da617b0094
Kaspad v0.12.6 - 2022-09-09
===========================
* Remove tests from docker files (#2133)
Wallet new features:
* Optionally show serialized transactions on send (#2135)
Bug fixes:
* Update virtual on IBD if nearly synced (#2134)
Kaspad v0.12.5 - 2022-08-28
===========================

View File

@@ -4,7 +4,7 @@ kaspactl is an RPC client for kaspad
## Requirements
Go 1.18 or later.
Go 1.19 or later.
## Installation

View File

@@ -1,13 +1,11 @@
# -- multistage docker build: stage #1: build stage
FROM golang:1.18-alpine AS build
FROM golang:1.19-alpine AS build
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
WORKDIR /go/src/github.com/kaspanet/kaspad
RUN apk add --no-cache curl git openssh binutils gcc musl-dev
RUN go get -u golang.org/x/lint/golint \
honnef.co/go/tools/cmd/staticcheck
COPY go.mod .
COPY go.sum .
@@ -18,10 +16,6 @@ COPY . .
WORKDIR /go/src/github.com/kaspanet/kaspad/cmd/kaspactl
RUN GOFMT_RESULT=`go fmt ./...`; echo $GOFMT_RESULT; test -z "$GOFMT_RESULT"
RUN go vet ./...
RUN golint -set_exit_status ./...
RUN staticcheck -checks SA4006 ./...
RUN GOOS=linux go build -a -installsuffix cgo -o kaspactl .
# --- multistage docker build: stage #2: runtime image

View File

@@ -4,7 +4,7 @@ Kaspaminer is a CPU-based miner for kaspad
## Requirements
Go 1.18 or later.
Go 1.19 or later.
## Installation

View File

@@ -1,13 +1,11 @@
# -- multistage docker build: stage #1: build stage
FROM golang:1.18-alpine AS build
FROM golang:1.19-alpine AS build
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
WORKDIR /go/src/github.com/kaspanet/kaspad
RUN apk add --no-cache curl git openssh binutils gcc musl-dev
RUN go get -u golang.org/x/lint/golint \
honnef.co/go/tools/cmd/staticcheck
COPY go.mod .
COPY go.sum .
@@ -17,11 +15,6 @@ RUN go mod download
COPY . .
WORKDIR /go/src/github.com/kaspanet/kaspad/cmd/kaspaminer
RUN GOFMT_RESULT=`go fmt ./...`; echo $GOFMT_RESULT; test -z "$GOFMT_RESULT"
RUN go vet ./...
RUN golint -set_exit_status ./...
RUN staticcheck -checks SA4006 ./...
RUN GOOS=linux go build -a -installsuffix cgo -o kaspaminer .
# --- multistage docker build: stage #2: runtime image

View File

@@ -57,8 +57,10 @@ type sendConfig struct {
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to"`
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
FromAddresses []string `long:"from-address" short:"a" description:"Specific public address to send Kaspa from. Use multiple times to accept several addresses" required:"false"`
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)"`
IsSendAll bool `long:"send-all" description:"Send all the Kaspa in the wallet (mutually exclusive with --send-amount)"`
UseExistingChangeAddress bool `long:"use-existing-change-address" short:"u" description:"Will use an existing change address (in case no change address was ever used, it will use a new one)"`
Verbose bool `long:"show-serialized" short:"s" description:"Show a list of hex encoded sent transactions"`
config.NetworkFlags
}
@@ -72,7 +74,8 @@ type createUnsignedTransactionConfig struct {
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to"`
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
FromAddresses []string `long:"from-address" short:"a" description:"Specific public address to send Kaspa from. Use multiple times to accept several addresses" required:"false"`
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)"`
IsSendAll bool `long:"send-all" description:"Send all the Kaspa in the wallet (mutually exclusive with --send-amount)"`
UseExistingChangeAddress bool `long:"use-existing-change-address" short:"u" description:"Will use an existing change address (in case no change address was ever used, it will use a new one)"`
config.NetworkFlags
}
@@ -215,6 +218,10 @@ func parseCommandLine() (subCommand string, config interface{}) {
if err != nil {
printErrorAndExit(err)
}
err = validateSendConfig(sendConf)
if err != nil {
printErrorAndExit(err)
}
config = sendConf
case sweepSubCmd:
combineNetworkFlags(&sweepConf.NetworkFlags, &cfg.NetworkFlags)
@@ -229,6 +236,10 @@ func parseCommandLine() (subCommand string, config interface{}) {
if err != nil {
printErrorAndExit(err)
}
err = validateCreateUnsignedTransactionConf(createUnsignedTransactionConf)
if err != nil {
printErrorAndExit(err)
}
config = createUnsignedTransactionConf
case signSubCmd:
combineNetworkFlags(&signConf.NetworkFlags, &cfg.NetworkFlags)
@@ -284,6 +295,24 @@ func parseCommandLine() (subCommand string, config interface{}) {
return parser.Command.Active.Name, config
}
func validateCreateUnsignedTransactionConf(conf *createUnsignedTransactionConfig) error {
if (!conf.IsSendAll && conf.SendAmount == 0) ||
(conf.IsSendAll && conf.SendAmount > 0) {
return errors.New("exactly one of '--send-amount' or '--all' must be specified")
}
return nil
}
func validateSendConfig(conf *sendConfig) error {
if (!conf.IsSendAll && conf.SendAmount == 0) ||
(conf.IsSendAll && conf.SendAmount > 0) {
return errors.New("exactly one of '--send-amount' or '--all' must be specified")
}
return nil
}
func combineNetworkFlags(dst, src *config.NetworkFlags) {
dst.Testnet = dst.Testnet || src.Testnet
dst.Simnet = dst.Simnet || src.Simnet

View File

@@ -78,6 +78,11 @@ func create(conf *createConfig) error {
return err
}
err = file.TryLock()
if err != nil {
return err
}
err = file.Save()
if err != nil {
return err

View File

@@ -25,6 +25,7 @@ func createUnsignedTransaction(conf *createUnsignedTransactionConfig) error {
From: conf.FromAddresses,
Address: conf.ToAddress,
Amount: sendAmountSompi,
IsSendAll: conf.IsSendAll,
UseExistingChangeAddress: conf.UseExistingChangeAddress,
})
if err != nil {

View File

@@ -2,6 +2,7 @@ package client
import (
"context"
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/server"
"time"
"github.com/pkg/errors"
@@ -16,7 +17,7 @@ func Connect(address string) (pb.KaspawalletdClient, func(), error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
conn, err := grpc.DialContext(ctx, address, grpc.WithInsecure(), grpc.WithBlock())
conn, err := grpc.DialContext(ctx, address, grpc.WithInsecure(), grpc.WithBlock(), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(server.MaxDaemonSendMsgSize)))
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`")

View File

@@ -1,13 +1,12 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.3
// protoc-gen-go v1.26.0
// protoc v3.21.12
// 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"
@@ -21,10 +20,6 @@ const (
_ = 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
@@ -198,6 +193,7 @@ type CreateUnsignedTransactionsRequest struct {
Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"`
From []string `protobuf:"bytes,3,rep,name=from,proto3" json:"from,omitempty"`
UseExistingChangeAddress bool `protobuf:"varint,4,opt,name=useExistingChangeAddress,proto3" json:"useExistingChangeAddress,omitempty"`
IsSendAll bool `protobuf:"varint,5,opt,name=isSendAll,proto3" json:"isSendAll,omitempty"`
}
func (x *CreateUnsignedTransactionsRequest) Reset() {
@@ -260,6 +256,13 @@ func (x *CreateUnsignedTransactionsRequest) GetUseExistingChangeAddress() bool {
return false
}
func (x *CreateUnsignedTransactionsRequest) GetIsSendAll() bool {
if x != nil {
return x.IsSendAll
}
return false
}
type CreateUnsignedTransactionsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1004,6 +1007,7 @@ type SendRequest struct {
Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"`
From []string `protobuf:"bytes,4,rep,name=from,proto3" json:"from,omitempty"`
UseExistingChangeAddress bool `protobuf:"varint,5,opt,name=useExistingChangeAddress,proto3" json:"useExistingChangeAddress,omitempty"`
IsSendAll bool `protobuf:"varint,6,opt,name=isSendAll,proto3" json:"isSendAll,omitempty"`
}
func (x *SendRequest) Reset() {
@@ -1073,12 +1077,20 @@ func (x *SendRequest) GetUseExistingChangeAddress() bool {
return false
}
func (x *SendRequest) GetIsSendAll() bool {
if x != nil {
return x.IsSendAll
}
return false
}
type SendResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TxIDs []string `protobuf:"bytes,1,rep,name=txIDs,proto3" json:"txIDs,omitempty"`
TxIDs []string `protobuf:"bytes,1,rep,name=txIDs,proto3" json:"txIDs,omitempty"`
SignedTransactions [][]byte `protobuf:"bytes,2,rep,name=signedTransactions,proto3" json:"signedTransactions,omitempty"`
}
func (x *SendResponse) Reset() {
@@ -1120,6 +1132,13 @@ func (x *SendResponse) GetTxIDs() []string {
return nil
}
func (x *SendResponse) GetSignedTransactions() [][]byte {
if x != nil {
return x.SignedTransactions
}
return nil
}
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection
type SignRequest struct {
state protoimpl.MessageState
@@ -1245,7 +1264,7 @@ var file_kaspawalletd_proto_rawDesc = []byte{
0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 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, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x70, 0x65, 0x6e,
0x64, 0x69, 0x6e, 0x67, 0x22, 0xa5, 0x01, 0x0a, 0x21, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55,
0x64, 0x69, 0x6e, 0x67, 0x22, 0xc3, 0x01, 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, 0x73, 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,
@@ -1255,152 +1274,159 @@ var file_kaspawalletd_proto_rawDesc = []byte{
0x12, 0x3a, 0x0a, 0x18, 0x75, 0x73, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x43,
0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x08, 0x52, 0x18, 0x75, 0x73, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x43,
0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x58, 0x0a, 0x22,
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, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c,
0x52, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x31,
0x0a, 0x15, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x22, 0x13, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07,
0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09,
0x69, 0x73, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x6c, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
0x09, 0x69, 0x73, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x6c, 0x6c, 0x22, 0x58, 0x0a, 0x22, 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, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x14,
0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x15,
0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22,
0x13, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x4e, 0x65, 0x77, 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, 0x52, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x44, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x29, 0x0a, 0x11, 0x42, 0x72, 0x6f, 0x61,
0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a,
0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x78,
0x49, 0x44, 0x73, 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, 0x22, 0x46, 0x0a, 0x08, 0x4f, 0x75,
0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05,
0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 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, 0x52, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63,
0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x29, 0x0a, 0x11, 0x42, 0x72,
0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69,
0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61,
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74,
0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x55, 0x74, 0x78,
0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x22, 0x55, 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28,
0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0xb2, 0x01, 0x0a, 0x09, 0x55, 0x74, 0x78,
0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47,
0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75,
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a,
0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x3c, 0x0a,
0x20, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e,
0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 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, 0x22, 0x62, 0x0a, 0x21, 0x47,
0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61,
0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x3d, 0x0a, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64,
0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22,
0xcd, 0x01, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 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, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52,
0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x3a, 0x0a, 0x18, 0x75, 0x73, 0x65, 0x45, 0x78, 0x69, 0x73,
0x74, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x75, 0x73, 0x65, 0x45, 0x78, 0x69, 0x73,
0x74, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x6c, 0x6c, 0x18, 0x06,
0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x6c, 0x6c, 0x22,
0x54, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x14, 0x0a, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05,
0x74, 0x78, 0x49, 0x44, 0x73, 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, 0x22, 0x46, 0x0a, 0x08,
0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14,
0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69,
0x6e, 0x64, 0x65, 0x78, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79,
0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 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, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70,
0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6b, 0x61, 0x73,
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69,
0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09,
0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x55,
0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x22, 0x55, 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0xb2, 0x01, 0x0a, 0x09, 0x55,
0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6b, 0x61, 0x73, 0x70,
0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12,
0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20,
0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22,
0x3c, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70,
0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 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, 0x22, 0x62, 0x0a,
0x21, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e,
0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x3d, 0x0a, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65,
0x74, 0x64, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65,
0x73, 0x22, 0xaf, 0x01, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 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, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x03, 0x28,
0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x3a, 0x0a, 0x18, 0x75, 0x73, 0x65, 0x45, 0x78,
0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x75, 0x73, 0x65, 0x45, 0x78,
0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x09, 0x52, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x22, 0x5d, 0x0a, 0x0b, 0x53, 0x69, 0x67,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x73, 0x69,
0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08,
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e,
0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0c, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xb3, 0x06, 0x0a, 0x0c, 0x6b, 0x61, 0x73,
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x47, 0x65, 0x74,
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61,
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e,
0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x19,
0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64,
0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x12, 0x2e, 0x2e, 0x6b, 0x61, 0x73, 0x70,
0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58,
0x4f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70,
0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58,
0x4f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a,
0x1a, 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, 0x73, 0x12, 0x2f, 0x2e, 0x6b, 0x61,
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 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, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b,
0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 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, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x5a, 0x0a, 0x0d, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65,
0x73, 0x12, 0x22, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64,
0x74, 0x78, 0x49, 0x44, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0c, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5d, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0c, 0x52, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c,
0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x32, 0xb3, 0x06, 0x0a, 0x0c, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
0x6e, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65,
0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c,
0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45,
0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65,
0x55, 0x54, 0x58, 0x4f, 0x73, 0x12, 0x2e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x1a, 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, 0x73, 0x12, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 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,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61,
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 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, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0d,
0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x22, 0x2e,
0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x6f,
0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64,
0x2e, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a,
0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73,
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61,
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
0x4b, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x6b, 0x61,
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64,
0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x61, 0x73,
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f,
0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x09,
0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70,
0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61,
0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70,
0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61,
0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04,
0x53, 0x65, 0x6e, 0x64, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c,
0x65, 0x74, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1a, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53,
0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a,
0x04, 0x53, 0x69, 0x67, 0x6e, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1a, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e,
0x53, 0x69, 0x67, 0x6e, 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,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x41,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x08, 0x53,
0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x09, 0x42, 0x72, 0x6f, 0x61,
0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64,
0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e,
0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6b, 0x61,
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, 0x69, 0x67,
0x6e, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64,
0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6b,
0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x69, 0x67, 0x6e,
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 (

View File

@@ -37,6 +37,7 @@ message CreateUnsignedTransactionsRequest {
uint64 amount = 2;
repeated string from = 3;
bool useExistingChangeAddress = 4;
bool isSendAll = 5;
}
message CreateUnsignedTransactionsResponse {
@@ -109,10 +110,12 @@ message SendRequest{
string password = 3;
repeated string from = 4;
bool useExistingChangeAddress = 5;
bool isSendAll = 6;
}
message SendResponse{
repeated string txIDs = 1;
repeated bytes signedTransactions = 2;
}
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection

View File

@@ -11,7 +11,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// KaspawalletdClient is the client API for Kaspawalletd service.
//
@@ -141,37 +142,44 @@ type KaspawalletdServer interface {
type UnimplementedKaspawalletdServer struct {
}
func (*UnimplementedKaspawalletdServer) GetBalance(context.Context, *GetBalanceRequest) (*GetBalanceResponse, error) {
func (UnimplementedKaspawalletdServer) GetBalance(context.Context, *GetBalanceRequest) (*GetBalanceResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBalance not implemented")
}
func (*UnimplementedKaspawalletdServer) GetExternalSpendableUTXOs(context.Context, *GetExternalSpendableUTXOsRequest) (*GetExternalSpendableUTXOsResponse, error) {
func (UnimplementedKaspawalletdServer) GetExternalSpendableUTXOs(context.Context, *GetExternalSpendableUTXOsRequest) (*GetExternalSpendableUTXOsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetExternalSpendableUTXOs not implemented")
}
func (*UnimplementedKaspawalletdServer) CreateUnsignedTransactions(context.Context, *CreateUnsignedTransactionsRequest) (*CreateUnsignedTransactionsResponse, error) {
func (UnimplementedKaspawalletdServer) CreateUnsignedTransactions(context.Context, *CreateUnsignedTransactionsRequest) (*CreateUnsignedTransactionsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateUnsignedTransactions not implemented")
}
func (*UnimplementedKaspawalletdServer) ShowAddresses(context.Context, *ShowAddressesRequest) (*ShowAddressesResponse, error) {
func (UnimplementedKaspawalletdServer) ShowAddresses(context.Context, *ShowAddressesRequest) (*ShowAddressesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ShowAddresses not implemented")
}
func (*UnimplementedKaspawalletdServer) NewAddress(context.Context, *NewAddressRequest) (*NewAddressResponse, error) {
func (UnimplementedKaspawalletdServer) NewAddress(context.Context, *NewAddressRequest) (*NewAddressResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method NewAddress not implemented")
}
func (*UnimplementedKaspawalletdServer) Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) {
func (UnimplementedKaspawalletdServer) Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Shutdown not implemented")
}
func (*UnimplementedKaspawalletdServer) Broadcast(context.Context, *BroadcastRequest) (*BroadcastResponse, error) {
func (UnimplementedKaspawalletdServer) Broadcast(context.Context, *BroadcastRequest) (*BroadcastResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Broadcast not implemented")
}
func (*UnimplementedKaspawalletdServer) Send(context.Context, *SendRequest) (*SendResponse, error) {
func (UnimplementedKaspawalletdServer) Send(context.Context, *SendRequest) (*SendResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Send not implemented")
}
func (*UnimplementedKaspawalletdServer) Sign(context.Context, *SignRequest) (*SignResponse, error) {
func (UnimplementedKaspawalletdServer) Sign(context.Context, *SignRequest) (*SignResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Sign not implemented")
}
func (*UnimplementedKaspawalletdServer) mustEmbedUnimplementedKaspawalletdServer() {}
func (UnimplementedKaspawalletdServer) mustEmbedUnimplementedKaspawalletdServer() {}
func RegisterKaspawalletdServer(s *grpc.Server, srv KaspawalletdServer) {
s.RegisterService(&_Kaspawalletd_serviceDesc, srv)
// UnsafeKaspawalletdServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to KaspawalletdServer will
// result in compilation errors.
type UnsafeKaspawalletdServer interface {
mustEmbedUnimplementedKaspawalletdServer()
}
func RegisterKaspawalletdServer(s grpc.ServiceRegistrar, srv KaspawalletdServer) {
s.RegisterService(&Kaspawalletd_ServiceDesc, srv)
}
func _Kaspawalletd_GetBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
@@ -336,7 +344,10 @@ func _Kaspawalletd_Sign_Handler(srv interface{}, ctx context.Context, dec func(i
return interceptor(ctx, in, info, handler)
}
var _Kaspawalletd_serviceDesc = grpc.ServiceDesc{
// Kaspawalletd_ServiceDesc is the grpc.ServiceDesc for Kaspawalletd service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Kaspawalletd_ServiceDesc = grpc.ServiceDesc{
ServiceName: "kaspawalletd.kaspawalletd",
HandlerType: (*KaspawalletdServer)(nil),
Methods: []grpc.MethodDesc{

View File

@@ -10,27 +10,33 @@ import (
"github.com/pkg/errors"
)
func (s *server) changeAddress(useFirst bool) (util.Address, *walletAddress, error) {
internalIndex := uint32(0)
if !useFirst {
err := s.keysFile.SetLastUsedInternalIndex(s.keysFile.LastUsedInternalIndex() + 1)
if err != nil {
return nil, nil, err
func (s *server) changeAddress(useExisting bool, fromAddresses []*walletAddress) (util.Address, *walletAddress, error) {
var walletAddr *walletAddress
if len(fromAddresses) != 0 && useExisting {
walletAddr = fromAddresses[0]
} else {
internalIndex := uint32(0)
if !useExisting {
err := s.keysFile.SetLastUsedInternalIndex(s.keysFile.LastUsedInternalIndex() + 1)
if err != nil {
return nil, nil, err
}
err = s.keysFile.Save()
if err != nil {
return nil, nil, err
}
internalIndex = s.keysFile.LastUsedInternalIndex()
}
err = s.keysFile.Save()
if err != nil {
return nil, nil, err
walletAddr = &walletAddress{
index: internalIndex,
cosignerIndex: s.keysFile.CosignerIndex,
keyChain: libkaspawallet.InternalKeychain,
}
internalIndex = s.keysFile.LastUsedInternalIndex()
}
walletAddr := &walletAddress{
index: internalIndex,
cosignerIndex: s.keysFile.CosignerIndex,
keyChain: libkaspawallet.InternalKeychain,
}
path := s.walletAddressPath(walletAddr)
address, err := libkaspawallet.Address(s.params, s.keysFile.ExtendedPublicKeys, s.keysFile.MinimumSignatures, path, s.keysFile.ECDSA)
if err != nil {

View File

@@ -22,7 +22,8 @@ func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.Creat
s.lock.Lock()
defer s.lock.Unlock()
unsignedTransactions, err := s.createUnsignedTransactions(request.Address, request.Amount, request.From, request.UseExistingChangeAddress)
unsignedTransactions, err := s.createUnsignedTransactions(request.Address, request.Amount, request.IsSendAll,
request.From, request.UseExistingChangeAddress)
if err != nil {
return nil, err
}
@@ -30,7 +31,7 @@ func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.Creat
return &pb.CreateUnsignedTransactionsResponse{UnsignedTransactions: unsignedTransactions}, nil
}
func (s *server) createUnsignedTransactions(address string, amount uint64, fromAddressesString []string, useExistingChangeAddress bool) ([][]byte, error) {
func (s *server) createUnsignedTransactions(address string, amount uint64, isSendAll bool, fromAddressesString []string, useExistingChangeAddress bool) ([][]byte, error) {
if !s.isSynced() {
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
}
@@ -56,19 +57,23 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, fromA
fromAddresses = append(fromAddresses, fromAddress)
}
selectedUTXOs, changeSompi, err := s.selectUTXOs(amount, feePerInput, fromAddresses)
selectedUTXOs, spendValue, changeSompi, err := s.selectUTXOs(amount, isSendAll, feePerInput, fromAddresses)
if err != nil {
return nil, err
}
changeAddress, changeWalletAddress, err := s.changeAddress(useExistingChangeAddress)
if len(selectedUTXOs) == 0 {
return nil, errors.Errorf("couldn't find funds to spend")
}
changeAddress, changeWalletAddress, err := s.changeAddress(useExistingChangeAddress, fromAddresses)
if err != nil {
return nil, err
}
payments := []*libkaspawallet.Payment{{
Address: toAddress,
Amount: amount,
Amount: spendValue,
}}
if changeSompi > 0 {
payments = append(payments, &libkaspawallet.Payment{
@@ -90,15 +95,15 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, fromA
return unsignedTransactions, nil
}
func (s *server) selectUTXOs(spendAmount uint64, feePerInput uint64, fromAddresses []*walletAddress) (
selectedUTXOs []*libkaspawallet.UTXO, changeSompi uint64, err error,
) {
func (s *server) selectUTXOs(spendAmount uint64, isSendAll bool, feePerInput uint64, fromAddresses []*walletAddress) (
selectedUTXOs []*libkaspawallet.UTXO, totalReceived uint64, changeSompi uint64, err error) {
selectedUTXOs = []*libkaspawallet.UTXO{}
totalValue := uint64(0)
dagInfo, err := s.rpcClient.GetBlockDAGInfo()
if err != nil {
return nil, 0, err
return nil, 0, 0, err
}
for _, utxo := range s.utxosSortedByAmount {
@@ -120,21 +125,29 @@ func (s *server) selectUTXOs(spendAmount uint64, feePerInput uint64, fromAddress
UTXOEntry: utxo.UTXOEntry,
DerivationPath: s.walletAddressPath(utxo.address),
})
totalValue += utxo.UTXOEntry.Amount()
fee := feePerInput * uint64(len(selectedUTXOs))
totalSpend := spendAmount + fee
if totalValue >= totalSpend {
if !isSendAll && totalValue >= totalSpend {
break
}
}
fee := feePerInput * uint64(len(selectedUTXOs))
totalSpend := spendAmount + fee
var totalSpend uint64
if isSendAll {
totalSpend = totalValue
totalReceived = totalValue - fee
} else {
totalSpend = spendAmount + fee
totalReceived = spendAmount
}
if totalValue < totalSpend {
return nil, 0, errors.Errorf("Insufficient funds for send: %f required, while only %f available",
return nil, 0, 0, errors.Errorf("Insufficient funds for send: %f required, while only %f available",
float64(totalSpend)/constants.SompiPerKaspa, float64(totalValue)/constants.SompiPerKaspa)
}
return selectedUTXOs, totalValue - totalSpend, nil
return selectedUTXOs, totalReceived, totalValue - totalSpend, nil
}

View File

@@ -10,7 +10,9 @@ func (s *server) Send(_ context.Context, request *pb.SendRequest) (*pb.SendRespo
s.lock.Lock()
defer s.lock.Unlock()
unsignedTransactions, err := s.createUnsignedTransactions(request.ToAddress, request.Amount, request.From, request.UseExistingChangeAddress)
unsignedTransactions, err := s.createUnsignedTransactions(request.ToAddress, request.Amount, request.IsSendAll,
request.From, request.UseExistingChangeAddress)
if err != nil {
return nil, err
}
@@ -25,5 +27,5 @@ func (s *server) Send(_ context.Context, request *pb.SendRequest) (*pb.SendRespo
return nil, err
}
return &pb.SendResponse{TxIDs: txIDs}, nil
return &pb.SendResponse{TxIDs: txIDs, SignedTransactions: signedTransactions}, nil
}

View File

@@ -44,6 +44,10 @@ type server struct {
maxProcessedAddressesForLog uint32
}
// MaxDaemonSendMsgSize is the max send message size used for the daemon server.
// Currently, set to 100MB
const MaxDaemonSendMsgSize = 100_000_000
// Start starts the kaspawalletd server
func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath string, profile string, timeout uint32) error {
initLog(defaultLogFile, defaultErrLogFile)
@@ -73,6 +77,11 @@ func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath stri
return (errors.Wrapf(err, "Error reading keys file %s", keysFilePath))
}
err = keysFile.TryLock()
if err != nil {
return err
}
serverInstance := &server{
rpcClient: rpcClient,
params: params,
@@ -96,7 +105,7 @@ func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath stri
}
})
grpcServer := grpc.NewServer()
grpcServer := grpc.NewServer(grpc.MaxSendMsgSize(MaxDaemonSendMsgSize))
pb.RegisterKaspawalletdServer(grpcServer, serverInstance)
spawn("grpcServer.Serve", func() {

View File

@@ -121,7 +121,7 @@ func testEstimateMassIncreaseForSignaturesSetUp(t *testing.T, consensusConfig *c
t.Fatalf("AddBlock: %+v", err)
}
block1, err := tc.GetBlock(block1Hash)
block1, _, err := tc.GetBlock(block1Hash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}

View File

@@ -0,0 +1,29 @@
# -- multistage docker build: stage #1: build stage
FROM golang:1.18-alpine AS build
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
WORKDIR /go/src/github.com/kaspanet/kaspad
RUN apk add --no-cache curl git openssh binutils gcc musl-dev
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
WORKDIR /go/src/github.com/kaspanet/kaspad/cmd/kaspawallet
RUN GOOS=linux go build -a -installsuffix cgo -o kaspawallet .
# --- multistage docker build: stage #2: runtime image
FROM alpine
WORKDIR /app
RUN apk add --no-cache ca-certificates tini
COPY --from=build /go/src/github.com/kaspanet/kaspad/cmd/kaspawallet/kaspawallet /app/
USER nobody
ENTRYPOINT [ "/sbin/tini", "--" ]

View File

@@ -6,6 +6,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/gofrs/flock"
"os"
"path/filepath"
"runtime"
@@ -400,3 +401,33 @@ func decryptMnemonic(numThreads uint8, encryptedPrivateKey *EncryptedMnemonic, p
return string(decrypted), nil
}
// flockMap is a map that holds all lock file handlers. This map guarantees that
// the associated locked file handler will never get cleaned by the GC, because
// once they are cleaned the associated file will be unlocked.
var flockMap = make(map[string]*flock.Flock)
// TryLock tries to acquire an exclusive lock for the file.
func (d *File) TryLock() error {
if _, ok := flockMap[d.path]; ok {
return errors.Errorf("file %s is already locked", d.path)
}
lockFile := flock.New(d.path + ".lock")
err := createFileDirectoryIfDoesntExist(lockFile.Path())
if err != nil {
return err
}
flockMap[d.path] = lockFile
success, err := lockFile.TryLock()
if err != nil {
return err
}
if !success {
return errors.Errorf("%s is locked and cannot be used. Make sure that no other active wallet command is using it.", d.path)
}
return nil
}

View File

@@ -6,7 +6,7 @@
Package base58 provides an API for working with modified base58 and Base58Check
encodings.
Modified Base58 Encoding
# Modified Base58 Encoding
Standard base58 encoding is similar to standard base64 encoding except, as the
name implies, it uses a 58 character alphabet which results in an alphanumeric
@@ -17,7 +17,7 @@ The modified base58 alphabet used by Bitcoin, and hence this package, omits the
0, O, I, and l characters that look the same in many fonts and are therefore
hard to humans to distinguish.
Base58Check Encoding Scheme
# Base58Check Encoding Scheme
The Base58Check encoding scheme is primarily used for Bitcoin addresses at the
time of this writing, however it can be used to generically encode arbitrary

View File

@@ -10,7 +10,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
)
//KaspawalletdUTXOsTolibkaspawalletUTXOs converts a []*pb.UtxosByAddressesEntry to a []*libkaspawallet.UTXO
// KaspawalletdUTXOsTolibkaspawalletUTXOs converts a []*pb.UtxosByAddressesEntry to a []*libkaspawallet.UTXO
func KaspawalletdUTXOsTolibkaspawalletUTXOs(kaspawalletdUtxoEntires []*pb.UtxosByAddressesEntry) ([]*UTXO, error) {
UTXOs := make([]*UTXO, len(kaspawalletdUtxoEntires))
for i, entry := range kaspawalletdUtxoEntires {

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.0
// protoc v3.17.2
// protoc-gen-go v1.26.0
// protoc v3.21.12
// source: wallet.proto
package protoserialization

View File

@@ -88,7 +88,7 @@ func SerializePartiallySignedTransaction(partiallySignedTransaction *PartiallySi
return proto.Marshal(partiallySignedTransactionToProto(partiallySignedTransaction))
}
//DeserializeDomainTransaction Deserialize a Transaction to an *externalapi.DomainTransaction
// DeserializeDomainTransaction Deserialize a Transaction to an *externalapi.DomainTransaction
func DeserializeDomainTransaction(serializedTransactionMessage []byte) (*externalapi.DomainTransaction, error) {
protoTransactionMessage := &protoserialization.TransactionMessage{}
err := proto.Unmarshal(serializedTransactionMessage, protoTransactionMessage)

View File

@@ -84,7 +84,7 @@ func TestMultisig(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
block1, err := tc.GetBlock(block1Hash)
block1, _, err := tc.GetBlock(block1Hash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
@@ -245,7 +245,7 @@ func TestP2PK(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
block1, err := tc.GetBlock(block1Hash)
block1, _, err := tc.GetBlock(block1Hash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
@@ -377,17 +377,17 @@ func TestMaxSompi(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
fundingBlock2, err := tc.GetBlock(fundingBlock2Hash)
fundingBlock2, _, err := tc.GetBlock(fundingBlock2Hash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
fundingBlock3, err := tc.GetBlock(fundingBlock3Hash)
fundingBlock3, _, err := tc.GetBlock(fundingBlock3Hash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
fundingBlock4, err := tc.GetBlock(fundingBlock4Hash)
fundingBlock4, _, err := tc.GetBlock(fundingBlock4Hash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
@@ -397,7 +397,7 @@ func TestMaxSompi(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
block1, err := tc.GetBlock(block1Hash)
block1, _, err := tc.GetBlock(block1Hash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}

View File

@@ -3,6 +3,8 @@ package main
import (
"context"
"fmt"
"os"
"strings"
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client"
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
@@ -31,13 +33,17 @@ func send(conf *sendConfig) error {
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
defer cancel()
sendAmountSompi := uint64(conf.SendAmount * constants.SompiPerKaspa)
var sendAmountSompi uint64
if !conf.IsSendAll {
sendAmountSompi = uint64(conf.SendAmount * constants.SompiPerKaspa)
}
createUnsignedTransactionsResponse, err :=
daemonClient.CreateUnsignedTransactions(ctx, &pb.CreateUnsignedTransactionsRequest{
From: conf.FromAddresses,
Address: conf.ToAddress,
Amount: sendAmountSompi,
IsSendAll: conf.IsSendAll,
UseExistingChangeAddress: conf.UseExistingChangeAddress,
})
if err != nil {
@@ -49,6 +55,10 @@ func send(conf *sendConfig) error {
}
mnemonics, err := keysFile.DecryptMnemonics(conf.Password)
if err != nil {
if strings.Contains(err.Error(), "message authentication failed") {
fmt.Fprintf(os.Stderr, "Password decryption failed. Sometimes this is a result of not "+
"specifying the same keys file used by the wallet daemon process.\n")
}
return err
}
@@ -80,5 +90,12 @@ func send(conf *sendConfig) error {
fmt.Printf("\t%s\n", txID)
}
if conf.Verbose {
fmt.Println("Serialized Transaction(s) (can be parsed via the `parse` command or resent via `broadcast`): ")
for _, signedTx := range signedTransactions {
fmt.Printf("\t%x\n\n", signedTx)
}
}
return nil
}

View File

@@ -26,5 +26,8 @@ func showAddresses(conf *showAddressesConfig) error {
for _, address := range response.Address {
fmt.Println(address)
}
fmt.Printf("\nNote: the above are only addresses that were manually created by the 'new-address' command. If you want to see a list of all addresses, including change addresses, " +
"that have a positive balance, use the command 'balance -v'\n")
return nil
}

6
doc.go
View File

@@ -13,10 +13,12 @@ the box' for most users. However, there are also a wide variety of flags that
can be used to control it.
Usage:
kaspad [OPTIONS]
kaspad [OPTIONS]
For an up-to-date help message:
kaspad --help
kaspad --help
The long form of all option flags (except -C) can be specified in a configuration
file that is automatically parsed when kaspad starts up. By default, the

View File

@@ -1,5 +1,5 @@
# -- multistage docker build: stage #1: build stage
FROM golang:1.18-alpine AS build
FROM golang:1.19-alpine AS build
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
@@ -10,19 +10,13 @@ RUN apk add --no-cache curl git openssh binutils gcc musl-dev
COPY go.mod .
COPY go.sum .
RUN go get -u golang.org/x/lint/golint \
github.com/kisielk/errcheck \
github.com/opennota/check/cmd/aligncheck \
github.com/opennota/check/cmd/structcheck \
github.com/opennota/check/cmd/varcheck \
honnef.co/go/tools/cmd/staticcheck
# Cache kaspad dependencies
RUN go mod download
COPY . .
RUN ./build_and_test.sh
RUN go build $FLAGS -o kaspad .
# --- multistage docker build: stage #2: runtime image
FROM alpine

View File

@@ -357,7 +357,7 @@ func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction
stagingArea, transaction, model.VirtualBlockHash)
}
func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) {
func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, bool, error) {
s.lock.Lock()
defer s.lock.Unlock()
@@ -366,11 +366,11 @@ func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.Do
block, err := s.blockStore.Block(s.databaseContext, stagingArea, blockHash)
if err != nil {
if errors.Is(err, database.ErrNotFound) {
return nil, errors.Wrapf(err, "block %s does not exist", blockHash)
return nil, false, nil
}
return nil, err
return nil, false, err
}
return block, nil
return block, true, nil
}
func (s *consensus) GetBlockEvenIfHeaderOnly(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) {
@@ -853,12 +853,16 @@ func (s *consensus) GetVirtualSelectedParentChainFromBlock(blockHash *externalap
}
func (s *consensus) validateBlockHashExists(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) error {
exists, err := s.blockStatusStore.Exists(s.databaseContext, stagingArea, blockHash)
status, err := s.blockStatusStore.Get(s.databaseContext, stagingArea, blockHash)
if database.IsNotFoundError(err) {
return errors.Errorf("block %s does not exist", blockHash)
}
if err != nil {
return err
}
if !exists {
return errors.Errorf("block %s does not exist", blockHash)
if status == externalapi.StatusInvalid {
return errors.Errorf("block %s is invalid", blockHash)
}
return nil
}

View File

@@ -216,6 +216,8 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
transactionValidator := transactionvalidator.New(config.BlockCoinbaseMaturity,
config.EnableNonNativeSubnetworks,
config.MaxCoinbasePayloadLength,
config.K,
config.CoinbasePayloadScriptPublicKeyMaxLength,
dbManager,
pastMedianTimeManager,
ghostdagDataStore,
@@ -237,12 +239,14 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
config.GenesisBlock.Header.Bits())
coinbaseManager := coinbasemanager.New(
dbManager,
config.SubsidyGenesisReward,
config.PreDeflationaryPhaseBaseSubsidy,
config.CoinbasePayloadScriptPublicKeyMaxLength,
config.GenesisHash,
config.DeflationaryPhaseDaaScore,
config.DeflationaryPhaseBaseSubsidy,
dagTraversalManager,
ghostdagDataStore,
acceptanceDataStore,

View File

@@ -263,7 +263,7 @@ func TestBoundedMergeDepth(t *testing.T) {
continue
}
block, err := tcSyncer.GetBlock(blocksHash)
block, _, err := tcSyncer.GetBlock(blocksHash)
if err != nil {
t.Fatalf("GetBlockHeader: %+v", err)
}

View File

@@ -10,10 +10,12 @@ package externalapi
//
// For example, assume a selected parent chain with IDs as depicted below, and the
// stop block is genesis:
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
//
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
//
// The block locator for block 17 would be the hashes of blocks:
// [17 16 14 11 7 2 genesis]
//
// [17 16 14 11 7 2 genesis]
type BlockLocator []*DomainHash
// Clone returns a clone of BlockLocator

View File

@@ -13,7 +13,7 @@ type Consensus interface {
ValidatePruningPointProof(pruningPointProof *PruningPointProof) error
ApplyPruningPointProof(pruningPointProof *PruningPointProof) error
GetBlock(blockHash *DomainHash) (*DomainBlock, error)
GetBlock(blockHash *DomainHash) (*DomainBlock, bool, error)
GetBlockEvenIfHeaderOnly(blockHash *DomainHash) (*DomainBlock, error)
GetBlockHeader(blockHash *DomainHash) (BlockHeader, error)
GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error)

View File

@@ -7,5 +7,4 @@ type MergeDepthManager interface {
CheckBoundedMergeDepth(stagingArea *StagingArea, blockHash *externalapi.DomainHash, isBlockWithTrustedData bool) error
NonBoundedMergeDepthViolatingBlues(stagingArea *StagingArea, blockHash, mergeDepthRoot *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
VirtualMergeDepthRoot(stagingArea *StagingArea) (*externalapi.DomainHash, error)
MergeDepthRoot(stagingArea *StagingArea, blockHash *externalapi.DomainHash, isBlockWithTrustedData bool) (*externalapi.DomainHash, error)
}

View File

@@ -93,7 +93,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
}
for _, blockHash := range pruningPointAndItsAnticone {
block, err := tcSyncer.GetBlock(blockHash)
block, _, err := tcSyncer.GetBlock(blockHash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
@@ -268,7 +268,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
}
for _, blocksHash := range missingBlockHashes {
block, err := tcSyncer.GetBlock(blocksHash)
block, _, err := tcSyncer.GetBlock(blocksHash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
@@ -294,7 +294,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
}
tipHash := addBlock(tcSyncer, syncerTips, t)
tip, err := tcSyncer.GetBlock(tipHash)
tip, _, err := tcSyncer.GetBlock(tipHash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}
@@ -341,7 +341,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
tipHash := consensusConfig.GenesisHash
for i := 0; i < numSharedBlocks; i++ {
tipHash = addBlock(tcSyncer, []*externalapi.DomainHash{tipHash}, t)
block, err := tcSyncer.GetBlock(tipHash)
block, _, err := tcSyncer.GetBlock(tipHash)
if err != nil {
t.Fatalf("GetBlock: %+v", err)
}

View File

@@ -41,7 +41,7 @@ func TestCheckBlockIsNotPruned(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
beforePruningBlock, err := tc.GetBlock(tipHash)
beforePruningBlock, _, err := tc.GetBlock(tipHash)
if err != nil {
t.Fatalf("beforePruningBlock: %+v", err)
}
@@ -199,7 +199,7 @@ func TestIsFinalizedTransaction(t *testing.T) {
t.Fatalf("Error getting block DAA score : %+v", err)
}
blockParents := block.Header.DirectParents()
parentToSpend, err := tc.GetBlock(blockParents[0])
parentToSpend, _, err := tc.GetBlock(blockParents[0])
if err != nil {
t.Fatalf("Error getting block1: %+v", err)
}

View File

@@ -70,7 +70,7 @@ func TestChainedTransactions(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
block1, err := tc.GetBlock(block1Hash)
block1, _, err := tc.GetBlock(block1Hash)
if err != nil {
t.Fatalf("Error getting block1: %+v", err)
}
@@ -97,7 +97,7 @@ func TestChainedTransactions(t *testing.T) {
t.Fatalf("unexpected error %+v", err)
}
block2, err := tc.GetBlock(block2Hash)
block2, _, err := tc.GetBlock(block2Hash)
if err != nil {
t.Fatalf("Error getting block2: %+v", err)
}
@@ -169,10 +169,10 @@ var unOrderedParentsBlock = externalapi.DomainBlock{
}),
}},
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x31, 0x33, 0x37, 0x72, 0x5c, 0xde, 0x1c, 0xdf,
0xf5, 0x9f, 0xde, 0x16, 0x74, 0xbf, 0x0c, 0x64,
0x37, 0x40, 0x49, 0xdf, 0x02, 0x05, 0xca, 0x6d,
0x52, 0x23, 0x6f, 0xc2, 0x2b, 0xec, 0xad, 0x42,
0x7e, 0xe2, 0x10, 0x4e, 0x21, 0x2f, 0x2a, 0xb1,
0x7d, 0x22, 0xf5, 0xe8, 0xa0, 0x98, 0xef, 0x53,
0x83, 0xae, 0x59, 0x1f, 0x83, 0xf3, 0x78, 0x5d,
0x30, 0xae, 0x3e, 0xb3, 0x06, 0x08, 0x6f, 0x79,
}),
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95,
@@ -202,20 +202,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{
Transactions: []*externalapi.DomainTransaction{
{
Version: 0,
Inputs: []*externalapi.DomainTransactionInput{
{
PreviousOutpoint: externalapi.DomainOutpoint{
TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{}),
Index: 0xffffffff,
},
SignatureScript: []byte{
0x02, 0x10, 0x27, 0x08, 0xac, 0x29, 0x2f, 0x2f,
0xcf, 0x70, 0xb0, 0x7e, 0x0b, 0x2f, 0x50, 0x32,
0x53, 0x48, 0x2f, 0x62, 0x74, 0x63, 0x64, 0x2f,
},
Sequence: math.MaxUint64,
},
},
Inputs: nil,
Outputs: []*externalapi.DomainTransactionOutput{
{
Value: 0x12a05f200, // 5000000000
@@ -446,10 +433,10 @@ var exampleValidBlock = externalapi.DomainBlock{
}),
}},
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x86, 0x8b, 0x73, 0xcd, 0x20, 0x51, 0x23, 0x60,
0xea, 0x62, 0x99, 0x9b, 0x87, 0xf6, 0xdd, 0x8d,
0xa4, 0x0b, 0xd7, 0xcf, 0xc6, 0x32, 0x38, 0xee,
0xd9, 0x68, 0x72, 0x1f, 0xa2, 0x51, 0xe4, 0x28,
0x46, 0xec, 0xf4, 0x5b, 0xe3, 0xba, 0xca, 0x34,
0x9d, 0xfe, 0x8a, 0x78, 0xde, 0xaf, 0x05, 0x3b,
0x0a, 0xa6, 0xd5, 0x38, 0x97, 0x4d, 0xa5, 0x0f,
0xd6, 0xef, 0xb4, 0xd2, 0x66, 0xbc, 0x8d, 0x21,
}),
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3,
@@ -474,21 +461,7 @@ var exampleValidBlock = externalapi.DomainBlock{
Transactions: []*externalapi.DomainTransaction{
{
Version: 0,
Inputs: []*externalapi.DomainTransactionInput{
{
PreviousOutpoint: externalapi.DomainOutpoint{
TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50,
0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33,
0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a,
0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f,
}),
Index: 0xffffffff,
},
SignatureScript: nil,
Sequence: math.MaxUint64,
},
},
Inputs: nil,
Outputs: []*externalapi.DomainTransactionOutput{
{
Value: 0x12a05f200, // 5000000000
@@ -751,10 +724,10 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{
}),
}},
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x7b, 0x25, 0x8b, 0xfa, 0xfb, 0x49, 0xe4, 0x94,
0x48, 0x2c, 0xf9, 0x74, 0xdd, 0xad, 0x9d, 0x6f,
0x98, 0x8f, 0xfb, 0x01, 0x9d, 0x49, 0x29, 0xbe,
0x3c, 0xec, 0x90, 0xfe, 0xa5, 0x0c, 0xaf, 0x6b,
0xd5, 0xd2, 0x32, 0xe4, 0xbe, 0x9c, 0x33, 0xbd,
0xf1, 0x0a, 0xd2, 0x9d, 0x0c, 0xbd, 0xe5, 0xae,
0xcb, 0x1a, 0xf9, 0x5a, 0x3e, 0xfb, 0xf3, 0xc7,
0x2b, 0x4d, 0x10, 0xa6, 0xbd, 0x5f, 0x07, 0xe7,
}),
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3,

View File

@@ -146,8 +146,8 @@ func (v *blockValidator) validateDifficulty(stagingArea *model.StagingArea,
// target difficulty as claimed.
//
// The flags modify the behavior of this function as follows:
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
// difficulty is not performed.
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
// difficulty is not performed.
func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error {
// The target difficulty must be larger than zero.
state := pow.NewState(header.ToMutable())

View File

@@ -204,8 +204,8 @@ func (c *coinbaseManager) calcDeflationaryPeriodBlockSubsidy(blockDaaScore uint6
}
/*
This table was pre-calculated by calling `calcDeflationaryPeriodBlockSubsidyFloatCalc` for all months until reaching 0 subsidy.
To regenerate this table, run `TestBuildSubsidyTable` in coinbasemanager_test.go (note the `deflationaryPhaseBaseSubsidy` therein)
This table was pre-calculated by calling `calcDeflationaryPeriodBlockSubsidyFloatCalc` for all months until reaching 0 subsidy.
To regenerate this table, run `TestBuildSubsidyTable` in coinbasemanager_test.go (note the `deflationaryPhaseBaseSubsidy` therein)
*/
var subsidyByDeflationaryMonthTable = []uint64{
44000000000, 41530469757, 39199543598, 36999442271, 34922823143, 32962755691, 31112698372, 29366476791, 27718263097, 26162556530, 24694165062, 23308188075, 22000000000, 20765234878, 19599771799, 18499721135, 17461411571, 16481377845, 15556349186, 14683238395, 13859131548, 13081278265, 12347082531, 11654094037, 11000000000,

View File

@@ -0,0 +1,57 @@
package coinbasemanager_test
import (
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"testing"
)
func TestExtractCoinbaseDataBlueScoreAndSubsidy(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
factory := consensus.NewFactory()
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockStatus")
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown(false)
tests := []struct {
name string
scriptPublicKeyVersion uint16
}{
{
name: "below 255",
scriptPublicKeyVersion: 100,
},
{
name: "above 255",
scriptPublicKeyVersion: 300,
},
}
for _, test := range tests {
coinbaseTx, _, err := tc.CoinbaseManager().ExpectedCoinbaseTransaction(model.NewStagingArea(), model.VirtualBlockHash, &externalapi.DomainCoinbaseData{
ScriptPublicKey: &externalapi.ScriptPublicKey{
Script: nil,
Version: test.scriptPublicKeyVersion,
},
ExtraData: nil,
})
if err != nil {
t.Fatal(err)
}
_, cbData, _, err := tc.CoinbaseManager().ExtractCoinbaseDataBlueScoreAndSubsidy(coinbaseTx)
if err != nil {
t.Fatal(err)
}
if cbData.ScriptPublicKey.Version != test.scriptPublicKeyVersion {
t.Fatalf("test %s post HF expected %d but got %d", test.name, test.scriptPublicKeyVersion, cbData.ScriptPublicKey.Version)
}
}
})
}

View File

@@ -28,7 +28,7 @@ func (c *coinbaseManager) serializeCoinbasePayload(blueScore uint64,
binary.LittleEndian.PutUint64(payload[:uint64Len], blueScore)
binary.LittleEndian.PutUint64(payload[uint64Len:], subsidy)
payload[uint64Len+lengthOfSubsidy] = uint8(coinbaseData.ScriptPublicKey.Version)
binary.LittleEndian.PutUint16(payload[uint64Len+lengthOfSubsidy:], coinbaseData.ScriptPublicKey.Version)
payload[uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey] = uint8(len(coinbaseData.ScriptPublicKey.Script))
copy(payload[uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey+lengthOfScriptPubKeyLength:], coinbaseData.ScriptPublicKey.Script)
copy(payload[uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey+lengthOfScriptPubKeyLength+scriptLengthOfScriptPubKey:], coinbaseData.ExtraData)
@@ -52,7 +52,7 @@ func ModifyCoinbasePayload(payload []byte, coinbaseData *externalapi.DomainCoinb
payload = newPayload
}
payload[uint64Len+lengthOfSubsidy] = uint8(coinbaseData.ScriptPublicKey.Version)
binary.LittleEndian.PutUint16(payload[uint64Len+lengthOfSubsidy:uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey], coinbaseData.ScriptPublicKey.Version)
payload[uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey] = uint8(len(coinbaseData.ScriptPublicKey.Script))
copy(payload[uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey+lengthOfScriptPubKeyLength:], coinbaseData.ScriptPublicKey.Script)
copy(payload[uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey+lengthOfScriptPubKeyLength+scriptLengthOfScriptPubKey:], coinbaseData.ExtraData)
@@ -73,7 +73,8 @@ func (c *coinbaseManager) ExtractCoinbaseDataBlueScoreAndSubsidy(coinbaseTx *ext
blueScore = binary.LittleEndian.Uint64(coinbaseTx.Payload[:uint64Len])
subsidy = binary.LittleEndian.Uint64(coinbaseTx.Payload[uint64Len:])
scriptPubKeyVersion := uint16(coinbaseTx.Payload[uint64Len+lengthOfSubsidy])
scriptPubKeyVersion := binary.LittleEndian.Uint16(coinbaseTx.Payload[uint64Len+lengthOfSubsidy : uint64Len+lengthOfSubsidy+uint16Len])
scriptPubKeyScriptLength := coinbaseTx.Payload[uint64Len+lengthOfSubsidy+lengthOfVersionScriptPubKey]
if scriptPubKeyScriptLength > c.coinbasePayloadScriptPublicKeyMaxLength {

View File

@@ -40,7 +40,7 @@ func TestUTXOCommitment(t *testing.T) {
if err != nil {
t.Fatalf("Error creating block B: %+v", err)
}
blockB, err := consensus.GetBlock(blockBHash)
blockB, _, err := consensus.GetBlock(blockBHash)
if err != nil {
t.Fatalf("Error getting block B: %+v", err)
}
@@ -73,7 +73,7 @@ func TestUTXOCommitment(t *testing.T) {
}
func checkBlockUTXOCommitment(t *testing.T, consensus testapi.TestConsensus, blockHash *externalapi.DomainHash, blockName string) {
block, err := consensus.GetBlock(blockHash)
block, _, err := consensus.GetBlock(blockHash)
if err != nil {
t.Fatalf("Error getting block %s: %+v", blockName, err)
}

View File

@@ -72,7 +72,8 @@ func New(
maxBlockParents: maxBlockParents,
mergeSetSizeLimit: mergeSetSizeLimit,
genesisHash: genesisHash,
databaseContext: databaseContext,
databaseContext: databaseContext,
ghostdagManager: ghostdagManager,
dagTopologyManager: dagTopologyManager,

View File

@@ -40,7 +40,7 @@ func TestDoubleSpends(t *testing.T) {
if err != nil {
t.Fatalf("Error creating fundingBlock: %+v", err)
}
fundingBlock, err := consensus.GetBlock(fundingBlockHash)
fundingBlock, _, err := consensus.GetBlock(fundingBlockHash)
if err != nil {
t.Fatalf("Error getting fundingBlock: %+v", err)
}
@@ -159,8 +159,9 @@ func TestDoubleSpends(t *testing.T) {
// TestTransactionAcceptance checks that block transactions are accepted correctly when the merge set is sorted topologically.
// DAG diagram:
// genesis <- blockA <- blockB <- blockC <- ..(chain of k-blocks).. lastBlockInChain <- blockD <- blockE <- blockF <- blockG
// ^ ^ |
// | redBlock <------------------------ blueChildOfRedBlock <-------------------------------
//
// ^ ^ |
// | redBlock <------------------------ blueChildOfRedBlock <-------------------------------
func TestTransactionAcceptance(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
stagingArea := model.NewStagingArea()
@@ -195,7 +196,7 @@ func TestTransactionAcceptance(t *testing.T) {
}
}
lastBlockInChain := chainTipHash
blockC, err := testConsensus.GetBlock(blockHashC)
blockC, _, err := testConsensus.GetBlock(blockHashC)
if err != nil {
t.Fatalf("Error getting blockC: %+v", err)
}
@@ -269,22 +270,27 @@ func TestTransactionAcceptance(t *testing.T) {
if err != nil {
t.Fatalf("Error getting acceptance data: %+v", err)
}
blueChildOfRedBlock, err := testConsensus.GetBlock(hashBlueChildOfRedBlock)
blueChildOfRedBlock, _, err := testConsensus.GetBlock(hashBlueChildOfRedBlock)
if err != nil {
t.Fatalf("Error getting blueChildOfRedBlock: %+v", err)
}
blockE, err := testConsensus.GetBlock(blockHashF)
blockE, _, err := testConsensus.GetBlock(blockHashF)
if err != nil {
t.Fatalf("Error getting blockE: %+v", err)
}
redBlock, err := testConsensus.GetBlock(redHash)
redBlock, _, err := testConsensus.GetBlock(redHash)
if err != nil {
t.Fatalf("Error getting redBlock: %+v", err)
}
_, err = testConsensus.GetBlock(blockHashG)
_, found, err := testConsensus.GetBlock(blockHashG)
if err != nil {
t.Fatalf("Error getting blockF: %+v", err)
t.Fatalf("Error getting blockG: %+v", err)
}
if !found {
t.Fatalf("block G is missing")
}
updatedDAAScoreVirtualBlock := consensusConfig.GenesisBlock.Header.DAAScore() + 26
//We expect the second transaction in the "blue block" (blueChildOfRedBlock) to be accepted because the merge set is ordered topologically
//and the red block is ordered topologically before the "blue block" so the input is known in the UTXOSet.

View File

@@ -205,37 +205,37 @@ func TestBlockWindow(t *testing.T) {
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "C", "D", "H", "G", "B"},
expectedWindow: []string{"F", "C", "H", "D", "B", "G"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "C", "D", "H", "G", "B"},
expectedWindow: []string{"I", "F", "C", "H", "D", "B", "G"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "C", "D", "H", "G", "B"},
expectedWindow: []string{"J", "I", "F", "C", "H", "D", "B", "G"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "C", "D", "H", "G", "B"},
expectedWindow: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "C", "D", "H", "G", "B"},
expectedWindow: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "G"},
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"},
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"},
},
},
dagconfig.SimnetParams.Name: {

View File

@@ -132,7 +132,7 @@ func TestDifficulty(t *testing.T) {
case dagconfig.TestnetParams.Name:
expectedBits = uint32(0x1e7f1441)
case dagconfig.DevnetParams.Name:
expectedBits = uint32(0x207f1441)
expectedBits = uint32(0x1f4e54ab)
case dagconfig.MainnetParams.Name:
expectedBits = uint32(0x1d02c50f)
}

View File

@@ -30,14 +30,14 @@ func (bg *blockGHOSTDAGData) toModel() *externalapi.BlockGHOSTDAGData {
//
// 1) |anticone-of-candidate-block ∩ blue-set-of-newBlock| ≤ K
//
// 2) For every blue block in blue-set-of-newBlock:
// |(anticone-of-blue-block ∩ blue-set-newBlock) {candidate-block}| ≤ K.
// We validate this condition by maintaining a map BluesAnticoneSizes for
// each block which holds all the blue anticone sizes that were affected by
// the new added blue blocks.
// So to find out what is |anticone-of-blue ∩ blue-set-of-newBlock| we just iterate in
// the selected parent chain of the new block until we find an existing entry in
// BluesAnticoneSizes.
// 2. For every blue block in blue-set-of-newBlock:
// |(anticone-of-blue-block ∩ blue-set-newBlock) {candidate-block}| ≤ K.
// We validate this condition by maintaining a map BluesAnticoneSizes for
// each block which holds all the blue anticone sizes that were affected by
// the new added blue blocks.
// So to find out what is |anticone-of-blue ∩ blue-set-of-newBlock| we just iterate in
// the selected parent chain of the new block until we find an existing entry in
// BluesAnticoneSizes.
//
// For further details see the article https://eprint.iacr.org/2018/104.pdf
func (gm *ghostdagManager) GHOSTDAG(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) error {

View File

@@ -38,7 +38,7 @@ func TestPruning(t *testing.T) {
"dag-for-test-pruning.json": {
dagconfig.MainnetParams.Name: "503",
dagconfig.TestnetParams.Name: "503",
dagconfig.DevnetParams.Name: "503",
dagconfig.DevnetParams.Name: "502",
dagconfig.SimnetParams.Name: "503",
},
}

View File

@@ -768,6 +768,114 @@ func (pm *pruningManager) calculateDiffBetweenPreviousAndCurrentPruningPoints(st
return nil, errors.Errorf("previous pruning point doesn't exist")
}
previousPruningHash, err := pm.pruningStore.PruningPointByIndex(pm.databaseContext, stagingArea, pruningPointIndex-1)
if err != nil {
return nil, err
}
currentPruningGhostDAG, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, currentPruningHash, false)
if err != nil {
return nil, err
}
previousPruningGhostDAG, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, previousPruningHash, false)
if err != nil {
return nil, err
}
currentPruningCurrentDiffChild := currentPruningHash
previousPruningCurrentDiffChild := previousPruningHash
// We need to use BlueWork because it's the only thing that's monotonic in the whole DAG
// We use the BlueWork to know which point is currently lower on the DAG so we can keep climbing its children,
// that way we keep climbing on the lowest point until they both reach the exact same descendant
currentPruningCurrentDiffChildBlueWork := currentPruningGhostDAG.BlueWork()
previousPruningCurrentDiffChildBlueWork := previousPruningGhostDAG.BlueWork()
var diffHashesFromPrevious []*externalapi.DomainHash
var diffHashesFromCurrent []*externalapi.DomainHash
for {
// if currentPruningCurrentDiffChildBlueWork > previousPruningCurrentDiffChildBlueWork
if currentPruningCurrentDiffChildBlueWork.Cmp(previousPruningCurrentDiffChildBlueWork) == 1 {
diffHashesFromPrevious = append(diffHashesFromPrevious, previousPruningCurrentDiffChild)
previousPruningCurrentDiffChild, err = pm.utxoDiffStore.UTXODiffChild(pm.databaseContext, stagingArea, previousPruningCurrentDiffChild)
if err != nil {
return nil, err
}
diffChildGhostDag, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, previousPruningCurrentDiffChild, false)
if err != nil {
return nil, err
}
previousPruningCurrentDiffChildBlueWork = diffChildGhostDag.BlueWork()
} else if currentPruningCurrentDiffChild.Equal(previousPruningCurrentDiffChild) {
break
} else {
diffHashesFromCurrent = append(diffHashesFromCurrent, currentPruningCurrentDiffChild)
currentPruningCurrentDiffChild, err = pm.utxoDiffStore.UTXODiffChild(pm.databaseContext, stagingArea, currentPruningCurrentDiffChild)
if err != nil {
return nil, err
}
diffChildGhostDag, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, currentPruningCurrentDiffChild, false)
if err != nil {
return nil, err
}
currentPruningCurrentDiffChildBlueWork = diffChildGhostDag.BlueWork()
}
}
// The order in which we apply the diffs should be from top to bottom, but we traversed from bottom to top
// so we apply the diffs in reverse order.
oldDiff := utxo.NewMutableUTXODiff()
for i := len(diffHashesFromPrevious) - 1; i >= 0; i-- {
utxoDiff, err := pm.utxoDiffStore.UTXODiff(pm.databaseContext, stagingArea, diffHashesFromPrevious[i])
if err != nil {
return nil, err
}
err = oldDiff.WithDiffInPlace(utxoDiff)
if err != nil {
return nil, err
}
}
newDiff := utxo.NewMutableUTXODiff()
for i := len(diffHashesFromCurrent) - 1; i >= 0; i-- {
utxoDiff, err := pm.utxoDiffStore.UTXODiff(pm.databaseContext, stagingArea, diffHashesFromCurrent[i])
if err != nil {
return nil, err
}
err = newDiff.WithDiffInPlace(utxoDiff)
if err != nil {
return nil, err
}
}
return oldDiff.DiffFrom(newDiff.ToImmutable())
}
// This function takes 2 chain blocks (currentPruningHash, previousPruningHash) and finds
// the UTXO diff between them by iterating over acceptance data of the chain blocks in between.
func (pm *pruningManager) calculateDiffBetweenPreviousAndCurrentPruningPointsUsingAcceptanceData(stagingArea *model.StagingArea, currentPruningHash *externalapi.DomainHash) (externalapi.UTXODiff, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.calculateDiffBetweenPreviousAndCurrentPruningPoints__UsingAcceptanceData")
defer onEnd()
if currentPruningHash.Equal(pm.genesisHash) {
iter, err := pm.consensusStateManager.RestorePastUTXOSetIterator(stagingArea, currentPruningHash)
if err != nil {
return nil, err
}
set := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry)
for ok := iter.First(); ok; ok = iter.Next() {
outpoint, entry, err := iter.Get()
if err != nil {
return nil, err
}
set[*outpoint] = entry
}
return utxo.NewUTXODiffFromCollections(utxo.NewUTXOCollection(set), utxo.NewUTXOCollection(make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry)))
}
pruningPointIndex, err := pm.pruningStore.CurrentPruningPointIndex(pm.databaseContext, stagingArea)
if err != nil {
return nil, err
}
if pruningPointIndex == 0 {
return nil, errors.Errorf("previous pruning point doesn't exist")
}
previousPruningHash, err := pm.pruningStore.PruningPointByIndex(pm.databaseContext, stagingArea, pruningPointIndex-1)
if err != nil {
return nil, err
@@ -893,7 +1001,13 @@ func (pm *pruningManager) updatePruningPoint() error {
log.Debugf("Restoring the pruning point UTXO set")
utxoSetDiff, err := pm.calculateDiffBetweenPreviousAndCurrentPruningPoints(stagingArea, pruningPoint)
if err != nil {
return err
log.Infof("Calculating pruning points diff through utxo diff children failed %s. Falling back to calculation "+
"through acceptance data", err)
utxoSetDiff, err = pm.calculateDiffBetweenPreviousAndCurrentPruningPointsUsingAcceptanceData(stagingArea, pruningPoint)
if err != nil {
return err
}
}
log.Debugf("Updating the pruning point UTXO set")
err = pm.pruningStore.UpdatePruningPointUTXOSet(pm.databaseContext, utxoSetDiff)

View File

@@ -12,13 +12,13 @@ import (
// interval contains B's interval, it replaces it.
//
// Notes:
// * Intervals never intersect unless one contains the other
// (this follows from the tree structure and the indexing rule).
// * Since node.FutureCoveringSet is kept ordered, a binary search can be
// used for insertion/queries.
// * Although reindexing may change a block's interval, the
// is-superset relation will by definition
// be always preserved.
// - Intervals never intersect unless one contains the other
// (this follows from the tree structure and the indexing rule).
// - Since node.FutureCoveringSet is kept ordered, a binary search can be
// used for insertion/queries.
// - Although reindexing may change a block's interval, the
// is-superset relation will by definition
// be always preserved.
func (rt *reachabilityManager) insertToFutureCoveringSet(stagingArea *model.StagingArea, node, futureNode *externalapi.DomainHash) error {
reachabilityData, err := rt.reachabilityDataForInsertion(stagingArea, node)
if err != nil {

View File

@@ -161,7 +161,9 @@ func intervalSplitWithExponentialBias(ri *model.ReachabilityInterval, sizes []ui
// exponentialFractions returns a fraction of each size in sizes
// as follows:
// fraction[i] = 2^size[i] / sum_j(2^size[j])
//
// fraction[i] = 2^size[i] / sum_j(2^size[j])
//
// In the code below the above equation is divided by 2^max(size)
// to avoid exploding numbers. Note that in 1 / 2^(max(size)-size[i])
// we divide 1 by potentially a very large number, which will

View File

@@ -42,13 +42,13 @@ Core (BFS) algorithms used during reindexing
// and populates the provided subTreeSizeMap with the results.
// It is equivalent to the following recursive implementation:
//
// func (rt *reachabilityManager) countSubtrees(node *model.ReachabilityTreeNode) uint64 {
// subtreeSize := uint64(0)
// for _, child := range node.children {
// subtreeSize += child.countSubtrees()
// }
// return subtreeSize + 1
// }
// func (rt *reachabilityManager) countSubtrees(node *model.ReachabilityTreeNode) uint64 {
// subtreeSize := uint64(0)
// for _, child := range node.children {
// subtreeSize += child.countSubtrees()
// }
// return subtreeSize + 1
// }
//
// However, we are expecting (linearly) deep trees, and so a
// recursive stack-based approach is inefficient and will hit

View File

@@ -350,6 +350,7 @@ func (v *transactionValidator) validateTransactionSigOpCounts(tx *externalapi.Do
sigScript := input.SignatureScript
isP2SH := txscript.IsPayToScriptHash(utxoEntry.ScriptPublicKey())
sigOpCount := txscript.GetPreciseSigOpCount(sigScript, utxoEntry.ScriptPublicKey(), isP2SH)
if sigOpCount != int(input.SigOpCount) {
return errors.Wrapf(ruleerrors.ErrWrongSigOpCount,
"input %d specifies SigOpCount %d while actual SigOpCount is %d",

View File

@@ -23,7 +23,7 @@ func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.Do
if err != nil {
return err
}
err = v.checkCoinbaseLength(tx)
err = v.checkCoinbaseInIsolation(tx)
if err != nil {
return err
}
@@ -114,7 +114,7 @@ func (v *transactionValidator) checkDuplicateTransactionInputs(tx *externalapi.D
return nil
}
func (v *transactionValidator) checkCoinbaseLength(tx *externalapi.DomainTransaction) error {
func (v *transactionValidator) checkCoinbaseInIsolation(tx *externalapi.DomainTransaction) error {
if !transactionhelper.IsCoinBase(tx) {
return nil
}
@@ -127,6 +127,22 @@ func (v *transactionValidator) checkCoinbaseLength(tx *externalapi.DomainTransac
payloadLen, v.maxCoinbasePayloadLength)
}
if len(tx.Inputs) != 0 {
return errors.Wrap(ruleerrors.ErrCoinbaseWithInputs, "coinbase has inputs")
}
outputsLimit := uint64(v.ghostdagK) + 2
if uint64(len(tx.Outputs)) > outputsLimit {
return errors.Wrapf(ruleerrors.ErrCoinbaseTooManyOutputs, "coinbase has too many outputs: got %d where the limit is %d", len(tx.Outputs), outputsLimit)
}
for i, output := range tx.Outputs {
if len(output.ScriptPublicKey.Script) > int(v.coinbasePayloadScriptPublicKeyMaxLength) {
return errors.Wrapf(ruleerrors.ErrCoinbaseTooLongScriptPublicKey, "coinbase output %d has a too long script public key", i)
}
}
return nil
}

View File

@@ -76,7 +76,7 @@ func TestValidateTransactionInIsolationAndPopulateMass(t *testing.T) {
subnetworks.SubnetworkIDNative,
&txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, nil},
nil,
nil, 0},
ruleerrors.ErrCoinbaseWithInputs, 0},
{"no inputs coinbase",
0,
1,

View File

@@ -2,6 +2,7 @@ package transactionvalidator
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
"github.com/kaspanet/kaspad/util/txmass"
)
@@ -11,22 +12,26 @@ const sigCacheSize = 10_000
// transactionValidator exposes a set of validation classes, after which
// it's possible to determine whether either a transaction is valid
type transactionValidator struct {
blockCoinbaseMaturity uint64
databaseContext model.DBReader
pastMedianTimeManager model.PastMedianTimeManager
ghostdagDataStore model.GHOSTDAGDataStore
daaBlocksStore model.DAABlocksStore
enableNonNativeSubnetworks bool
maxCoinbasePayloadLength uint64
sigCache *txscript.SigCache
sigCacheECDSA *txscript.SigCacheECDSA
txMassCalculator *txmass.Calculator
blockCoinbaseMaturity uint64
databaseContext model.DBReader
pastMedianTimeManager model.PastMedianTimeManager
ghostdagDataStore model.GHOSTDAGDataStore
daaBlocksStore model.DAABlocksStore
enableNonNativeSubnetworks bool
maxCoinbasePayloadLength uint64
ghostdagK externalapi.KType
coinbasePayloadScriptPublicKeyMaxLength uint8
sigCache *txscript.SigCache
sigCacheECDSA *txscript.SigCacheECDSA
txMassCalculator *txmass.Calculator
}
// New instantiates a new TransactionValidator
func New(blockCoinbaseMaturity uint64,
enableNonNativeSubnetworks bool,
maxCoinbasePayloadLength uint64,
ghostdagK externalapi.KType,
coinbasePayloadScriptPublicKeyMaxLength uint8,
databaseContext model.DBReader,
pastMedianTimeManager model.PastMedianTimeManager,
ghostdagDataStore model.GHOSTDAGDataStore,
@@ -34,15 +39,17 @@ func New(blockCoinbaseMaturity uint64,
txMassCalculator *txmass.Calculator) model.TransactionValidator {
return &transactionValidator{
blockCoinbaseMaturity: blockCoinbaseMaturity,
enableNonNativeSubnetworks: enableNonNativeSubnetworks,
maxCoinbasePayloadLength: maxCoinbasePayloadLength,
databaseContext: databaseContext,
pastMedianTimeManager: pastMedianTimeManager,
ghostdagDataStore: ghostdagDataStore,
daaBlocksStore: daaBlocksStore,
sigCache: txscript.NewSigCache(sigCacheSize),
sigCacheECDSA: txscript.NewSigCacheECDSA(sigCacheSize),
txMassCalculator: txMassCalculator,
blockCoinbaseMaturity: blockCoinbaseMaturity,
enableNonNativeSubnetworks: enableNonNativeSubnetworks,
maxCoinbasePayloadLength: maxCoinbasePayloadLength,
ghostdagK: ghostdagK,
coinbasePayloadScriptPublicKeyMaxLength: coinbasePayloadScriptPublicKeyMaxLength,
databaseContext: databaseContext,
pastMedianTimeManager: pastMedianTimeManager,
ghostdagDataStore: ghostdagDataStore,
daaBlocksStore: daaBlocksStore,
sigCache: txscript.NewSigCache(sigCacheSize),
sigCacheECDSA: txscript.NewSigCacheECDSA(sigCacheSize),
txMassCalculator: txMassCalculator,
}
}

View File

@@ -109,18 +109,6 @@ func TestValidateTransactionInContextAndPopulateFee(t *testing.T) {
0),
}
txInputWithBadSigOpCount := externalapi.DomainTransactionInput{
PreviousOutpoint: prevOutPoint,
SignatureScript: []byte{},
Sequence: constants.MaxTxInSequenceNum,
SigOpCount: 2,
UTXOEntry: utxo.NewUTXOEntry(
100_000_000, // 1 KAS
scriptPublicKey,
true,
uint64(5)),
}
txOutput := externalapi.DomainTransactionOutput{
Value: 100000000, // 1 KAS
ScriptPublicKey: scriptPublicKey,
@@ -193,13 +181,6 @@ func TestValidateTransactionInContextAndPopulateFee(t *testing.T) {
SubnetworkID: subnetworks.SubnetworkIDRegistry,
Gas: 0,
LockTime: 0}
txWithBadSigOpCount := externalapi.DomainTransaction{
Version: constants.MaxTransactionVersion,
Inputs: []*externalapi.DomainTransactionInput{&txInputWithBadSigOpCount},
Outputs: []*externalapi.DomainTransactionOutput{&txOutput},
SubnetworkID: subnetworks.SubnetworkIDRegistry,
Gas: 0,
LockTime: 0}
stagingArea := model.NewStagingArea()
@@ -266,13 +247,6 @@ func TestValidateTransactionInContextAndPopulateFee(t *testing.T) {
isValid: false,
expectedError: ruleerrors.ErrScriptValidation,
},
{ // the SigOpCount in the input is wrong, and hence invalid
name: "checkTransactionSigOpCounts",
tx: &txWithBadSigOpCount,
povBlockHash: povBlockHash,
isValid: false,
expectedError: ruleerrors.ErrWrongSigOpCount,
},
}
for _, test := range tests {
@@ -344,12 +318,12 @@ func TestSigningTwoInputs(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
block2, err := tc.GetBlock(block2Hash)
block2, _, err := tc.GetBlock(block2Hash)
if err != nil {
t.Fatalf("Error getting block2: %+v", err)
}
block3, err := tc.GetBlock(block3Hash)
block3, _, err := tc.GetBlock(block3Hash)
if err != nil {
t.Fatalf("Error getting block3: %+v", err)
}
@@ -470,12 +444,12 @@ func TestSigningTwoInputsECDSA(t *testing.T) {
t.Fatalf("AddBlock: %+v", err)
}
block2, err := tc.GetBlock(block2Hash)
block2, _, err := tc.GetBlock(block2Hash)
if err != nil {
t.Fatalf("Error getting block2: %+v", err)
}
block3, err := tc.GetBlock(block3Hash)
block3, _, err := tc.GetBlock(block3Hash)
if err != nil {
t.Fatalf("Error getting block3: %+v", err)
}

View File

@@ -241,6 +241,9 @@ var (
ErrPruningProofEmpty = newRuleError("ErrPruningProofEmpty")
ErrWrongCoinbaseSubsidy = newRuleError("ErrWrongCoinbaseSubsidy")
ErrWrongBlockVersion = newRuleError("ErrWrongBlockVersion")
ErrCoinbaseWithInputs = newRuleError("ErrCoinbaseWithInputs")
ErrCoinbaseTooManyOutputs = newRuleError("ErrCoinbaseTooManyOutputs")
ErrCoinbaseTooLongScriptPublicKey = newRuleError("ErrCoinbaseTooLongScriptPublicKey")
)
// RuleError identifies a rule violation. It is used to indicate that

View File

@@ -43,7 +43,7 @@ func TestCheckLockTimeVerifyConditionedByDAAScore(t *testing.T) {
if err != nil {
t.Fatalf("Error creating blockD: %v", err)
}
blockD, err := testConsensus.GetBlock(blockDHash)
blockD, _, err := testConsensus.GetBlock(blockDHash)
if err != nil {
t.Fatalf("Failed getting blockD: %v", err)
}
@@ -150,7 +150,7 @@ func TestCheckLockTimeVerifyConditionedByDAAScoreWithWrongLockTime(t *testing.T)
if err != nil {
t.Fatalf("Error creating blockD: %v", err)
}
blockD, err := testConsensus.GetBlock(blockDHash)
blockD, _, err := testConsensus.GetBlock(blockDHash)
if err != nil {
t.Fatalf("Failed getting blockD: %v", err)
}
@@ -252,7 +252,7 @@ func TestCheckLockTimeVerifyConditionedByAbsoluteTime(t *testing.T) {
if err != nil {
t.Fatalf("Error creating blockD: %v", err)
}
blockD, err := testConsensus.GetBlock(blockDHash)
blockD, _, err := testConsensus.GetBlock(blockDHash)
if err != nil {
t.Fatalf("Failed getting blockD: %v", err)
}
@@ -283,7 +283,7 @@ func TestCheckLockTimeVerifyConditionedByAbsoluteTime(t *testing.T) {
if err != nil {
t.Fatalf("Error creating blockE: %v", err)
}
blockE, err := testConsensus.GetBlock(blockEHash)
blockE, _, err := testConsensus.GetBlock(blockEHash)
if err != nil {
t.Fatalf("Failed getting blockE: %v", err)
}
@@ -380,7 +380,7 @@ func TestCheckLockTimeVerifyConditionedByAbsoluteTimeWithWrongLockTime(t *testin
if err != nil {
t.Fatalf("Error creating blockD: %v", err)
}
blockD, err := testConsensus.GetBlock(blockDHash)
blockD, _, err := testConsensus.GetBlock(blockDHash)
if err != nil {
t.Fatalf("Failed getting blockD: %v", err)
}
@@ -411,7 +411,7 @@ func TestCheckLockTimeVerifyConditionedByAbsoluteTimeWithWrongLockTime(t *testin
if err != nil {
t.Fatalf("Error creating blockE: %v", err)
}
blockE, err := testConsensus.GetBlock(blockEHash)
blockE, _, err := testConsensus.GetBlock(blockEHash)
if err != nil {
t.Fatalf("Failed getting blockE: %v", err)
}

View File

@@ -3,6 +3,7 @@ package consensushashing_test
import (
"encoding/hex"
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"testing"
"github.com/kaspanet/go-secp256k1"
@@ -108,73 +109,73 @@ func TestCalculateSignatureHashSchnorr(t *testing.T) {
// sigHashAll
{name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0,
expectedSignatureHash: "b363613fe99c8bb1d3712656ec8dfaea621ee6a9a95d851aec5bb59363b03f5e"},
expectedSignatureHash: "03b7ac6927b2b67100734c3cc313ff8c2e8b3ce3e746d46dd660b706a916b1f5"},
{name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0,
modificationFunction: modifyInput(1), // should change the hash
expectedSignatureHash: "34ae2989115068fc73a1b2cae023ad79c3cdb5cbe532a46fa91d9181a36990fd"},
expectedSignatureHash: "a9f563d86c0ef19ec2e4f483901d202e90150580b6123c3d492e26e7965f488c"},
{name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0,
modificationFunction: modifyOutput(1), // should change the hash
expectedSignatureHash: "043441346c66e461f9f1dc618ebbfe7fd87f74e363f267bf8b3243a7bfe0c870"},
expectedSignatureHash: "aad2b61bd2405dfcf7294fc2be85f325694f02dda22d0af30381cb50d8295e0a"},
{name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0,
modificationFunction: modifySequence(1), // should change the hash
expectedSignatureHash: "de8d3d46bc8c51f51a1b85470f8bf01ee38214901d6d514fd13bafe4efc8aa0f"},
expectedSignatureHash: "0818bd0a3703638d4f01014c92cf866a8903cab36df2fa2506dc0d06b94295e8"},
{name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
expectedSignatureHash: "19897764789644c2ac5cd6d83f7a78a1208f3ce6d15e8788f9b9fa6d7c91d8f1"},
expectedSignatureHash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2"},
{name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyInput(0), // should change the hash
expectedSignatureHash: "f1ff39b1b9ce86d2fdfac61a75f3b13e98fe5e0f1057b4ec69245031ecf7be37"},
expectedSignatureHash: "d09cb639f335ee69ac71f2ad43fd9e59052d38a7d0638de4cf989346588a7c38"},
{name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyInput(1), // shouldn't change the hash
expectedSignatureHash: "19897764789644c2ac5cd6d83f7a78a1208f3ce6d15e8788f9b9fa6d7c91d8f1"},
expectedSignatureHash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2"},
{name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
modificationFunction: modifySequence(1), // shouldn't change the hash
expectedSignatureHash: "19897764789644c2ac5cd6d83f7a78a1208f3ce6d15e8788f9b9fa6d7c91d8f1"},
expectedSignatureHash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2"},
// sigHashNone
{name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0,
expectedSignatureHash: "7a5b0fef8219bb72ef1912db5335c71c4fdfac873a6096c24b2f0b5c3774349c"},
expectedSignatureHash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba"},
{name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0,
modificationFunction: modifyOutput(1), // shouldn't change the hash
expectedSignatureHash: "7a5b0fef8219bb72ef1912db5335c71c4fdfac873a6096c24b2f0b5c3774349c"},
expectedSignatureHash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba"},
{name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0,
modificationFunction: modifySequence(0), // should change the hash
expectedSignatureHash: "852011233473ee1e61a9d0e51fb5ecd65857ceca65ebea4c54b6d557f2006f2a"},
expectedSignatureHash: "d9efdd5edaa0d3fd0133ee3ab731d8c20e0a1b9f3c0581601ae2075db1109268"},
{name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0,
modificationFunction: modifySequence(1), // shouldn't change the hash
expectedSignatureHash: "7a5b0fef8219bb72ef1912db5335c71c4fdfac873a6096c24b2f0b5c3774349c"},
expectedSignatureHash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba"},
{name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
expectedSignatureHash: "1624d46e77d09cb09e4a7dcbf419b8c37671bd0274b9dc6aba0668922da83935"},
expectedSignatureHash: "06aa9f4239491e07bb2b6bda6b0657b921aeae51e193d2c5bf9e81439cfeafa0"},
{name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyAmountSpent(0), // should change the hash
expectedSignatureHash: "235f0766528865a4c478a46b0b3eef6b4760c6a05c792a452c06fab9ad0bd57c"},
expectedSignatureHash: "f07f45f3634d3ea8c0f2cb676f56e20993edf9be07a83bf0dfdb3debcf1441bf"},
{name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyScriptPublicKey(0), // should change the hash
expectedSignatureHash: "42b408acc6df78f1b1aef605339233af129b6e656788e8c93712e4954d28583d"},
expectedSignatureHash: "20a525c54dc33b2a61201f05233c086dbe8e06e9515775181ed96550b4f2d714"},
// sigHashSingle
{name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0,
expectedSignatureHash: "c9f7adaa7a22af87195183cf1f10e368429139f16069597d5631a0f522e320a5"},
expectedSignatureHash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005"},
{name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifyOutput(0), // should change the hash
expectedSignatureHash: "af40fbd0ac061c586484c4f266d44007c0715eb0b80d20eb89be65325db05716"},
expectedSignatureHash: "0fcaca1211f7ea44997717eb84c04c9c807db8b59797bc6800c2ccb135a5271c"},
{name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifyOutput(1), // shouldn't change the hash
expectedSignatureHash: "c9f7adaa7a22af87195183cf1f10e368429139f16069597d5631a0f522e320a5"},
expectedSignatureHash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005"},
{name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifySequence(0), // should change the hash
expectedSignatureHash: "c40f48b35fc933d5930c612c420e80bad336388126aaba6073588e31d95aca2c"},
expectedSignatureHash: "83796d22879718eee1165d4aace667bb6778075dab579c32c57be945f466a451"},
{name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifySequence(1), // shouldn't change the hash
expectedSignatureHash: "c9f7adaa7a22af87195183cf1f10e368429139f16069597d5631a0f522e320a5"},
expectedSignatureHash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005"},
{name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2,
expectedSignatureHash: "145487f676cd1d5f8042b9d042cc63bc0ecdf20563d324fa0b847714eeb94816"},
expectedSignatureHash: "022ad967192f39d8d5895d243e025ec14cc7a79708c5e364894d4eff3cecb1b0"},
{name: "native-single-2-no-corresponding-output-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 2,
modificationFunction: modifyOutput(1), // shouldn't change the hash
expectedSignatureHash: "145487f676cd1d5f8042b9d042cc63bc0ecdf20563d324fa0b847714eeb94816"},
expectedSignatureHash: "022ad967192f39d8d5895d243e025ec14cc7a79708c5e364894d4eff3cecb1b0"},
{name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0,
expectedSignatureHash: "4f3f758e1ed9c438dcc241efd31dd07e6bf2e11e900e105eebd4d337391e48fe"},
expectedSignatureHash: "43b20aba775050cf9ba8d5e48fc7ed2dc6c071d23f30382aea58b7c59cfb8ed7"},
{name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2,
expectedSignatureHash: "200207998528ab3b58cbdfe578cd079572eb3093e68fb5c728e505b847e91c64"},
expectedSignatureHash: "846689131fb08b77f83af1d3901076732ef09d3f8fdff945be89aa4300562e5f"},
// subnetwork transaction
{name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0,
@@ -230,73 +231,73 @@ func TestCalculateSignatureHashECDSA(t *testing.T) {
// sigHashAll
{name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0,
expectedSignatureHash: "6ec7f4949d0c095d78bf41475310fd38eb054f3e7c4240daf91ea888e4eb9a30"},
expectedSignatureHash: "1d679268414c20ffe952e3c255befd892e60e86ae1657fce8a20225e5dc87d64"},
{name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0,
modificationFunction: modifyInput(1), // should change the hash
expectedSignatureHash: "34fcc1cb538736c473c1778eba4df5f88c3d9f27508b0d842ec2348d097cd103"},
expectedSignatureHash: "c573469b9ec6551507371d26eaa75417905420577f56d0277c4234a99f2305d7"},
{name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0,
modificationFunction: modifyOutput(1), // should change the hash
expectedSignatureHash: "faf02d20d32f0e4536dfb0a86c67f97b394c11a34069bd74a2f7533ea964b10f"},
expectedSignatureHash: "a92450b0662c120db3993b6bb258d06d2bcb983aa591d85f97adf8b7207a5db5"},
{name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0,
modificationFunction: modifySequence(1), // should change the hash
expectedSignatureHash: "25484c5dcc89d21e5b5858847964c8c2938d5090be54b21a590099ce4f792b14"},
expectedSignatureHash: "c7a7524096499e4401a1592f892bada1afe7f7d276c4f0e691c993e17c03cf7d"},
{name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
expectedSignatureHash: "458a711830a66d592c89845cd6406b525b5f89f4d9ca50abbdbb48dbb5adbb07"},
expectedSignatureHash: "13270aeb5b56d844d064d5d2cf06af7dbd0341fd55069b9af56d5e3c99f2eddd"},
{name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyInput(0), // should change the hash
expectedSignatureHash: "67157f1984a881c71ea92c9959da1b856383489a8bb0150783cdc4d58bca95ea"},
expectedSignatureHash: "981959e8c427ba4a06c3d53abc93514ba179d8cc7e94daeb4f516a0c2c685f86"},
{name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyInput(1), // shouldn't change the hash
expectedSignatureHash: "458a711830a66d592c89845cd6406b525b5f89f4d9ca50abbdbb48dbb5adbb07"},
expectedSignatureHash: "13270aeb5b56d844d064d5d2cf06af7dbd0341fd55069b9af56d5e3c99f2eddd"},
{name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
modificationFunction: modifySequence(1), // shouldn't change the hash
expectedSignatureHash: "458a711830a66d592c89845cd6406b525b5f89f4d9ca50abbdbb48dbb5adbb07"},
expectedSignatureHash: "13270aeb5b56d844d064d5d2cf06af7dbd0341fd55069b9af56d5e3c99f2eddd"},
// sigHashNone
{name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0,
expectedSignatureHash: "bf92d39b8381e49d4b2f37a7d2e2d9b4f126b6659cb873b84ae3db8910cd9664"},
expectedSignatureHash: "a45955ca970039160bb91b1ea42e070b4ff21598654aad91c562e8b9af922c5f"},
{name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0,
modificationFunction: modifyOutput(1), // shouldn't change the hash
expectedSignatureHash: "bf92d39b8381e49d4b2f37a7d2e2d9b4f126b6659cb873b84ae3db8910cd9664"},
expectedSignatureHash: "a45955ca970039160bb91b1ea42e070b4ff21598654aad91c562e8b9af922c5f"},
{name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0,
modificationFunction: modifySequence(0), // should change the hash
expectedSignatureHash: "20550f85a6ac0d4b20ebb0d8df9b1f4ec0ecb3df5adf539c9d6ad9af03f712d6"},
expectedSignatureHash: "e1a430a24d77bc259ae572e1505dd67d3444ba0ffbc7918e06ae7e907e575adb"},
{name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0,
modificationFunction: modifySequence(1), // shouldn't change the hash
expectedSignatureHash: "bf92d39b8381e49d4b2f37a7d2e2d9b4f126b6659cb873b84ae3db8910cd9664"},
expectedSignatureHash: "a45955ca970039160bb91b1ea42e070b4ff21598654aad91c562e8b9af922c5f"},
{name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
expectedSignatureHash: "a048ec7a396397e1357b42905f26c51d0ec6c0943298ff4f2b8707ec3e8e1aa0"},
expectedSignatureHash: "6bae2a0f1f7b9fd59804f4720a1a918be31b7ec12e184585fa16bda8c7f8c35c"},
{name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyAmountSpent(0), // should change the hash
expectedSignatureHash: "66125d23d3dc9711683a6dbc96d4d4411af41e71f92596e9983ea8c5e3a04753"},
expectedSignatureHash: "6653d3d882d2ffc1c3ff5b7ccf07f7970c5973b824abb5b117803809c5a884c7"},
{name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
modificationFunction: modifyScriptPublicKey(0), // should change the hash
expectedSignatureHash: "0ba5f527f8408b252eb77ea54efe63b831c736fea4bed58fc47c4ceaabf3f6cf"},
expectedSignatureHash: "da3cb9094d905de69b3881cf8d4e2d5268bcf029dec5b62a972fcab90e6abde9"},
// sigHashSingle
{name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0,
expectedSignatureHash: "b21ec5c5e1830f8b9b3cb13bfbd542318a17d89d9844bd64167696ca36374f7f"},
expectedSignatureHash: "964d03d8477dd468f3d9933676b5b4a976a68fee1760eae037be4247c36cc207"},
{name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifyOutput(0), // should change the hash
expectedSignatureHash: "e15914f6b22979f70162f5c57b3ad7ceff91b8a2356960f66a23dc8e602303fe"},
expectedSignatureHash: "7c51b4a7c6a6e786b1c420c859c2853131d7041b8ba8de72cbcd026b2e0d511b"},
{name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifyOutput(1), // shouldn't change the hash
expectedSignatureHash: "b21ec5c5e1830f8b9b3cb13bfbd542318a17d89d9844bd64167696ca36374f7f"},
expectedSignatureHash: "964d03d8477dd468f3d9933676b5b4a976a68fee1760eae037be4247c36cc207"},
{name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifySequence(0), // should change the hash
expectedSignatureHash: "a09f20428456475bc5fcff07242416d439faa0dec37152e31a8546874f323473"},
expectedSignatureHash: "d31e5a9e71560d2f66483e7e4e7d41418b66cd22814450848a2d8fa78045d6a0"},
{name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0,
modificationFunction: modifySequence(1), // shouldn't change the hash
expectedSignatureHash: "b21ec5c5e1830f8b9b3cb13bfbd542318a17d89d9844bd64167696ca36374f7f"},
expectedSignatureHash: "964d03d8477dd468f3d9933676b5b4a976a68fee1760eae037be4247c36cc207"},
{name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2,
expectedSignatureHash: "7cc3c80a6250599e47e4ceca66e3670b4fc74a009aba2b7df737bc37e8cb5b79"},
expectedSignatureHash: "667b6b65682a6e1e14aec699a177d22ce1392661828e54dcd97cd83b05233d41"},
{name: "native-single-2-no-corresponding-output-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 2,
modificationFunction: modifyOutput(1), // shouldn't change the hash
expectedSignatureHash: "7cc3c80a6250599e47e4ceca66e3670b4fc74a009aba2b7df737bc37e8cb5b79"},
expectedSignatureHash: "667b6b65682a6e1e14aec699a177d22ce1392661828e54dcd97cd83b05233d41"},
{name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0,
expectedSignatureHash: "8040f5ebfc6c5a8285272d5e1956dd3036eaa9a7abec9b18cb1b614a015f2fc7"},
expectedSignatureHash: "a11c2fbcd4f09bffce9e5fca62323388a2cf9037fd3be66211c7869c067123a2"},
{name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2,
expectedSignatureHash: "5e1ac311544301aa6afa578f18e1d1871ffbc15915e01f25f2375715c3a3147d"},
expectedSignatureHash: "00f429dfb9150d7a96aa3f179bcc6f8fbf9bce481f00c6bb97af67e108e5d0ff"},
// subnetwork transaction
{name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0,
@@ -390,7 +391,7 @@ func generateTxs() (nativeTx, subnetworkTx *externalapi.DomainTransaction, err e
Inputs: txIns,
Outputs: txOuts,
LockTime: 1615462089000,
SubnetworkID: externalapi.DomainSubnetworkID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
SubnetworkID: subnetworks.SubnetworkIDNative,
}
subnetworkTx = &externalapi.DomainTransaction{
Version: 0,

View File

@@ -139,11 +139,19 @@ func writeTransactionInput(w io.Writer, ti *externalapi.DomainTransactionInput,
if encodingFlags&txEncodingExcludeSignatureScript != txEncodingExcludeSignatureScript {
err = writeVarBytes(w, ti.SignatureScript)
if err != nil {
return err
}
_, err = w.Write([]byte{ti.SigOpCount})
if err != nil {
return err
}
} else {
err = writeVarBytes(w, []byte{})
}
if err != nil {
return err
if err != nil {
return err
}
}
return binaryserializer.PutUint64(w, ti.Sequence)

View File

@@ -1,102 +0,0 @@
package consensushashing
import (
"fmt"
"testing"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
)
func TestTransactionHash(t *testing.T) {
tx := externalapi.DomainTransaction{0, []*externalapi.DomainTransactionInput{}, []*externalapi.DomainTransactionOutput{}, 0,
externalapi.DomainSubnetworkID{}, 0, []byte{}, 0, 0,
nil}
id := TransactionID(&tx)
fmt.Printf("%s\n", id)
tx_hash := TransactionHash(&tx)
fmt.Printf("%s\n\n", tx_hash)
inputs := []*externalapi.DomainTransactionInput{&externalapi.DomainTransactionInput{
PreviousOutpoint: externalapi.DomainOutpoint{
TransactionID: externalapi.DomainTransactionID{},
Index: 2,
},
SignatureScript: []byte{1, 2},
Sequence: 7,
SigOpCount: 5,
UTXOEntry: nil,
}}
tx = externalapi.DomainTransaction{1, inputs, []*externalapi.DomainTransactionOutput{}, 0,
externalapi.DomainSubnetworkID{}, 0, []byte{}, 0, 0,
nil}
id = TransactionID(&tx)
fmt.Printf("%s\n", id)
tx_hash = TransactionHash(&tx)
fmt.Printf("%s\n\n", tx_hash)
outputs := []*externalapi.DomainTransactionOutput{&externalapi.DomainTransactionOutput{
Value: 1564,
ScriptPublicKey: &externalapi.ScriptPublicKey{
Script: []byte{1, 2, 3, 4, 5},
Version: 7,
},
}}
tx = externalapi.DomainTransaction{1, inputs, outputs, 0,
externalapi.DomainSubnetworkID{}, 0, []byte{}, 0, 0,
nil}
id = TransactionID(&tx)
fmt.Printf("%s\n", id)
tx_hash = TransactionHash(&tx)
fmt.Printf("%s\n\n", tx_hash)
tx = externalapi.DomainTransaction{2, inputs, outputs, 54,
externalapi.DomainSubnetworkID{}, 3, []byte{}, 4, 7,
nil}
id = TransactionID(&tx)
fmt.Printf("%s\n", id)
tx_hash = TransactionHash(&tx)
fmt.Printf("%s\n\n", tx_hash)
transactionId, err := externalapi.NewDomainHashFromString("59b3d6dc6cdc660c389c3fdb5704c48c598d279cdf1bab54182db586a4c95dd5")
if err != nil {
t.Fatalf("%s", err)
}
inputs = []*externalapi.DomainTransactionInput{&externalapi.DomainTransactionInput{
PreviousOutpoint: externalapi.DomainOutpoint{
TransactionID: externalapi.DomainTransactionID(*transactionId),
Index: 2,
},
SignatureScript: []byte{1, 2},
Sequence: 7,
SigOpCount: 5,
UTXOEntry: nil,
}}
tx = externalapi.DomainTransaction{2, inputs, outputs, 54,
externalapi.DomainSubnetworkID{}, 3, []byte{}, 4, 7,
nil}
id = TransactionID(&tx)
fmt.Printf("%s\n", id)
tx_hash = TransactionHash(&tx)
fmt.Printf("%s\n\n", tx_hash)
tx = externalapi.DomainTransaction{2, inputs, outputs, 54,
subnetworks.SubnetworkIDCoinbase, 3, []byte{}, 4, 7,
nil}
id = TransactionID(&tx)
fmt.Printf("%s\n", id)
tx_hash = TransactionHash(&tx)
fmt.Printf("%s\n\n", tx_hash)
tx = externalapi.DomainTransaction{2, inputs, outputs, 54,
subnetworks.SubnetworkIDRegistry, 3, []byte{}, 4, 7,
nil}
id = TransactionID(&tx)
fmt.Printf("%s\n", id)
tx_hash = TransactionHash(&tx)
fmt.Printf("%s\n\n", tx_hash)
}

View File

@@ -272,7 +272,7 @@
"P2SH"
],
[
"Argument negative with by-blockheight nLockTime=0"
"Argument negative with by-DAAScore nLockTime=0"
],
[
[
@@ -564,7 +564,7 @@
"P2SH"
],
[
"Argument negative with by-blockheight txin.nSequence=0"
"Argument negative with by-DAAScore txin.nSequence=0"
],
[
[

View File

@@ -4,7 +4,7 @@ Package txscript implements the kaspa transaction script language.
This package provides data structures and functions to parse and execute
kaspa transaction scripts.
Script Overview
# Script Overview
Kaspa transaction scripts are written in a stack-base, FORTH-like language.
@@ -22,7 +22,7 @@ is used to prove the the spender is authorized to perform the transaction.
One benefit of using a scripting language is added flexibility in specifying
what conditions must be met in order to spend kaspa.
Errors
# Errors
Errors returned by this package are of type txscript.Error. This allows the
caller to programmatically determine the specific error by examining the

View File

@@ -272,10 +272,10 @@ func (e ErrorCode) String() string {
// Error identifies a script-related error. It is used to indicate three
// classes of errors:
// 1) Script execution failures due to violating one of the many requirements
// imposed by the script engine or evaluating to false
// 2) Improper API usage by callers
// 3) Internal consistency check failures
// 1. Script execution failures due to violating one of the many requirements
// imposed by the script engine or evaluating to false
// 2. Improper API usage by callers
// 3. Internal consistency check failures
//
// The caller can use type assertions on the returned errors to access the
// ErrorCode field to ascertain the specific reason for the error. As an

View File

@@ -6,6 +6,7 @@ package txscript
import (
"bytes"
"encoding/hex"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"reflect"
"testing"
@@ -3581,50 +3582,92 @@ func TestHasCanonicalPush(t *testing.T) {
}
}
func hexDecode(src string) []byte {
decoded, err := hex.DecodeString(src)
if err != nil {
panic(err)
}
return decoded
}
// TestGetPreciseSigOps ensures the more precise signature operation counting
// mechanism which includes signatures in P2SH scripts works as expected.
func TestGetPreciseSigOps(t *testing.T) {
t.Parallel()
tests := []struct {
name string
scriptSig []byte
nSigOps int
}{
{
name: "scriptSig doesn't parse",
scriptSig: mustParseShortForm("PUSHDATA1 0x02", 0),
},
{
name: "scriptSig isn't push only",
scriptSig: mustParseShortForm("1 DUP", 0),
nSigOps: 0,
},
{
name: "scriptSig length 0",
scriptSig: nil,
nSigOps: 0,
},
{
name: "No script at the end",
// No script at end but still push only.
scriptSig: mustParseShortForm("1 1", 0),
nSigOps: 0,
},
{
name: "pushed script doesn't parse",
scriptSig: mustParseShortForm("DATA_2 PUSHDATA1 0x02", 0),
},
}
// The signature in the p2sh script is nonsensical for the tests since
// The signature in the p2sh script is nonsensical for most tests since
// this script will never be executed. What matters is that it matches
// the right pattern.
scriptOnly := mustParseShortForm("BLAKE2B DATA_32 0x433ec2ac1ffa1b7b7d0"+
"27f564529c57197f9ae88 EQUAL", 0)
scriptPubKey := &externalapi.ScriptPublicKey{scriptOnly, 0}
tests := []struct {
name string
scriptSig []byte
scriptPublicKey *externalapi.ScriptPublicKey
nSigOps int
}{
{
name: "scriptSig doesn't parse",
scriptSig: mustParseShortForm("PUSHDATA1 0x02", 0),
scriptPublicKey: scriptPubKey,
},
{
name: "scriptSig isn't push only",
scriptSig: mustParseShortForm("1 DUP", 0),
nSigOps: 0,
scriptPublicKey: scriptPubKey,
},
{
name: "scriptSig length 0",
scriptSig: nil,
nSigOps: 0,
scriptPublicKey: scriptPubKey,
},
{
name: "No script at the end",
// No script at end but still push only.
scriptSig: mustParseShortForm("1 1", 0),
nSigOps: 0,
scriptPublicKey: scriptPubKey,
},
{
name: "pushed script doesn't parse",
scriptSig: mustParseShortForm("DATA_2 PUSHDATA1 0x02", 0),
scriptPublicKey: scriptPubKey,
},
{
name: "mainnet multisig transaction 487f94ffa63106f72644068765b9dc629bb63e481210f382667d4a93b69af412",
scriptSig: hexDecode("41eb577889fa28283709201ef5b056745c6cf0546dd31666cecd41c40a581b256e885d941b86b14d44efacec12d614e7fcabf7b341660f95bab16b71d766ab010501411c0eeef117ca485d34e4bc0cf6d5b578aa250c5d13ebff0882a7e2eeea1f31e8ecb6755696d194b1b0fcb853afab28b61f3f7cec487bd611df7e57252802f535014c875220ab64c7691713a32ea6dfced9155c5c26e8186426f0697af0db7a4b1340f992d12041ae738d66fe3d21105483e5851778ad73c5cddf0819c5e8fd8a589260d967e72065120722c36d3fac19646258481dd3661fa767da151304af514cb30af5cb5692203cd7690ecb67cbbe6cafad00a7c9133da535298ab164549e0cce2658f7b3032754ae"),
scriptPublicKey: &externalapi.ScriptPublicKey{
Script: hexDecode("aa20f38031f61ca23d70844f63a477d07f0b2c2decab907c2e096e548b0e08721c7987"),
Version: 0,
},
nSigOps: 4,
},
{
name: "a partially parseable script public key",
scriptSig: nil,
scriptPublicKey: &externalapi.ScriptPublicKey{
Script: mustParseShortForm("CHECKSIG CHECKSIG DATA_1", 0),
Version: 0,
},
nSigOps: 2,
},
{
name: "p2pk",
scriptSig: hexDecode("416db0c0ce824a6d076c8e73aae9987416933df768e07760829cb0685dc0a2bbb11e2c0ced0cab806e111a11cbda19784098fd25db176b6a9d7c93e5747674d32301"),
scriptPublicKey: &externalapi.ScriptPublicKey{
Script: hexDecode("208a457ca74ade0492c44c440da1cab5b008d8449150fe2794f0d8f4cce7e8aa27ac"),
Version: 0,
},
nSigOps: 1,
},
}
for _, test := range tests {
count := GetPreciseSigOpCount(test.scriptSig, scriptPubKey, true)
count := GetPreciseSigOpCount(test.scriptSig, test.scriptPublicKey, true)
if count != test.nSigOps {
t.Errorf("%s: expected count of %d, got %d", test.name,
test.nSigOps, count)

View File

@@ -37,16 +37,17 @@ func (e ErrScriptNotCanonical) Error() string {
// For example, the following would build a 2-of-3 multisig script for usage in
// a pay-to-script-hash (although in this situation MultiSigScript() would be a
// better choice to generate the script):
// builder := txscript.NewScriptBuilder()
// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
// builder.AddData(pubKey3).AddOp(txscript.OP_3)
// builder.AddOp(txscript.OP_CHECKMULTISIG)
// script, err := builder.Script()
// if err != nil {
// // Handle the error.
// return
// }
// fmt.Printf("Final multi-sig script: %x\n", script)
//
// builder := txscript.NewScriptBuilder()
// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
// builder.AddData(pubKey3).AddOp(txscript.OP_3)
// builder.AddOp(txscript.OP_CHECKMULTISIG)
// script, err := builder.Script()
// if err != nil {
// // Handle the error.
// return
// }
// fmt.Printf("Final multi-sig script: %x\n", script)
type ScriptBuilder struct {
script []byte
err error

View File

@@ -82,18 +82,19 @@ func checkMinimalDataEncoding(v []byte) error {
// Bytes returns the number serialized as a little endian with a sign bit.
//
// Example encodings:
// 127 -> [0x7f]
// -127 -> [0xff]
// 128 -> [0x80 0x00]
// -128 -> [0x80 0x80]
// 129 -> [0x81 0x00]
// -129 -> [0x81 0x80]
// 256 -> [0x00 0x01]
// -256 -> [0x00 0x81]
// 32767 -> [0xff 0x7f]
// -32767 -> [0xff 0xff]
// 32768 -> [0x00 0x80 0x00]
// -32768 -> [0x00 0x80 0x80]
//
// 127 -> [0x7f]
// -127 -> [0xff]
// 128 -> [0x80 0x00]
// -128 -> [0x80 0x80]
// 129 -> [0x81 0x00]
// -129 -> [0x81 0x80]
// 256 -> [0x00 0x01]
// -256 -> [0x00 0x81]
// 32767 -> [0xff 0x7f]
// -32767 -> [0xff 0xff]
// 32768 -> [0x00 0x80 0x00]
// -32768 -> [0x00 0x80 0x80]
func (n scriptNum) Bytes() []byte {
// Zero encodes as an empty byte slice.
if n == 0 {

View File

@@ -75,15 +75,21 @@ func subtractionWithRemainderHavingDAAScoreInPlace(collection1, collection2, res
//
// diffFrom follows a set of rules represented by the following 3 by 3 table:
//
// | | this | |
// | | this | |
//
// ---------+-----------+-----------+-----------+-----------
// | | toAdd | toRemove | None
//
// | | toAdd | toRemove | None
//
// ---------+-----------+-----------+-----------+-----------
// other | toAdd | - | X | toAdd
// ---------+-----------+-----------+-----------+-----------
// | toRemove | X | - | toRemove
//
// | toRemove | X | - | toRemove
//
// ---------+-----------+-----------+-----------+-----------
// | None | toRemove | toAdd | -
//
// | None | toRemove | toAdd | -
//
// Key:
// - Don't add anything to the result
@@ -92,10 +98,10 @@ func subtractionWithRemainderHavingDAAScoreInPlace(collection1, collection2, res
// toRemove Add the UTXO into the toRemove collection of the result
//
// Examples:
// 1. This diff contains a UTXO in toAdd, and the other diff contains it in toRemove
// diffFrom results in an error
// 2. This diff contains a UTXO in toRemove, and the other diff does not contain it
// diffFrom results in the UTXO being added to toAdd
// 1. This diff contains a UTXO in toAdd, and the other diff contains it in toRemove
// diffFrom results in an error
// 2. This diff contains a UTXO in toRemove, and the other diff does not contain it
// diffFrom results in the UTXO being added to toAdd
func diffFrom(this, other *mutableUTXODiff) (*mutableUTXODiff, error) {
// Note that the following cases are not accounted for, as they are impossible
// as long as the base utxoSet is the same:

View File

@@ -3,9 +3,10 @@ Package dagconfig defines DAG configuration parameters.
In addition to the main Kaspa network, which is intended for the transfer
of monetary value, there also exists the following standard networks:
* testnet
* simnet
* devnet
- testnet
- simnet
- devnet
These networks are incompatible with each other (each sharing a different
genesis block) and software should handle errors where input intended for
one network is used on an application instance running on a different
@@ -19,40 +20,40 @@ one of the standard Param vars for use as the application's "active" network.
When a network parameter is needed, it may then be looked up through this
variable (either directly, or hidden in a library call).
package main
package main
import (
"flag"
"fmt"
"log"
import (
"flag"
"fmt"
"log"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/domain/dagconfig"
)
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/domain/dagconfig"
)
var testnet = flag.Bool("testnet", false, "operate on the testnet Kaspa network")
var testnet = flag.Bool("testnet", false, "operate on the testnet Kaspa network")
// By default (without --testnet), use mainnet.
var dagParams = &dagconfig.MainnetParams
// By default (without --testnet), use mainnet.
var dagParams = &dagconfig.MainnetParams
func main() {
flag.Parse()
func main() {
flag.Parse()
// Modify active network parameters if operating on testnet.
if *testnet {
dagParams = &dagconfig.TestnetParams
}
// Modify active network parameters if operating on testnet.
if *testnet {
dagParams = &dagconfig.TestnetParams
}
// later...
// later...
// Create and print new payment address, specific to the active network.
pubKey := make([]byte, 32)
addr, err := util.NewAddressPubKey(pubKey, dagParams)
if err != nil {
log.Fatal(err)
}
fmt.Println(addr)
}
// Create and print new payment address, specific to the active network.
pubKey := make([]byte, 32)
addr, err := util.NewAddressPubKey(pubKey, dagParams)
if err != nil {
log.Fatal(err)
}
fmt.Println(addr)
}
If an application does not use one of the standard Kaspa networks, a new
Params struct may be created which defines the parameters for the non-

View File

@@ -105,7 +105,7 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0,
// devGenesisHash is the hash of the first block in the block DAG for the development
// network (genesis block).
var devnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x4c, 0x64, 0x16, 0x35, 0xc8, 0x5d, 0xc8, 0x8d, 0x90, 0xbe, 0x2a, 0x42, 0xc1, 0xf6, 0x0f, 0xc4, 0xe9, 0xfc, 0xfc, 0xda, 0xdb, 0x53, 0x0d, 0x51, 0xe3, 0x02, 0x2b, 0x68, 0x65, 0xa6, 0x46, 0x7b,
0xb3, 0x13, 0x87, 0x0a, 0x32, 0xc7, 0x04, 0xbd, 0xf1, 0x21, 0x4a, 0x3b, 0x27, 0x0c, 0xc4, 0x75, 0xd9, 0x42, 0xc2, 0x09, 0x2d, 0x37, 0x9b, 0xc8, 0x70, 0x0a, 0xb0, 0x43, 0x31, 0x9e, 0xf8, 0x46,
})
// devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block
@@ -127,7 +127,7 @@ var devnetGenesisBlock = externalapi.DomainBlock{
&externalapi.DomainHash{},
externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray()),
0x11e9db49828,
0x207fffff,
525264379,
0x48e5e,
0,
0,

View File

@@ -297,7 +297,11 @@ var TestnetParams = Params{
Net: appmessage.Testnet,
RPCPort: "16210",
DefaultPort: "16211",
DNSSeeds: []string{"testnet-10-dnsseed.kas.pa"},
DNSSeeds: []string{
"testnet-10-dnsseed.kas.pa",
// This DNS seeder is run by Tiram
"seeder1-testnet.kaspad.net",
},
// DAG parameters
GenesisBlock: &testnetGenesisBlock,

View File

@@ -2,6 +2,7 @@ package domain
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/pkg/errors"
"math"
)
@@ -66,11 +67,15 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
}
for _, blockHash := range pruningPointAndItsAnticone {
block, err := syncer.GetBlock(blockHash)
block, found, err := syncer.GetBlock(blockHash)
if err != nil {
return err
}
if !found {
return errors.Errorf("block %s is missing", blockHash)
}
blockDAAWindowHashes, err := syncer.BlockDAAWindowHashes(blockHash)
if err != nil {
return err
@@ -156,11 +161,14 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
continue
}
block, err := syncer.GetBlock(blocksHash)
block, found, err := syncer.GetBlock(blocksHash)
if err != nil {
return err
}
if !found {
return errors.Errorf("block %s is missing", blocksHash)
}
err = syncee.ValidateAndInsertBlock(block, false)
if err != nil {
return err

View File

@@ -339,7 +339,7 @@ func TestOrphanTransactions(t *testing.T) {
t.Fatalf("AddBlock: %v", err)
}
blockParentsTransactions, err := tc.GetBlock(blockParentsTransactionsHash)
blockParentsTransactions, _, err := tc.GetBlock(blockParentsTransactionsHash)
if err != nil {
t.Fatalf("GetBlock: %v", err)
}
@@ -648,7 +648,7 @@ func TestModifyBlockTemplate(t *testing.T) {
t.Fatalf("AddBlock: %v", err)
}
blockParentsTransactions, err := tc.GetBlock(blockParentsTransactionsHash)
blockParentsTransactions, _, err := tc.GetBlock(blockParentsTransactionsHash)
if err != nil {
t.Fatalf("GetBlock: %v", err)
}
@@ -924,7 +924,7 @@ func createParentAndChildrenTransactions(tc testapi.TestConsensus) (txParent *ex
if err != nil {
return nil, nil, errors.Wrap(err, "AddBlock: ")
}
fundingBlockForParent, err := tc.GetBlock(fundingBlockHashForParent)
fundingBlockForParent, _, err := tc.GetBlock(fundingBlockHashForParent)
if err != nil {
return nil, nil, errors.Wrap(err, "GetBlock: ")
}
@@ -949,7 +949,7 @@ func createChildAndParentTxsAndAddParentToConsensus(tc testapi.TestConsensus) (*
if err != nil {
return nil, errors.Wrap(err, "AddBlock: ")
}
ParentBlock, err := tc.GetBlock(ParentBlockHash)
ParentBlock, _, err := tc.GetBlock(ParentBlockHash)
if err != nil {
return nil, errors.Wrap(err, "GetBlock: ")
}

7
go.mod
View File

@@ -7,6 +7,7 @@ require (
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd
github.com/btcsuite/winsvc v1.0.0
github.com/davecgh/go-spew v1.1.1
github.com/gofrs/flock v0.8.1
github.com/golang/protobuf v1.5.2
github.com/jessevdk/go-flags v1.4.0
github.com/jrick/logrotate v1.0.0
@@ -19,14 +20,14 @@ require (
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
google.golang.org/grpc v1.38.0
google.golang.org/protobuf v1.27.1
google.golang.org/protobuf v1.28.1
)
require (
github.com/golang/snappy v0.0.1 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/text v0.3.8 // indirect
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
)

19
go.sum
View File

@@ -26,6 +26,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -118,17 +120,16 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -155,8 +156,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0 h1:TLkBREm4nIsEcexnCjgQd5GQWaHcqMzwQV0TX9pq8S0=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -167,10 +166,10 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

View File

@@ -207,10 +207,10 @@ func DefaultConfig() *Config {
// line options.
//
// The configuration proceeds as follows:
// 1) Start with a default config with sane settings
// 2) Pre-parse the command line to check for an alternative config file
// 3) Load configuration file overwriting defaults with any specified options
// 4) Parse CLI options and overwrite/add any specified options
// 1. Start with a default config with sane settings
// 2. Pre-parse the command line to check for an alternative config file
// 3. Load configuration file overwriting defaults with any specified options
// 4. Parse CLI options and overwrite/add any specified options
//
// The above results in kaspad functioning properly without any config settings
// while still allowing the user to override settings with config files and

View File

@@ -1,7 +1,7 @@
/*
Package database provides a database for kaspad.
Overview
# Overview
This package provides a database layer to store and retrieve data in a simple
and efficient manner.
@@ -11,23 +11,23 @@ checksums in key areas to ensure data integrity.
Implementors of additional backends are required to implement the following interfaces:
DataAccessor
# DataAccessor
This defines the common interface by which data gets accessed in a generic kaspad
database. Both the Database and the Transaction interfaces (see below) implement it.
Database
# Database
This defines the interface of a database that can begin transactions and close itself.
Transaction
# Transaction
This defines the interface of a generic kaspad database transaction.
Note: transactions provide data consistency over the state of the database as it was
when the transaction started. There is NO guarantee that if one puts data into the
transaction then it will be available to get within the same transaction.
Cursor
# Cursor
This iterates over database entries given some bucket.
*/

View File

@@ -15,9 +15,9 @@ variable and overridden per-Backend by using the WithFlags call option. Multiple
LOGFLAGS options can be specified, separated by commas. The following options
are recognized:
longfile: Include the full filepath and line number in all log messages
longfile: Include the full filepath and line number in all log messages
shortfile: Include the filename and line number in all log messages.
Overrides longfile.
shortfile: Include the filename and line number in all log messages.
Overrides longfile.
*/
package logger

View File

@@ -1,7 +1,7 @@
/*
Package addressmanager implements concurrency safe Kaspa address manager.
Address Manager Overview
# Address Manager Overview
In order maintain the peer-to-peer Kaspa network, there needs to be a source
of addresses to connect to as nodes come and go. The Kaspa protocol provides

View File

@@ -2,8 +2,12 @@ package grpcserver
import (
"github.com/davecgh/go-spew/spew"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/infrastructure/logger"
"io"
"os"
"strconv"
"sync"
"time"
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
@@ -25,6 +29,9 @@ func (c *gRPCConnection) connectionLoops() error {
return err
}
var blockDelayOnce sync.Once
var blockDelay = 0
func (c *gRPCConnection) sendLoop() error {
outgoingRoute := c.router.OutgoingRoute()
for c.IsConnected() {
@@ -36,6 +43,20 @@ func (c *gRPCConnection) sendLoop() error {
return err
}
blockDelayOnce.Do(func() {
experimentalDelayEnv := os.Getenv("KASPA_EXPERIMENTAL_DELAY")
if experimentalDelayEnv != "" {
blockDelay, err = strconv.Atoi(experimentalDelayEnv)
if err != nil {
panic(err)
}
}
})
if blockDelay != 0 && message.Command() == appmessage.CmdBlock {
time.Sleep(time.Duration(blockDelay) * time.Second)
}
log.Debugf("outgoing '%s' message to %s", message.Command(), c)
log.Tracef("outgoing '%s' message to %s: %s", message.Command(), c, logger.NewLogClosure(func() string {
return spew.Sdump(message)

View File

@@ -35,7 +35,7 @@ func (x *KaspadMessage_GetConnectedPeerInfoResponse) fromAppMessage(message *app
TimeOffset: info.TimeOffset,
UserAgent: info.UserAgent,
AdvertisedProtocolVersion: info.AdvertisedProtocolVersion,
TimeConnected: info.TimeOffset,
TimeConnected: info.TimeConnected,
IsIbdPeer: info.IsIBDPeer,
}
}

View File

@@ -72,7 +72,7 @@ func (c *RPCClient) connect() error {
remoteVersion := getInfoResponse.ServerVersion
if localVersion != remoteVersion {
return errors.Errorf("Server version mismatch, expect: %s, got: %s", localVersion, remoteVersion)
log.Warnf("version mismatch, client: %s, server: %s - expected responses and requests may deviate", localVersion, remoteVersion)
}
return nil

View File

@@ -105,7 +105,16 @@ func mineBlocks(consensusConfig *consensus.Config, rpcClient *rpc.Client, blockC
func mineOrFetchBlock(blockData JSONBlock, mdb *miningDB, testConsensus testapi.TestConsensus) (*externalapi.DomainBlock, error) {
hash := mdb.hashByID(blockData.ID)
if mdb.hashByID(blockData.ID) != nil {
return testConsensus.GetBlock(hash)
block, found, err := testConsensus.GetBlock(hash)
if err != nil {
return nil, err
}
if !found {
return nil, errors.Errorf("block %s is missing", hash)
}
return block, nil
}
parentHashes := make([]*externalapi.DomainHash, len(blockData.Parents))

Some files were not shown because too many files have changed in this diff Show More