mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-21 11:17:05 +00:00
Compare commits
1 Commits
rc2-tmp
...
wallet-exp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c1b4b2125 |
2
.github/workflows/deploy.yaml
vendored
2
.github/workflows/deploy.yaml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21
|
||||
go-version: 1.18
|
||||
|
||||
- name: Build on Linux
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
2
.github/workflows/race.yaml
vendored
2
.github/workflows/race.yaml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19
|
||||
go-version: 1.18
|
||||
|
||||
- name: Set scheduled branch name
|
||||
shell: bash
|
||||
|
||||
6
.github/workflows/tests.yaml
vendored
6
.github/workflows/tests.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19
|
||||
go-version: 1.18
|
||||
|
||||
|
||||
# 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.19
|
||||
go-version: 1.18
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19
|
||||
go-version: 1.18
|
||||
|
||||
- name: Delete the stability tests from coverage
|
||||
run: rm -r stability-tests
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainers on this [Google form][gform]. The project maintainers will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[gform]: https://forms.gle/dnKXMJL7VxdUjt3x5
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
@@ -7,6 +7,8 @@ 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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -27,15 +27,18 @@ 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.
|
||||
block, found, err := context.Domain().Consensus().GetBlock(hash)
|
||||
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)
|
||||
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)
|
||||
|
||||
@@ -119,15 +119,11 @@ func HandlePruningPointAndItsAnticoneRequests(context PruningPointAndItsAnticone
|
||||
}
|
||||
|
||||
for i, blockHash := range pointAndItsAnticone {
|
||||
block, found, err := context.Domain().Consensus().GetBlock(blockHash)
|
||||
block, 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
|
||||
|
||||
@@ -28,15 +28,18 @@ 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.
|
||||
block, found, err := context.Domain().Consensus().GetBlock(hash)
|
||||
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)
|
||||
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))
|
||||
|
||||
@@ -211,14 +211,10 @@ func (flow *handleRelayInvsFlow) start() error {
|
||||
continue
|
||||
}
|
||||
virtualHasNewParents = true
|
||||
block, found, err := flow.Domain().Consensus().GetBlock(parent)
|
||||
block, 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)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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"
|
||||
@@ -71,17 +70,16 @@ func (flow *handleIBDFlow) runIBDIfNotRunning(block *externalapi.DomainBlock) er
|
||||
}
|
||||
|
||||
isFinishedSuccessfully := false
|
||||
var err error
|
||||
defer func() {
|
||||
flow.UnsetIBDRunning()
|
||||
flow.logIBDFinished(isFinishedSuccessfully, err)
|
||||
flow.logIBDFinished(isFinishedSuccessfully)
|
||||
}()
|
||||
|
||||
relayBlockHash := consensushashing.BlockHash(block)
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
syncerHeaderSelectedTipHash, highestKnownSyncerChainHash, err := flow.negotiateMissingSyncerChainSegment()
|
||||
if err != nil {
|
||||
@@ -100,7 +98,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
|
||||
}
|
||||
@@ -175,11 +173,6 @@ 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 {
|
||||
@@ -192,21 +185,8 @@ func (flow *handleIBDFlow) negotiateMissingSyncerChainSegment() (*externalapi.Do
|
||||
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
|
||||
}
|
||||
currentHighestKnownSyncerChainHash = syncerChainHash
|
||||
break
|
||||
}
|
||||
lowestUnknownSyncerChainHash = syncerChainHash
|
||||
}
|
||||
@@ -285,7 +265,7 @@ func (flow *handleIBDFlow) negotiateMissingSyncerChainSegment() (*externalapi.Do
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Found highest known syncer chain block %s from peer %s",
|
||||
log.Debugf("Found highest known syncer chain block %s from peer %s",
|
||||
highestKnownSyncerChainHash, flow.peer)
|
||||
|
||||
return syncerHeaderSelectedTipHash, highestKnownSyncerChainHash, nil
|
||||
@@ -300,14 +280,10 @@ func (flow *handleIBDFlow) isGenesisVirtualSelectedParent() (bool, error) {
|
||||
return virtualSelectedParent.Equal(flow.Config().NetParams().GenesisHash), nil
|
||||
}
|
||||
|
||||
func (flow *handleIBDFlow) logIBDFinished(isFinishedSuccessfully bool, err error) {
|
||||
func (flow *handleIBDFlow) logIBDFinished(isFinishedSuccessfully bool) {
|
||||
successString := "successfully"
|
||||
if !isFinishedSuccessfully {
|
||||
if err != nil {
|
||||
successString = fmt.Sprintf("(interrupted: %s)", err)
|
||||
} else {
|
||||
successString = fmt.Sprintf("(interrupted)")
|
||||
}
|
||||
successString = "(interrupted)"
|
||||
}
|
||||
log.Infof("IBD with peer %s finished %s", flow.peer, successString)
|
||||
}
|
||||
|
||||
@@ -55,12 +55,7 @@ func (flow *handleIBDFlow) shouldSyncAndShouldDownloadHeadersProof(
|
||||
|
||||
var highestSharedBlockFound, isPruningPointInSharedBlockChain bool
|
||||
if highestKnownSyncerChainHash != nil {
|
||||
blockInfo, err := flow.Domain().Consensus().GetBlockInfo(highestKnownSyncerChainHash)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
highestSharedBlockFound = blockInfo.HasBody()
|
||||
highestSharedBlockFound = true
|
||||
pruningPoint, err := flow.Domain().Consensus().PruningPoint()
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
@@ -85,33 +80,28 @@ func (flow *handleIBDFlow) shouldSyncAndShouldDownloadHeadersProof(
|
||||
return true, true, 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, false, nil
|
||||
}
|
||||
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
func (flow *handleIBDFlow) checkIfHighHashHasMoreBlueWorkThanSelectedTipAndPruningDepthMoreBlueScore(relayBlock *externalapi.DomainBlock) (bool, error) {
|
||||
virtualSelectedParent, err := flow.Domain().Consensus().GetVirtualSelectedParent()
|
||||
headersSelectedTip, err := flow.Domain().Consensus().GetHeadersSelectedTip()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
virtualSelectedTipInfo, err := flow.Domain().Consensus().GetBlockInfo(virtualSelectedParent)
|
||||
headersSelectedTipInfo, err := flow.Domain().Consensus().GetBlockInfo(headersSelectedTip)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if relayBlock.Header.BlueScore() < virtualSelectedTipInfo.BlueScore+flow.Config().NetParams().PruningDepth() {
|
||||
if relayBlock.Header.BlueScore() < headersSelectedTipInfo.BlueScore+flow.Config().NetParams().PruningDepth() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return relayBlock.Header.BlueWork().Cmp(virtualSelectedTipInfo.BlueWork) > 0, nil
|
||||
return relayBlock.Header.BlueWork().Cmp(headersSelectedTipInfo.BlueWork) > 0, nil
|
||||
}
|
||||
|
||||
func (flow *handleIBDFlow) syncAndValidatePruningPointProof() (*externalapi.DomainHash, error) {
|
||||
@@ -291,13 +281,7 @@ func (flow *handleIBDFlow) processBlockWithTrustedData(
|
||||
}
|
||||
|
||||
err := consensus.ValidateAndInsertBlockWithTrustedData(blockWithTrustedData, false)
|
||||
if err != nil {
|
||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||
return protocolerrors.Wrapf(true, err, "failed validating block with trusted data")
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (flow *handleIBDFlow) receiveBlockWithTrustedData() (*appmessage.MsgBlockWithTrustedDataV4, bool, error) {
|
||||
|
||||
@@ -1,39 +1,3 @@
|
||||
Kaspad v0.12.13 - 2023-03-06
|
||||
===========================
|
||||
|
||||
* Bump golang.org/x/crypto from 0.0.0-20210513164829-c07d793c2f9a to 0.1.0 (#2195)
|
||||
* Bump golang.org/x/net from 0.0.0-20210405180319-a5a99cb37ef4 to 0.7.0 (#2194)
|
||||
* Avoid sending transactions with no funds (#2193)
|
||||
|
||||
Kaspad v0.12.12 - 2023-03-06
|
||||
===========================
|
||||
|
||||
* 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
|
||||
===========================
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ kaspactl is an RPC client for kaspad
|
||||
|
||||
## Requirements
|
||||
|
||||
Go 1.19 or later.
|
||||
Go 1.18 or later.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -- multistage docker build: stage #1: build stage
|
||||
FROM golang:1.19-alpine AS build
|
||||
FROM golang:1.18-alpine AS build
|
||||
|
||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Kaspaminer is a CPU-based miner for kaspad
|
||||
|
||||
## Requirements
|
||||
|
||||
Go 1.19 or later.
|
||||
Go 1.18 or later.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -- multistage docker build: stage #1: build stage
|
||||
FROM golang:1.19-alpine AS build
|
||||
FROM golang:1.18-alpine AS build
|
||||
|
||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||
|
||||
|
||||
@@ -57,8 +57,7 @@ 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 string `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)"`
|
||||
SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"`
|
||||
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
|
||||
@@ -74,8 +73,7 @@ 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 string `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)"`
|
||||
SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"`
|
||||
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
|
||||
}
|
||||
@@ -218,10 +216,6 @@ 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)
|
||||
@@ -236,10 +230,6 @@ 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)
|
||||
@@ -295,24 +285,6 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
||||
return parser.Command.Active.Name, config
|
||||
}
|
||||
|
||||
func validateCreateUnsignedTransactionConf(conf *createUnsignedTransactionConfig) error {
|
||||
if (!conf.IsSendAll && conf.SendAmount == "") ||
|
||||
(conf.IsSendAll && conf.SendAmount != "") {
|
||||
|
||||
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 == "") ||
|
||||
(conf.IsSendAll && conf.SendAmount != "") {
|
||||
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/utils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
)
|
||||
|
||||
func createUnsignedTransaction(conf *createUnsignedTransactionConfig) error {
|
||||
@@ -20,17 +20,11 @@ func createUnsignedTransaction(conf *createUnsignedTransactionConfig) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||
defer cancel()
|
||||
|
||||
sendAmountSompi, err := utils.KasToSompi(conf.SendAmount)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sendAmountSompi := uint64(conf.SendAmount * constants.SompiPerKaspa)
|
||||
response, err := daemonClient.CreateUnsignedTransactions(ctx, &pb.CreateUnsignedTransactionsRequest{
|
||||
From: conf.FromAddresses,
|
||||
Address: conf.ToAddress,
|
||||
Amount: sendAmountSompi,
|
||||
IsSendAll: conf.IsSendAll,
|
||||
UseExistingChangeAddress: conf.UseExistingChangeAddress,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.12
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.12.3
|
||||
// source: kaspawalletd.proto
|
||||
|
||||
package pb
|
||||
@@ -193,7 +193,6 @@ 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() {
|
||||
@@ -256,13 +255,6 @@ 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
|
||||
@@ -1007,7 +999,6 @@ 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() {
|
||||
@@ -1077,13 +1068,6 @@ 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
|
||||
@@ -1264,7 +1248,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, 0xc3, 0x01, 0x0a, 0x21, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55,
|
||||
0x64, 0x69, 0x6e, 0x67, 0x22, 0xa5, 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,
|
||||
@@ -1274,159 +1258,155 @@ 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, 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, 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, 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,
|
||||
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, 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,
|
||||
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, 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, 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, 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,
|
||||
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,
|
||||
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,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -37,7 +37,6 @@ message CreateUnsignedTransactionsRequest {
|
||||
uint64 amount = 2;
|
||||
repeated string from = 3;
|
||||
bool useExistingChangeAddress = 4;
|
||||
bool isSendAll = 5;
|
||||
}
|
||||
|
||||
message CreateUnsignedTransactionsResponse {
|
||||
@@ -110,7 +109,6 @@ message SendRequest{
|
||||
string password = 3;
|
||||
repeated string from = 4;
|
||||
bool useExistingChangeAddress = 5;
|
||||
bool isSendAll = 6;
|
||||
}
|
||||
|
||||
message SendResponse{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.12.3
|
||||
// source: kaspawalletd.proto
|
||||
|
||||
package pb
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (s *server) changeAddress(useExisting bool, fromAddresses []*walletAddress) (util.Address, *walletAddress, error) {
|
||||
func (s *server) changeAddress(useFirst bool, fromAddresses []*walletAddress) (util.Address, *walletAddress, error) {
|
||||
internalIndex := uint32(0)
|
||||
var walletAddr *walletAddress
|
||||
if len(fromAddresses) != 0 && useExisting {
|
||||
if len(fromAddresses) != 0 {
|
||||
walletAddr = fromAddresses[0]
|
||||
} else {
|
||||
internalIndex := uint32(0)
|
||||
if !useExisting {
|
||||
if !useFirst {
|
||||
err := s.keysFile.SetLastUsedInternalIndex(s.keysFile.LastUsedInternalIndex() + 1)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -22,8 +22,7 @@ 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.IsSendAll,
|
||||
request.From, request.UseExistingChangeAddress)
|
||||
unsignedTransactions, err := s.createUnsignedTransactions(request.Address, request.Amount, request.From, request.UseExistingChangeAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -31,7 +30,7 @@ func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.Creat
|
||||
return &pb.CreateUnsignedTransactionsResponse{UnsignedTransactions: unsignedTransactions}, nil
|
||||
}
|
||||
|
||||
func (s *server) createUnsignedTransactions(address string, amount uint64, isSendAll bool, fromAddressesString []string, useExistingChangeAddress bool) ([][]byte, error) {
|
||||
func (s *server) createUnsignedTransactions(address string, amount uint64, fromAddressesString []string, useExistingChangeAddress bool) ([][]byte, error) {
|
||||
if !s.isSynced() {
|
||||
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
||||
}
|
||||
@@ -57,15 +56,11 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, isSen
|
||||
fromAddresses = append(fromAddresses, fromAddress)
|
||||
}
|
||||
|
||||
selectedUTXOs, spendValue, changeSompi, err := s.selectUTXOs(amount, isSendAll, feePerInput, fromAddresses)
|
||||
selectedUTXOs, changeSompi, err := s.selectUTXOs(amount, feePerInput, fromAddresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
@@ -73,7 +68,7 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, isSen
|
||||
|
||||
payments := []*libkaspawallet.Payment{{
|
||||
Address: toAddress,
|
||||
Amount: spendValue,
|
||||
Amount: amount,
|
||||
}}
|
||||
if changeSompi > 0 {
|
||||
payments = append(payments, &libkaspawallet.Payment{
|
||||
@@ -95,15 +90,15 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, isSen
|
||||
return unsignedTransactions, nil
|
||||
}
|
||||
|
||||
func (s *server) selectUTXOs(spendAmount uint64, isSendAll bool, feePerInput uint64, fromAddresses []*walletAddress) (
|
||||
selectedUTXOs []*libkaspawallet.UTXO, totalReceived uint64, changeSompi uint64, err error) {
|
||||
|
||||
func (s *server) selectUTXOs(spendAmount uint64, feePerInput uint64, fromAddresses []*walletAddress) (
|
||||
selectedUTXOs []*libkaspawallet.UTXO, changeSompi uint64, err error,
|
||||
) {
|
||||
selectedUTXOs = []*libkaspawallet.UTXO{}
|
||||
totalValue := uint64(0)
|
||||
|
||||
dagInfo, err := s.rpcClient.GetBlockDAGInfo()
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
for _, utxo := range s.utxosSortedByAmount {
|
||||
@@ -125,29 +120,21 @@ func (s *server) selectUTXOs(spendAmount uint64, isSendAll bool, feePerInput uin
|
||||
UTXOEntry: utxo.UTXOEntry,
|
||||
DerivationPath: s.walletAddressPath(utxo.address),
|
||||
})
|
||||
|
||||
totalValue += utxo.UTXOEntry.Amount()
|
||||
|
||||
fee := feePerInput * uint64(len(selectedUTXOs))
|
||||
totalSpend := spendAmount + fee
|
||||
if !isSendAll && totalValue >= totalSpend {
|
||||
if totalValue >= totalSpend {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fee := feePerInput * uint64(len(selectedUTXOs))
|
||||
var totalSpend uint64
|
||||
if isSendAll {
|
||||
totalSpend = totalValue
|
||||
totalReceived = totalValue - fee
|
||||
} else {
|
||||
totalSpend = spendAmount + fee
|
||||
totalReceived = spendAmount
|
||||
}
|
||||
totalSpend := spendAmount + fee
|
||||
if totalValue < totalSpend {
|
||||
return nil, 0, 0, errors.Errorf("Insufficient funds for send: %f required, while only %f available",
|
||||
return nil, 0, errors.Errorf("Insufficient funds for send: %f required, while only %f available",
|
||||
float64(totalSpend)/constants.SompiPerKaspa, float64(totalValue)/constants.SompiPerKaspa)
|
||||
}
|
||||
|
||||
return selectedUTXOs, totalReceived, totalValue - totalSpend, nil
|
||||
return selectedUTXOs, totalValue - totalSpend, nil
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ 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.IsSendAll,
|
||||
request.From, request.UseExistingChangeAddress)
|
||||
|
||||
unsignedTransactions, err := s.createUnsignedTransactions(request.ToAddress, request.Amount, request.From, request.UseExistingChangeAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# -- 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", "--" ]
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.12
|
||||
// protoc-gen-go v1.28.0
|
||||
// protoc v3.17.2
|
||||
// source: wallet.proto
|
||||
|
||||
package protoserialization
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/utils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -33,21 +33,13 @@ func send(conf *sendConfig) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||
defer cancel()
|
||||
|
||||
var sendAmountSompi uint64
|
||||
if !conf.IsSendAll {
|
||||
sendAmountSompi, err = utils.KasToSompi(conf.SendAmount)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
||||
@@ -26,8 +26,5 @@ 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
|
||||
}
|
||||
|
||||
@@ -2,13 +2,8 @@ package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// FormatKas takes the amount of sompis as uint64, and returns amount of KAS with 8 decimal places
|
||||
@@ -19,50 +14,3 @@ func FormatKas(amount uint64) string {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// KasToSompi takes in a string representation of the Kas value to convert to Sompi
|
||||
func KasToSompi(amount string) (uint64, error) {
|
||||
err := validateKASAmountFormat(amount)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// after validation, amount can only be either an int OR
|
||||
// a float with an int component and decimal places
|
||||
parts := strings.Split(amount, ".")
|
||||
amountStr := ""
|
||||
|
||||
if constants.SompiPerKaspa%10 != 0 {
|
||||
return 0, errors.Errorf("Unable to convert to sompi when SompiPerKaspa is not a multiple of 10")
|
||||
}
|
||||
|
||||
decimalPlaces := int(math.Log10(constants.SompiPerKaspa))
|
||||
decimalStr := ""
|
||||
|
||||
if len(parts) == 2 {
|
||||
decimalStr = parts[1]
|
||||
}
|
||||
|
||||
amountStr = fmt.Sprintf("%s%-*s", parts[0], decimalPlaces, decimalStr) // Padded with spaces at the end to fill for missing decimals: Sample "0.01234 "
|
||||
amountStr = strings.ReplaceAll(amountStr, " ", "0") // Make the spaces be 0s. Sample "0.012340000"
|
||||
|
||||
convertedAmount, err := strconv.ParseUint(amountStr, 10, 64)
|
||||
|
||||
return convertedAmount, err
|
||||
}
|
||||
|
||||
func validateKASAmountFormat(amount string) error {
|
||||
// Check whether it's an integer, or a float with max 8 digits
|
||||
match, err := regexp.MatchString("^([1-9]\\d{0,11}|0)(\\.\\d{0,8})?$", amount)
|
||||
|
||||
if !match {
|
||||
return errors.Errorf("Invalid amount")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
|
||||
// Takes in a string representation of the Kas value to convert to Sompi
|
||||
func TestKasToSompi(t *testing.T) {
|
||||
type testVector struct {
|
||||
originalAmount string
|
||||
convertedAmount uint64
|
||||
}
|
||||
|
||||
validCases := []testVector{
|
||||
{originalAmount: "0", convertedAmount: 0},
|
||||
{originalAmount: "1", convertedAmount: 100000000},
|
||||
{originalAmount: "33184.1489732", convertedAmount: 3318414897320},
|
||||
{originalAmount: "21.35808032", convertedAmount: 2135808032},
|
||||
{originalAmount: "184467440737.09551615", convertedAmount: 18446744073709551615},
|
||||
}
|
||||
|
||||
for _, currentTestVector := range validCases {
|
||||
convertedAmount, err := KasToSompi(currentTestVector.originalAmount)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else if convertedAmount != currentTestVector.convertedAmount {
|
||||
t.Errorf("Expected %s, to convert to %d. Got: %d", currentTestVector.originalAmount, currentTestVector.convertedAmount, convertedAmount)
|
||||
}
|
||||
}
|
||||
|
||||
invalidCases := []string{
|
||||
"184467440737.09551616", // Bigger than max uint64
|
||||
"-1",
|
||||
"a",
|
||||
"",
|
||||
}
|
||||
|
||||
for _, currentTestVector := range invalidCases {
|
||||
_, err := KasToSompi(currentTestVector)
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error but succeeded validation for test case %s", currentTestVector)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAmountFormat(t *testing.T) {
|
||||
validCases := []string{
|
||||
"0",
|
||||
"1",
|
||||
"1.0",
|
||||
"0.1",
|
||||
"0.12345678",
|
||||
"111111111111.11111111", // 12 digits to the left of decimal, 8 digits to the right
|
||||
"184467440737.09551615", // Maximum input that can be represented in sompi later
|
||||
"184467440737.09551616", // Cannot be represented in sompi, but we'll acccept for "correct format"
|
||||
"999999999999.99999999", // Cannot be represented in sompi, but we'll acccept for "correct format"
|
||||
}
|
||||
|
||||
for _, testCase := range validCases {
|
||||
err := validateKASAmountFormat(testCase)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
invalidCases := []string{
|
||||
"",
|
||||
"a",
|
||||
"-1",
|
||||
"0.123456789", // 9 decimal digits
|
||||
".1", // decimal but no integer component
|
||||
"0a", // Extra character
|
||||
"0000000000000", // 13 zeros
|
||||
"012", // Int padded with zero
|
||||
"00.1", // Decimal padded with zeros
|
||||
"111111111111111111111", // all digits
|
||||
"111111111111A11111111", // non-period/non-digit where decimal would be
|
||||
"000000000000.00000000", // all zeros
|
||||
"kaspa", // all text
|
||||
}
|
||||
|
||||
for _, testCase := range invalidCases {
|
||||
err := validateKASAmountFormat(testCase)
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error but succeeded validation for test case %s", testCase)
|
||||
}
|
||||
}
|
||||
}
|
||||
6
doc.go
6
doc.go
@@ -13,12 +13,10 @@ 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -- multistage docker build: stage #1: build stage
|
||||
FROM golang:1.19-alpine AS build
|
||||
FROM golang:1.18-alpine AS build
|
||||
|
||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||
|
||||
|
||||
@@ -357,7 +357,7 @@ func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction
|
||||
stagingArea, transaction, model.VirtualBlockHash)
|
||||
}
|
||||
|
||||
func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, bool, error) {
|
||||
func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, 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, false, nil
|
||||
return nil, errors.Wrapf(err, "block %s does not exist", blockHash)
|
||||
}
|
||||
return nil, false, err
|
||||
return nil, err
|
||||
}
|
||||
return block, true, nil
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func (s *consensus) GetBlockEvenIfHeaderOnly(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -10,12 +10,10 @@ 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
|
||||
|
||||
@@ -13,7 +13,7 @@ type Consensus interface {
|
||||
ValidatePruningPointProof(pruningPointProof *PruningPointProof) error
|
||||
ApplyPruningPointProof(pruningPointProof *PruningPointProof) error
|
||||
|
||||
GetBlock(blockHash *DomainHash) (*DomainBlock, bool, error)
|
||||
GetBlock(blockHash *DomainHash) (*DomainBlock, error)
|
||||
GetBlockEvenIfHeaderOnly(blockHash *DomainHash) (*DomainBlock, error)
|
||||
GetBlockHeader(blockHash *DomainHash) (BlockHeader, error)
|
||||
GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error)
|
||||
|
||||
@@ -43,9 +43,6 @@ type TestConsensus interface {
|
||||
AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
|
||||
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
||||
|
||||
AddBlockOnTips(coinbaseData *externalapi.DomainCoinbaseData,
|
||||
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
||||
|
||||
AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
||||
|
||||
AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,9 +159,8 @@ 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()
|
||||
@@ -196,7 +195,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)
|
||||
}
|
||||
@@ -270,27 +269,22 @@ 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)
|
||||
}
|
||||
_, found, err := testConsensus.GetBlock(blockHashG)
|
||||
_, err = testConsensus.GetBlock(blockHashG)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting blockG: %+v", err)
|
||||
t.Fatalf("Error getting blockF: %+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.
|
||||
|
||||
@@ -205,37 +205,37 @@ func TestBlockWindow(t *testing.T) {
|
||||
{
|
||||
parents: []string{"H", "F"},
|
||||
id: "I",
|
||||
expectedWindow: []string{"F", "C", "H", "D", "B", "G"},
|
||||
expectedWindow: []string{"F", "C", "D", "H", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"I"},
|
||||
id: "J",
|
||||
expectedWindow: []string{"I", "F", "C", "H", "D", "B", "G"},
|
||||
expectedWindow: []string{"I", "F", "C", "D", "H", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"J"},
|
||||
id: "K",
|
||||
expectedWindow: []string{"J", "I", "F", "C", "H", "D", "B", "G"},
|
||||
expectedWindow: []string{"J", "I", "F", "C", "D", "H", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"K"},
|
||||
id: "L",
|
||||
expectedWindow: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G"},
|
||||
expectedWindow: []string{"K", "J", "I", "F", "C", "D", "H", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"L"},
|
||||
id: "M",
|
||||
expectedWindow: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"},
|
||||
expectedWindow: []string{"L", "K", "J", "I", "F", "C", "D", "H", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "N",
|
||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"},
|
||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "G"},
|
||||
},
|
||||
{
|
||||
parents: []string{"N"},
|
||||
id: "O",
|
||||
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"},
|
||||
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"},
|
||||
},
|
||||
},
|
||||
dagconfig.SimnetParams.Name: {
|
||||
|
||||
@@ -132,7 +132,7 @@ func TestDifficulty(t *testing.T) {
|
||||
case dagconfig.TestnetParams.Name:
|
||||
expectedBits = uint32(0x1e7f1441)
|
||||
case dagconfig.DevnetParams.Name:
|
||||
expectedBits = uint32(0x1f4e54ab)
|
||||
expectedBits = uint32(0x207f1441)
|
||||
case dagconfig.MainnetParams.Name:
|
||||
expectedBits = uint32(0x1d02c50f)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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: "502",
|
||||
dagconfig.DevnetParams.Name: "503",
|
||||
dagconfig.SimnetParams.Name: "503",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -161,9 +161,7 @@ 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -318,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)
|
||||
}
|
||||
@@ -444,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)
|
||||
}
|
||||
|
||||
@@ -69,17 +69,6 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba
|
||||
return consensushashing.BlockHash(block), virtualChangeSet, nil
|
||||
}
|
||||
|
||||
func (tc *testConsensus) AddBlockOnTips(coinbaseData *externalapi.DomainCoinbaseData,
|
||||
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error) {
|
||||
|
||||
tips, err := tc.Tips()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return tc.AddBlock(tips, coinbaseData, transactions)
|
||||
}
|
||||
|
||||
func (tc *testConsensus) AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
||||
*externalapi.VirtualChangeSet, error) {
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package consensushashing_test
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/go-secp256k1"
|
||||
@@ -109,73 +108,73 @@ func TestCalculateSignatureHashSchnorr(t *testing.T) {
|
||||
|
||||
// sigHashAll
|
||||
{name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
expectedSignatureHash: "03b7ac6927b2b67100734c3cc313ff8c2e8b3ce3e746d46dd660b706a916b1f5"},
|
||||
expectedSignatureHash: "b363613fe99c8bb1d3712656ec8dfaea621ee6a9a95d851aec5bb59363b03f5e"},
|
||||
{name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
modificationFunction: modifyInput(1), // should change the hash
|
||||
expectedSignatureHash: "a9f563d86c0ef19ec2e4f483901d202e90150580b6123c3d492e26e7965f488c"},
|
||||
expectedSignatureHash: "34ae2989115068fc73a1b2cae023ad79c3cdb5cbe532a46fa91d9181a36990fd"},
|
||||
{name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(1), // should change the hash
|
||||
expectedSignatureHash: "aad2b61bd2405dfcf7294fc2be85f325694f02dda22d0af30381cb50d8295e0a"},
|
||||
expectedSignatureHash: "043441346c66e461f9f1dc618ebbfe7fd87f74e363f267bf8b3243a7bfe0c870"},
|
||||
{name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // should change the hash
|
||||
expectedSignatureHash: "0818bd0a3703638d4f01014c92cf866a8903cab36df2fa2506dc0d06b94295e8"},
|
||||
expectedSignatureHash: "de8d3d46bc8c51f51a1b85470f8bf01ee38214901d6d514fd13bafe4efc8aa0f"},
|
||||
{name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
expectedSignatureHash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2"},
|
||||
expectedSignatureHash: "19897764789644c2ac5cd6d83f7a78a1208f3ce6d15e8788f9b9fa6d7c91d8f1"},
|
||||
{name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyInput(0), // should change the hash
|
||||
expectedSignatureHash: "d09cb639f335ee69ac71f2ad43fd9e59052d38a7d0638de4cf989346588a7c38"},
|
||||
expectedSignatureHash: "f1ff39b1b9ce86d2fdfac61a75f3b13e98fe5e0f1057b4ec69245031ecf7be37"},
|
||||
{name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyInput(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2"},
|
||||
expectedSignatureHash: "19897764789644c2ac5cd6d83f7a78a1208f3ce6d15e8788f9b9fa6d7c91d8f1"},
|
||||
{name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "24821e466e53ff8e5fa93257cb17bb06131a48be4ef282e87f59d2bdc9afebc2"},
|
||||
expectedSignatureHash: "19897764789644c2ac5cd6d83f7a78a1208f3ce6d15e8788f9b9fa6d7c91d8f1"},
|
||||
|
||||
// sigHashNone
|
||||
{name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
expectedSignatureHash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba"},
|
||||
expectedSignatureHash: "7a5b0fef8219bb72ef1912db5335c71c4fdfac873a6096c24b2f0b5c3774349c"},
|
||||
{name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba"},
|
||||
expectedSignatureHash: "7a5b0fef8219bb72ef1912db5335c71c4fdfac873a6096c24b2f0b5c3774349c"},
|
||||
{name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
modificationFunction: modifySequence(0), // should change the hash
|
||||
expectedSignatureHash: "d9efdd5edaa0d3fd0133ee3ab731d8c20e0a1b9f3c0581601ae2075db1109268"},
|
||||
expectedSignatureHash: "852011233473ee1e61a9d0e51fb5ecd65857ceca65ebea4c54b6d557f2006f2a"},
|
||||
{name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "38ce4bc93cf9116d2e377b33ff8449c665b7b5e2f2e65303c543b9afdaa4bbba"},
|
||||
expectedSignatureHash: "7a5b0fef8219bb72ef1912db5335c71c4fdfac873a6096c24b2f0b5c3774349c"},
|
||||
{name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
|
||||
expectedSignatureHash: "06aa9f4239491e07bb2b6bda6b0657b921aeae51e193d2c5bf9e81439cfeafa0"},
|
||||
expectedSignatureHash: "1624d46e77d09cb09e4a7dcbf419b8c37671bd0274b9dc6aba0668922da83935"},
|
||||
{name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyAmountSpent(0), // should change the hash
|
||||
expectedSignatureHash: "f07f45f3634d3ea8c0f2cb676f56e20993edf9be07a83bf0dfdb3debcf1441bf"},
|
||||
expectedSignatureHash: "235f0766528865a4c478a46b0b3eef6b4760c6a05c792a452c06fab9ad0bd57c"},
|
||||
{name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyScriptPublicKey(0), // should change the hash
|
||||
expectedSignatureHash: "20a525c54dc33b2a61201f05233c086dbe8e06e9515775181ed96550b4f2d714"},
|
||||
expectedSignatureHash: "42b408acc6df78f1b1aef605339233af129b6e656788e8c93712e4954d28583d"},
|
||||
|
||||
// sigHashSingle
|
||||
{name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
expectedSignatureHash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005"},
|
||||
expectedSignatureHash: "c9f7adaa7a22af87195183cf1f10e368429139f16069597d5631a0f522e320a5"},
|
||||
{name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(0), // should change the hash
|
||||
expectedSignatureHash: "0fcaca1211f7ea44997717eb84c04c9c807db8b59797bc6800c2ccb135a5271c"},
|
||||
expectedSignatureHash: "af40fbd0ac061c586484c4f266d44007c0715eb0b80d20eb89be65325db05716"},
|
||||
{name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005"},
|
||||
expectedSignatureHash: "c9f7adaa7a22af87195183cf1f10e368429139f16069597d5631a0f522e320a5"},
|
||||
{name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifySequence(0), // should change the hash
|
||||
expectedSignatureHash: "83796d22879718eee1165d4aace667bb6778075dab579c32c57be945f466a451"},
|
||||
expectedSignatureHash: "c40f48b35fc933d5930c612c420e80bad336388126aaba6073588e31d95aca2c"},
|
||||
{name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "44a0b407ff7b239d447743dd503f7ad23db5b2ee4d25279bd3dffaf6b474e005"},
|
||||
expectedSignatureHash: "c9f7adaa7a22af87195183cf1f10e368429139f16069597d5631a0f522e320a5"},
|
||||
{name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2,
|
||||
expectedSignatureHash: "022ad967192f39d8d5895d243e025ec14cc7a79708c5e364894d4eff3cecb1b0"},
|
||||
expectedSignatureHash: "145487f676cd1d5f8042b9d042cc63bc0ecdf20563d324fa0b847714eeb94816"},
|
||||
{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: "022ad967192f39d8d5895d243e025ec14cc7a79708c5e364894d4eff3cecb1b0"},
|
||||
expectedSignatureHash: "145487f676cd1d5f8042b9d042cc63bc0ecdf20563d324fa0b847714eeb94816"},
|
||||
{name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0,
|
||||
expectedSignatureHash: "43b20aba775050cf9ba8d5e48fc7ed2dc6c071d23f30382aea58b7c59cfb8ed7"},
|
||||
expectedSignatureHash: "4f3f758e1ed9c438dcc241efd31dd07e6bf2e11e900e105eebd4d337391e48fe"},
|
||||
{name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2,
|
||||
expectedSignatureHash: "846689131fb08b77f83af1d3901076732ef09d3f8fdff945be89aa4300562e5f"},
|
||||
expectedSignatureHash: "200207998528ab3b58cbdfe578cd079572eb3093e68fb5c728e505b847e91c64"},
|
||||
|
||||
// subnetwork transaction
|
||||
{name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0,
|
||||
@@ -231,73 +230,73 @@ func TestCalculateSignatureHashECDSA(t *testing.T) {
|
||||
|
||||
// sigHashAll
|
||||
{name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
expectedSignatureHash: "1d679268414c20ffe952e3c255befd892e60e86ae1657fce8a20225e5dc87d64"},
|
||||
expectedSignatureHash: "6ec7f4949d0c095d78bf41475310fd38eb054f3e7c4240daf91ea888e4eb9a30"},
|
||||
{name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
modificationFunction: modifyInput(1), // should change the hash
|
||||
expectedSignatureHash: "c573469b9ec6551507371d26eaa75417905420577f56d0277c4234a99f2305d7"},
|
||||
expectedSignatureHash: "34fcc1cb538736c473c1778eba4df5f88c3d9f27508b0d842ec2348d097cd103"},
|
||||
{name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(1), // should change the hash
|
||||
expectedSignatureHash: "a92450b0662c120db3993b6bb258d06d2bcb983aa591d85f97adf8b7207a5db5"},
|
||||
expectedSignatureHash: "faf02d20d32f0e4536dfb0a86c67f97b394c11a34069bd74a2f7533ea964b10f"},
|
||||
{name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // should change the hash
|
||||
expectedSignatureHash: "c7a7524096499e4401a1592f892bada1afe7f7d276c4f0e691c993e17c03cf7d"},
|
||||
expectedSignatureHash: "25484c5dcc89d21e5b5858847964c8c2938d5090be54b21a590099ce4f792b14"},
|
||||
{name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
expectedSignatureHash: "13270aeb5b56d844d064d5d2cf06af7dbd0341fd55069b9af56d5e3c99f2eddd"},
|
||||
expectedSignatureHash: "458a711830a66d592c89845cd6406b525b5f89f4d9ca50abbdbb48dbb5adbb07"},
|
||||
{name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyInput(0), // should change the hash
|
||||
expectedSignatureHash: "981959e8c427ba4a06c3d53abc93514ba179d8cc7e94daeb4f516a0c2c685f86"},
|
||||
expectedSignatureHash: "67157f1984a881c71ea92c9959da1b856383489a8bb0150783cdc4d58bca95ea"},
|
||||
{name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyInput(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "13270aeb5b56d844d064d5d2cf06af7dbd0341fd55069b9af56d5e3c99f2eddd"},
|
||||
expectedSignatureHash: "458a711830a66d592c89845cd6406b525b5f89f4d9ca50abbdbb48dbb5adbb07"},
|
||||
{name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "13270aeb5b56d844d064d5d2cf06af7dbd0341fd55069b9af56d5e3c99f2eddd"},
|
||||
expectedSignatureHash: "458a711830a66d592c89845cd6406b525b5f89f4d9ca50abbdbb48dbb5adbb07"},
|
||||
|
||||
// sigHashNone
|
||||
{name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
expectedSignatureHash: "a45955ca970039160bb91b1ea42e070b4ff21598654aad91c562e8b9af922c5f"},
|
||||
expectedSignatureHash: "bf92d39b8381e49d4b2f37a7d2e2d9b4f126b6659cb873b84ae3db8910cd9664"},
|
||||
{name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "a45955ca970039160bb91b1ea42e070b4ff21598654aad91c562e8b9af922c5f"},
|
||||
expectedSignatureHash: "bf92d39b8381e49d4b2f37a7d2e2d9b4f126b6659cb873b84ae3db8910cd9664"},
|
||||
{name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
modificationFunction: modifySequence(0), // should change the hash
|
||||
expectedSignatureHash: "e1a430a24d77bc259ae572e1505dd67d3444ba0ffbc7918e06ae7e907e575adb"},
|
||||
expectedSignatureHash: "20550f85a6ac0d4b20ebb0d8df9b1f4ec0ecb3df5adf539c9d6ad9af03f712d6"},
|
||||
{name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "a45955ca970039160bb91b1ea42e070b4ff21598654aad91c562e8b9af922c5f"},
|
||||
expectedSignatureHash: "bf92d39b8381e49d4b2f37a7d2e2d9b4f126b6659cb873b84ae3db8910cd9664"},
|
||||
{name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
|
||||
expectedSignatureHash: "6bae2a0f1f7b9fd59804f4720a1a918be31b7ec12e184585fa16bda8c7f8c35c"},
|
||||
expectedSignatureHash: "a048ec7a396397e1357b42905f26c51d0ec6c0943298ff4f2b8707ec3e8e1aa0"},
|
||||
{name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyAmountSpent(0), // should change the hash
|
||||
expectedSignatureHash: "6653d3d882d2ffc1c3ff5b7ccf07f7970c5973b824abb5b117803809c5a884c7"},
|
||||
expectedSignatureHash: "66125d23d3dc9711683a6dbc96d4d4411af41e71f92596e9983ea8c5e3a04753"},
|
||||
{name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0,
|
||||
modificationFunction: modifyScriptPublicKey(0), // should change the hash
|
||||
expectedSignatureHash: "da3cb9094d905de69b3881cf8d4e2d5268bcf029dec5b62a972fcab90e6abde9"},
|
||||
expectedSignatureHash: "0ba5f527f8408b252eb77ea54efe63b831c736fea4bed58fc47c4ceaabf3f6cf"},
|
||||
|
||||
// sigHashSingle
|
||||
{name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
expectedSignatureHash: "964d03d8477dd468f3d9933676b5b4a976a68fee1760eae037be4247c36cc207"},
|
||||
expectedSignatureHash: "b21ec5c5e1830f8b9b3cb13bfbd542318a17d89d9844bd64167696ca36374f7f"},
|
||||
{name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(0), // should change the hash
|
||||
expectedSignatureHash: "7c51b4a7c6a6e786b1c420c859c2853131d7041b8ba8de72cbcd026b2e0d511b"},
|
||||
expectedSignatureHash: "e15914f6b22979f70162f5c57b3ad7ceff91b8a2356960f66a23dc8e602303fe"},
|
||||
{name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifyOutput(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "964d03d8477dd468f3d9933676b5b4a976a68fee1760eae037be4247c36cc207"},
|
||||
expectedSignatureHash: "b21ec5c5e1830f8b9b3cb13bfbd542318a17d89d9844bd64167696ca36374f7f"},
|
||||
{name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifySequence(0), // should change the hash
|
||||
expectedSignatureHash: "d31e5a9e71560d2f66483e7e4e7d41418b66cd22814450848a2d8fa78045d6a0"},
|
||||
expectedSignatureHash: "a09f20428456475bc5fcff07242416d439faa0dec37152e31a8546874f323473"},
|
||||
{name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0,
|
||||
modificationFunction: modifySequence(1), // shouldn't change the hash
|
||||
expectedSignatureHash: "964d03d8477dd468f3d9933676b5b4a976a68fee1760eae037be4247c36cc207"},
|
||||
expectedSignatureHash: "b21ec5c5e1830f8b9b3cb13bfbd542318a17d89d9844bd64167696ca36374f7f"},
|
||||
{name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2,
|
||||
expectedSignatureHash: "667b6b65682a6e1e14aec699a177d22ce1392661828e54dcd97cd83b05233d41"},
|
||||
expectedSignatureHash: "7cc3c80a6250599e47e4ceca66e3670b4fc74a009aba2b7df737bc37e8cb5b79"},
|
||||
{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: "667b6b65682a6e1e14aec699a177d22ce1392661828e54dcd97cd83b05233d41"},
|
||||
expectedSignatureHash: "7cc3c80a6250599e47e4ceca66e3670b4fc74a009aba2b7df737bc37e8cb5b79"},
|
||||
{name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0,
|
||||
expectedSignatureHash: "a11c2fbcd4f09bffce9e5fca62323388a2cf9037fd3be66211c7869c067123a2"},
|
||||
expectedSignatureHash: "8040f5ebfc6c5a8285272d5e1956dd3036eaa9a7abec9b18cb1b614a015f2fc7"},
|
||||
{name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2,
|
||||
expectedSignatureHash: "00f429dfb9150d7a96aa3f179bcc6f8fbf9bce481f00c6bb97af67e108e5d0ff"},
|
||||
expectedSignatureHash: "5e1ac311544301aa6afa578f18e1d1871ffbc15915e01f25f2375715c3a3147d"},
|
||||
|
||||
// subnetwork transaction
|
||||
{name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0,
|
||||
@@ -391,7 +390,7 @@ func generateTxs() (nativeTx, subnetworkTx *externalapi.DomainTransaction, err e
|
||||
Inputs: txIns,
|
||||
Outputs: txOuts,
|
||||
LockTime: 1615462089000,
|
||||
SubnetworkID: subnetworks.SubnetworkIDNative,
|
||||
SubnetworkID: externalapi.DomainSubnetworkID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
}
|
||||
subnetworkTx = &externalapi.DomainTransaction{
|
||||
Version: 0,
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
"P2SH"
|
||||
],
|
||||
[
|
||||
"Argument negative with by-DAAScore nLockTime=0"
|
||||
"Argument negative with by-blockheight nLockTime=0"
|
||||
],
|
||||
[
|
||||
[
|
||||
@@ -564,7 +564,7 @@
|
||||
"P2SH"
|
||||
],
|
||||
[
|
||||
"Argument negative with by-DAAScore txin.nSequence=0"
|
||||
"Argument negative with by-blockheight txin.nSequence=0"
|
||||
],
|
||||
[
|
||||
[
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,7 +6,6 @@ package txscript
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -3582,92 +3581,50 @@ 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()
|
||||
|
||||
// The signature in the p2sh script is nonsensical for most tests since
|
||||
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
|
||||
// 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, test.scriptPublicKey, true)
|
||||
count := GetPreciseSigOpCount(test.scriptSig, scriptPubKey, true)
|
||||
if count != test.nSigOps {
|
||||
t.Errorf("%s: expected count of %d, got %d", test.name,
|
||||
test.nSigOps, count)
|
||||
|
||||
@@ -37,17 +37,16 @@ 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
|
||||
|
||||
@@ -82,19 +82,18 @@ 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 {
|
||||
|
||||
@@ -75,21 +75,15 @@ 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
|
||||
@@ -98,10 +92,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:
|
||||
|
||||
@@ -3,10 +3,9 @@ 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
|
||||
@@ -20,40 +19,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-
|
||||
|
||||
@@ -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{
|
||||
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,
|
||||
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,
|
||||
})
|
||||
|
||||
// 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,
|
||||
525264379,
|
||||
0x207fffff,
|
||||
0x48e5e,
|
||||
0,
|
||||
0,
|
||||
|
||||
@@ -2,7 +2,6 @@ package domain
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/pkg/errors"
|
||||
"math"
|
||||
)
|
||||
|
||||
@@ -67,15 +66,11 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
|
||||
}
|
||||
|
||||
for _, blockHash := range pruningPointAndItsAnticone {
|
||||
block, found, err := syncer.GetBlock(blockHash)
|
||||
block, 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
|
||||
@@ -161,14 +156,11 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
|
||||
continue
|
||||
}
|
||||
|
||||
block, found, err := syncer.GetBlock(blocksHash)
|
||||
block, 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
|
||||
|
||||
@@ -147,12 +147,16 @@ func (btb *blockTemplateBuilder) BuildBlockTemplate(
|
||||
invalidTxsErr := ruleerrors.ErrInvalidTransactionsInNewBlock{}
|
||||
if errors.As(err, &invalidTxsErr) {
|
||||
log.Criticalf("consensusReference.Consensus().BuildBlock returned invalid txs in BuildBlockTemplate")
|
||||
err = btb.mempool.RemoveInvalidTransactions(&invalidTxsErr)
|
||||
invalidTxs := make([]*consensusexternalapi.DomainTransaction, 0, len(invalidTxsErr.InvalidTransactions))
|
||||
for _, tx := range invalidTxsErr.InvalidTransactions {
|
||||
invalidTxs = append(invalidTxs, tx.Transaction)
|
||||
}
|
||||
err = btb.mempool.RemoveTransactions(invalidTxs, true)
|
||||
if err != nil {
|
||||
// mempool.RemoveInvalidTransactions might return errors in situations that are perfectly fine in this context.
|
||||
// mempool.RemoveTransactions might return errors in situations that are perfectly fine in this context.
|
||||
// TODO: Once the mempool invariants are clear, this should be converted back `return nil, err`:
|
||||
// https://github.com/kaspanet/kaspad/issues/1553
|
||||
log.Criticalf("Error from mempool.RemoveInvalidTransactions: %+v", err)
|
||||
log.Criticalf("Error from mempool.RemoveTransactions: %+v", err)
|
||||
}
|
||||
// We can call this recursively without worry because this should almost never happen
|
||||
return btb.BuildBlockTemplate(coinbaseData)
|
||||
|
||||
@@ -51,7 +51,6 @@ const (
|
||||
RejectDifficulty RejectCode = 0x44
|
||||
RejectImmatureSpend RejectCode = 0x45
|
||||
RejectBadOrphan RejectCode = 0x64
|
||||
RejectSpamTx RejectCode = 0x65
|
||||
)
|
||||
|
||||
// Map of reject codes back strings for pretty printing.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"sync"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensusreference"
|
||||
@@ -144,57 +141,7 @@ func (mp *mempool) BlockCandidateTransactions() []*externalapi.DomainTransaction
|
||||
mp.mtx.RLock()
|
||||
defer mp.mtx.RUnlock()
|
||||
|
||||
readyTxs := mp.transactionsPool.allReadyTransactions()
|
||||
var candidateTxs []*externalapi.DomainTransaction
|
||||
var spamTx *externalapi.DomainTransaction
|
||||
var spamTxNewestUTXODaaScore uint64
|
||||
for _, tx := range readyTxs {
|
||||
if len(tx.Outputs) > len(tx.Inputs) {
|
||||
hasCoinbaseInput := false
|
||||
for _, input := range tx.Inputs {
|
||||
if input.UTXOEntry.IsCoinbase() {
|
||||
hasCoinbaseInput = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
numExtraOuts := len(tx.Outputs) - len(tx.Inputs)
|
||||
if !hasCoinbaseInput && numExtraOuts > 2 && tx.Fee < uint64(numExtraOuts)*constants.SompiPerKaspa {
|
||||
log.Debugf("Filtered spam tx %s", consensushashing.TransactionID(tx))
|
||||
continue
|
||||
}
|
||||
|
||||
if hasCoinbaseInput || tx.Fee > uint64(numExtraOuts)*constants.SompiPerKaspa {
|
||||
candidateTxs = append(candidateTxs, tx)
|
||||
} else {
|
||||
txNewestUTXODaaScore := tx.Inputs[0].UTXOEntry.BlockDAAScore()
|
||||
for _, input := range tx.Inputs {
|
||||
if input.UTXOEntry.BlockDAAScore() > txNewestUTXODaaScore {
|
||||
txNewestUTXODaaScore = input.UTXOEntry.BlockDAAScore()
|
||||
}
|
||||
}
|
||||
|
||||
if spamTx != nil {
|
||||
if txNewestUTXODaaScore < spamTxNewestUTXODaaScore {
|
||||
spamTx = tx
|
||||
spamTxNewestUTXODaaScore = txNewestUTXODaaScore
|
||||
}
|
||||
} else {
|
||||
spamTx = tx
|
||||
spamTxNewestUTXODaaScore = txNewestUTXODaaScore
|
||||
}
|
||||
}
|
||||
} else {
|
||||
candidateTxs = append(candidateTxs, tx)
|
||||
}
|
||||
}
|
||||
|
||||
if spamTx != nil {
|
||||
log.Debugf("Adding spam tx candidate %s", consensushashing.TransactionID(spamTx))
|
||||
candidateTxs = append(candidateTxs, spamTx)
|
||||
}
|
||||
|
||||
return candidateTxs
|
||||
return mp.transactionsPool.allReadyTransactions()
|
||||
}
|
||||
|
||||
func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error) {
|
||||
@@ -204,29 +151,11 @@ func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*ex
|
||||
return mp.revalidateHighPriorityTransactions()
|
||||
}
|
||||
|
||||
func (mp *mempool) RemoveInvalidTransactions(err *ruleerrors.ErrInvalidTransactionsInNewBlock) error {
|
||||
func (mp *mempool) RemoveTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error {
|
||||
mp.mtx.Lock()
|
||||
defer mp.mtx.Unlock()
|
||||
|
||||
for _, tx := range err.InvalidTransactions {
|
||||
ruleErr, success := tx.Error.(ruleerrors.RuleError)
|
||||
if !success {
|
||||
continue
|
||||
}
|
||||
|
||||
inner := ruleErr.Unwrap()
|
||||
removeRedeemers := true
|
||||
if _, ok := inner.(ruleerrors.ErrMissingTxOut); ok {
|
||||
removeRedeemers = false
|
||||
}
|
||||
|
||||
err := mp.removeTransaction(consensushashing.TransactionID(tx.Transaction), removeRedeemers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return mp.removeTransactions(transactions, removeRedeemers)
|
||||
}
|
||||
|
||||
func (mp *mempool) RemoveTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||
|
||||
@@ -2,9 +2,20 @@ package mempool
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||
)
|
||||
|
||||
func (mp *mempool) removeTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error {
|
||||
for _, transaction := range transactions {
|
||||
err := mp.removeTransaction(consensushashing.TransactionID(transaction), removeRedeemers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *mempool) removeTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||
if _, ok := mp.orphansPool.allOrphans[*transactionID]; ok {
|
||||
return mp.orphansPool.removeOrphan(transactionID, true)
|
||||
|
||||
@@ -7,85 +7,20 @@ import (
|
||||
)
|
||||
|
||||
func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTransaction, error) {
|
||||
type txNode struct {
|
||||
children map[externalapi.DomainTransactionID]struct{}
|
||||
nonVisitedParents int
|
||||
tx *model.MempoolTransaction
|
||||
visited bool
|
||||
}
|
||||
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "revalidateHighPriorityTransactions")
|
||||
defer onEnd()
|
||||
|
||||
// We revalidate transactions in topological order in case there are dependencies between them
|
||||
|
||||
// Naturally transactions point to their dependencies, but since we want to start processing the dependencies
|
||||
// first, we build the opposite DAG. We initially fill `queue` with transactions with no dependencies.
|
||||
txDAG := make(map[externalapi.DomainTransactionID]*txNode)
|
||||
|
||||
maybeAddNode := func(txID externalapi.DomainTransactionID) *txNode {
|
||||
if node, ok := txDAG[txID]; ok {
|
||||
return node
|
||||
}
|
||||
|
||||
node := &txNode{
|
||||
children: make(map[externalapi.DomainTransactionID]struct{}),
|
||||
nonVisitedParents: 0,
|
||||
tx: mp.transactionsPool.highPriorityTransactions[txID],
|
||||
}
|
||||
txDAG[txID] = node
|
||||
return node
|
||||
}
|
||||
|
||||
queue := make([]*txNode, 0, len(mp.transactionsPool.highPriorityTransactions))
|
||||
for id, transaction := range mp.transactionsPool.highPriorityTransactions {
|
||||
node := maybeAddNode(id)
|
||||
|
||||
parents := make(map[externalapi.DomainTransactionID]struct{})
|
||||
for _, input := range transaction.Transaction().Inputs {
|
||||
if _, ok := mp.transactionsPool.highPriorityTransactions[input.PreviousOutpoint.TransactionID]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
parents[input.PreviousOutpoint.TransactionID] = struct{}{} // To avoid duplicate parents, we first add it to a set and then count it
|
||||
maybeAddNode(input.PreviousOutpoint.TransactionID).children[id] = struct{}{}
|
||||
}
|
||||
node.nonVisitedParents = len(parents)
|
||||
|
||||
if node.nonVisitedParents == 0 {
|
||||
queue = append(queue, node)
|
||||
}
|
||||
}
|
||||
|
||||
validTransactions := []*externalapi.DomainTransaction{}
|
||||
|
||||
// Now we iterate the DAG in topological order using BFS
|
||||
for len(queue) > 0 {
|
||||
var node *txNode
|
||||
node, queue = queue[0], queue[1:]
|
||||
|
||||
if node.visited {
|
||||
continue
|
||||
}
|
||||
node.visited = true
|
||||
|
||||
transaction := node.tx
|
||||
for _, transaction := range mp.transactionsPool.highPriorityTransactions {
|
||||
isValid, err := mp.revalidateTransaction(transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for child := range node.children {
|
||||
childNode := txDAG[child]
|
||||
childNode.nonVisitedParents--
|
||||
if childNode.nonVisitedParents == 0 {
|
||||
queue = append(queue, txDAG[child])
|
||||
}
|
||||
if !isValid {
|
||||
continue
|
||||
}
|
||||
|
||||
if isValid {
|
||||
validTransactions = append(validTransactions, transaction.Transaction().Clone())
|
||||
}
|
||||
validTransactions = append(validTransactions, transaction.Transaction().Clone())
|
||||
}
|
||||
|
||||
return validTransactions, nil
|
||||
@@ -100,7 +35,7 @@ func (mp *mempool) revalidateTransaction(transaction *model.MempoolTransaction)
|
||||
}
|
||||
if len(missingParents) > 0 {
|
||||
log.Debugf("Removing transaction %s, it failed revalidation", transaction.TransactionID())
|
||||
err := mp.removeTransaction(transaction.TransactionID(), false)
|
||||
err := mp.removeTransaction(transaction.TransactionID(), true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
@@ -2,7 +2,6 @@ package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
@@ -45,20 +44,6 @@ func (mp *mempool) validateTransactionInIsolation(transaction *externalapi.Domai
|
||||
}
|
||||
|
||||
func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainTransaction) error {
|
||||
hasCoinbaseInput := false
|
||||
for _, input := range transaction.Inputs {
|
||||
if input.UTXOEntry.IsCoinbase() {
|
||||
hasCoinbaseInput = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
numExtraOuts := len(transaction.Outputs) - len(transaction.Inputs)
|
||||
if !hasCoinbaseInput && numExtraOuts > 2 && transaction.Fee < uint64(numExtraOuts)*constants.SompiPerKaspa {
|
||||
log.Warnf("Rejected spam tx %s from mempool (%d outputs)", consensushashing.TransactionID(transaction), len(transaction.Outputs))
|
||||
return transactionRuleError(RejectSpamTx, fmt.Sprintf("Rejected spam tx %s from mempool", consensushashing.TransactionID(transaction)))
|
||||
}
|
||||
|
||||
if !mp.config.AcceptNonStandard {
|
||||
err := mp.checkTransactionStandardInContext(transaction)
|
||||
if err != nil {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -577,72 +577,6 @@ func TestRevalidateHighPriorityTransactions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestRevalidateHighPriorityTransactionsWithChain(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestRevalidateHighPriorityTransactions")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
mempoolConfig := mempool.DefaultConfig(&consensusConfig.Params)
|
||||
tcAsConsensus := tc.(externalapi.Consensus)
|
||||
tcAsConsensusPointer := &tcAsConsensus
|
||||
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
||||
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempoolConfig)
|
||||
|
||||
const chainSize = 10
|
||||
chain, err := createTxChain(tc, chainSize)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = miningManager.ValidateAndInsertTransaction(chain[0], true, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
blockHash, _, err := tc.AddBlockOnTips(nil, []*externalapi.DomainTransaction{chain[0].Clone()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block, _, err := tc.GetBlock(blockHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = miningManager.HandleNewBlockTransactions(block.Transactions)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, transaction := range chain[1:] {
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transaction, true, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err = tc.AddBlockOnTips(nil, []*externalapi.DomainTransaction{chain[1].Clone()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
revalidated, err := miningManager.RevalidateHighPriorityTransactions()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(revalidated) != chainSize-2 {
|
||||
t.Fatalf("expected %d transactions to revalidate but instead only %d revalidated", chainSize-2, len(revalidated))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestModifyBlockTemplate verifies that modifying a block template changes coinbase data correctly.
|
||||
func TestModifyBlockTemplate(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
@@ -714,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)
|
||||
}
|
||||
@@ -970,58 +904,40 @@ func createArraysOfParentAndChildrenTransactions(tc testapi.TestConsensus) ([]*e
|
||||
func createParentAndChildrenTransactions(tc testapi.TestConsensus) (txParent *externalapi.DomainTransaction,
|
||||
txChild *externalapi.DomainTransaction, err error) {
|
||||
|
||||
chain, err := createTxChain(tc, 2)
|
||||
// We will add two blocks by consensus before the parent transactions, in order to fund the parent transactions.
|
||||
tips, err := tc.Tips()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return chain[0], chain[1], nil
|
||||
}
|
||||
|
||||
func createTxChain(tc testapi.TestConsensus, numTxs int) ([]*externalapi.DomainTransaction, error) {
|
||||
// We will add two blocks by consensus before the parent transactions, in order to fund the parent transactions.
|
||||
tips, err := tc.Tips()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, err = tc.AddBlock(tips, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "AddBlock: %v", err)
|
||||
return nil, nil, errors.Wrapf(err, "AddBlock: %v", err)
|
||||
}
|
||||
|
||||
tips, err = tc.Tips()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fundingBlockHashForParent, _, err := tc.AddBlock(tips, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "AddBlock: ")
|
||||
return nil, nil, errors.Wrap(err, "AddBlock: ")
|
||||
}
|
||||
fundingBlockForParent, _, err := tc.GetBlock(fundingBlockHashForParent)
|
||||
fundingBlockForParent, err := tc.GetBlock(fundingBlockHashForParent)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBlock: ")
|
||||
return nil, nil, errors.Wrap(err, "GetBlock: ")
|
||||
}
|
||||
fundingTransactionForParent := fundingBlockForParent.Transactions[transactionhelper.CoinbaseTransactionIndex]
|
||||
|
||||
transactions := make([]*externalapi.DomainTransaction, numTxs)
|
||||
transactions[0], err = testutils.CreateTransaction(fundingTransactionForParent, 1000)
|
||||
txParent, err = testutils.CreateTransaction(fundingTransactionForParent, 1000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
txParent := transactions[0]
|
||||
for i := 1; i < numTxs; i++ {
|
||||
transactions[i], err = testutils.CreateTransaction(txParent, 1000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txParent = transactions[i]
|
||||
txChild, err = testutils.CreateTransaction(txParent, 1000)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return transactions, nil
|
||||
return txParent, txChild, nil
|
||||
}
|
||||
|
||||
func createChildAndParentTxsAndAddParentToConsensus(tc testapi.TestConsensus) (*externalapi.DomainTransaction, error) {
|
||||
@@ -1033,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: ")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package model
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
)
|
||||
|
||||
// Mempool maintains a set of known transactions that
|
||||
@@ -12,7 +11,7 @@ type Mempool interface {
|
||||
BlockCandidateTransactions() []*externalapi.DomainTransaction
|
||||
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
||||
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
||||
RemoveInvalidTransactions(err *ruleerrors.ErrInvalidTransactionsInNewBlock) error
|
||||
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
||||
GetTransaction(
|
||||
transactionID *externalapi.DomainTransactionID,
|
||||
includeTransactionPool bool,
|
||||
|
||||
@@ -52,8 +52,6 @@ func (ui *UTXOIndex) Reset() error {
|
||||
ui.mutex.Lock()
|
||||
defer ui.mutex.Unlock()
|
||||
|
||||
log.Infof("Starting UTXO index reset")
|
||||
|
||||
err := ui.store.deleteAll()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,13 +88,7 @@ func (ui *UTXOIndex) Reset() error {
|
||||
}
|
||||
|
||||
// This has to be done last to mark that the reset went smoothly and no reset has to be called next time.
|
||||
err = ui.store.updateAndCommitVirtualParentsWithoutTransaction(virtualInfo.ParentHashes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("Finished UTXO index reset")
|
||||
return nil
|
||||
return ui.store.updateAndCommitVirtualParentsWithoutTransaction(virtualInfo.ParentHashes)
|
||||
}
|
||||
|
||||
func (ui *UTXOIndex) isSynced() (bool, error) {
|
||||
|
||||
10
go.mod
10
go.mod
@@ -16,18 +16,18 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
golang.org/x/crypto v0.1.0
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd
|
||||
golang.org/x/term v0.5.0
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||
google.golang.org/grpc v1.38.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // 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
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
)
|
||||
|
||||
18
go.sum
18
go.sum
@@ -86,8 +86,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4=
|
||||
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
@@ -105,9 +105,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -121,16 +120,15 @@ 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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
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.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -105,16 +105,7 @@ 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 {
|
||||
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
|
||||
return testConsensus.GetBlock(hash)
|
||||
}
|
||||
|
||||
parentHashes := make([]*externalapi.DomainHash, len(blockData.Parents))
|
||||
|
||||
@@ -4,7 +4,7 @@ ARG KASPAMINER_IMAGE
|
||||
FROM ${KASPAD_IMAGE} as kaspad
|
||||
FROM ${KASPAMINER_IMAGE} as kaspaminer
|
||||
|
||||
FROM golang:1.19-alpine
|
||||
FROM golang:1.18-alpine
|
||||
|
||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ func TestGenerateFastPruningIBDTest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
tip, _, err := tc.GetBlock(tipHash)
|
||||
tip, err := tc.GetBlock(tipHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -105,18 +105,23 @@ func TestAddresses(t *testing.T) {
|
||||
// ECDSA P2PK tests.
|
||||
{
|
||||
name: "mainnet ecdsa p2pk",
|
||||
addr: "kaspa:qyp0r5mcq4rd5grj3652ra09u5dcgwqq9ntuswp247nama5quyj40eq03sc2dkx",
|
||||
encoded: "kaspa:qyp0r5mcq4rd5grj3652ra09u5dcgwqq9ntuswp247nama5quyj40eq03sc2dkx",
|
||||
addr: "kaspa:q835ennsep3hxfe7lnz5ee7j5jgmkjswsn35ennsep3hxfe7ln35e2sm7yrlr4w",
|
||||
encoded: "kaspa:q835ennsep3hxfe7lnz5ee7j5jgmkjswsn35ennsep3hxfe7ln35e2sm7yrlr4w",
|
||||
valid: true,
|
||||
result: util.TstAddressPubKeyECDSA(
|
||||
util.Bech32PrefixKaspa,
|
||||
[util.PublicKeySizeECDSA]byte{
|
||||
0x02, 0xf1, 0xd3, 0x78, 0x05, 0x46, 0xda, 0x20, 0x72, 0x8e, 0xa8, 0xa1, 0xf5, 0xe5, 0xe5, 0x1b, 0x84, 0x38, 0x00, 0x2c, 0xd7, 0xc8, 0x38, 0x2a, 0xaf, 0xa7, 0xdd, 0xf6, 0x80, 0xe1, 0x25, 0x57, 0xe4,
|
||||
0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
|
||||
0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84,
|
||||
0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
|
||||
0xe3, 0x4c, 0xaa,
|
||||
}),
|
||||
f: func() (util.Address, error) {
|
||||
publicKey := []byte{
|
||||
0x02, 0xf1, 0xd3, 0x78, 0x05, 0x46, 0xda, 0x20, 0x72, 0x8e, 0xa8, 0xa1, 0xf5, 0xe5, 0xe5, 0x1b, 0x84, 0x38, 0x00, 0x2c, 0xd7, 0xc8, 0x38, 0x2a, 0xaf, 0xa7, 0xdd, 0xf6, 0x80, 0xe1, 0x25, 0x57, 0xe4,
|
||||
}
|
||||
0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
|
||||
0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84,
|
||||
0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
|
||||
0xe3, 0x4c, 0xaa}
|
||||
return util.NewAddressPublicKeyECDSA(publicKey, util.Bech32PrefixKaspa)
|
||||
},
|
||||
passedPrefix: util.Bech32PrefixUnknown,
|
||||
|
||||
@@ -95,12 +95,11 @@ func appDir(goos, appName string, roaming bool) string {
|
||||
// (%LOCALAPPDATA%) that is used by default.
|
||||
//
|
||||
// Example results:
|
||||
//
|
||||
// dir := AppDir("myapp", false)
|
||||
// POSIX (Linux/BSD): ~/.myapp
|
||||
// Mac OS: $HOME/Library/Application Support/Myapp
|
||||
// Windows: %LOCALAPPDATA%\Myapp
|
||||
// Plan 9: $home/myapp
|
||||
// dir := AppDir("myapp", false)
|
||||
// POSIX (Linux/BSD): ~/.myapp
|
||||
// Mac OS: $HOME/Library/Application Support/Myapp
|
||||
// Windows: %LOCALAPPDATA%\Myapp
|
||||
// Plan 9: $home/myapp
|
||||
func AppDir(appName string, roaming bool) string {
|
||||
return appDir(runtime.GOOS, appName, roaming)
|
||||
}
|
||||
|
||||
@@ -22,21 +22,18 @@ var (
|
||||
// Like IEEE754 floating point, there are three basic components: the sign,
|
||||
// the exponent, and the mantissa. They are broken out as follows:
|
||||
//
|
||||
// - the most significant 8 bits represent the unsigned base 256 exponent
|
||||
// * the most significant 8 bits represent the unsigned base 256 exponent
|
||||
// * bit 23 (the 24th bit) represents the sign bit
|
||||
// * the least significant 23 bits represent the mantissa
|
||||
//
|
||||
// - bit 23 (the 24th bit) represents the sign bit
|
||||
//
|
||||
// - the least significant 23 bits represent the mantissa
|
||||
//
|
||||
// -------------------------------------------------
|
||||
// | Exponent | Sign | Mantissa |
|
||||
// -------------------------------------------------
|
||||
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
|
||||
// -------------------------------------------------
|
||||
// -------------------------------------------------
|
||||
// | Exponent | Sign | Mantissa |
|
||||
// -------------------------------------------------
|
||||
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
|
||||
// -------------------------------------------------
|
||||
//
|
||||
// The formula to calculate N is:
|
||||
//
|
||||
// N = (-1^sign) * mantissa * 256^(exponent-3)
|
||||
// N = (-1^sign) * mantissa * 256^(exponent-3)
|
||||
func CompactToBig(compact uint32) *big.Int {
|
||||
destination := big.NewInt(0)
|
||||
CompactToBigWithDestination(compact, destination)
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestGetHashrateString(t *testing.T) {
|
||||
var results = map[string]string{
|
||||
dagconfig.MainnetParams.Name: "1.53 GH/s",
|
||||
dagconfig.TestnetParams.Name: "131.07 KH/s",
|
||||
dagconfig.DevnetParams.Name: "830 H/s",
|
||||
dagconfig.DevnetParams.Name: "2 H/s",
|
||||
dagconfig.SimnetParams.Name: "2.00 KH/s",
|
||||
}
|
||||
testutils.ForAllNets(t, false, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
Package util provides kaspa-specific convenience functions and types.
|
||||
|
||||
# Block Overview
|
||||
Block Overview
|
||||
|
||||
A Block defines a kaspa block that provides easier and more efficient
|
||||
manipulation of raw blocks. It also memoizes hashes for the
|
||||
block and its transactions on their first access so subsequent accesses don't
|
||||
have to repeat the relatively expensive hashing operations.
|
||||
|
||||
# Tx Overview
|
||||
Tx Overview
|
||||
|
||||
A Tx defines a kaspa transaction that provides more efficient manipulation of
|
||||
raw transactions. It memoizes the hash for the transaction on its
|
||||
first access so subsequent accesses don't have to repeat the relatively
|
||||
expensive hashing operations.
|
||||
|
||||
# Address Overview
|
||||
Address Overview
|
||||
|
||||
The Address interface provides an abstraction for a kaspa address. While the
|
||||
most common type is a pay-to-pubkey, kaspa already supports others and
|
||||
|
||||
@@ -28,7 +28,6 @@ func (t Time) UnixSeconds() int64 {
|
||||
}
|
||||
|
||||
// String returns the time formatted using the format string
|
||||
//
|
||||
// "2006-01-02 15:04:05.999999999 -0700 MST"
|
||||
func (t Time) String() string {
|
||||
return t.time.String()
|
||||
|
||||
@@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
|
||||
const (
|
||||
appMajor uint = 0
|
||||
appMinor uint = 12
|
||||
appPatch uint = 15
|
||||
appPatch uint = 8
|
||||
)
|
||||
|
||||
// appBuild is defined as a variable so it can be overridden during the build
|
||||
|
||||
Reference in New Issue
Block a user