mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-24 14:35:53 +00:00
Merge branch 'dev' into dependabot/go_modules/golang.org/x/text-0.3.8
This commit is contained in:
commit
5849adf3ee
2
.github/workflows/deploy.yaml
vendored
2
.github/workflows/deploy.yaml
vendored
@ -23,7 +23,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.19
|
||||||
|
|
||||||
- name: Build on Linux
|
- name: Build on Linux
|
||||||
if: runner.os == '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
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.19
|
||||||
|
|
||||||
- name: Set scheduled branch name
|
- name: Set scheduled branch name
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
6
.github/workflows/tests.yaml
vendored
6
.github/workflows/tests.yaml
vendored
@ -33,7 +33,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.19
|
||||||
|
|
||||||
|
|
||||||
# Source: https://github.com/actions/cache/blob/main/examples.md#go---modules
|
# Source: https://github.com/actions/cache/blob/main/examples.md#go---modules
|
||||||
@ -58,7 +58,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.19
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@ -86,7 +86,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.19
|
||||||
|
|
||||||
- name: Delete the stability tests from coverage
|
- name: Delete the stability tests from coverage
|
||||||
run: rm -r stability-tests
|
run: rm -r stability-tests
|
||||||
|
|||||||
@ -6,7 +6,7 @@ supported kaspa messages to and from the appmessage. This package does not deal
|
|||||||
with the specifics of message handling such as what to do when a message is
|
with the specifics of message handling such as what to do when a message is
|
||||||
received. This provides the caller with a high level of flexibility.
|
received. This provides the caller with a high level of flexibility.
|
||||||
|
|
||||||
Kaspa Message Overview
|
# Kaspa Message Overview
|
||||||
|
|
||||||
The kaspa protocol consists of exchanging messages between peers. Each
|
The kaspa protocol consists of exchanging messages between peers. Each
|
||||||
message is preceded by a header which identifies information about it such as
|
message is preceded by a header which identifies information about it such as
|
||||||
@ -22,7 +22,7 @@ messages, all of the details of marshalling and unmarshalling to and from the
|
|||||||
appmessage using kaspa encoding are handled so the caller doesn't have to concern
|
appmessage using kaspa encoding are handled so the caller doesn't have to concern
|
||||||
themselves with the specifics.
|
themselves with the specifics.
|
||||||
|
|
||||||
Message Interaction
|
# Message Interaction
|
||||||
|
|
||||||
The following provides a quick summary of how the kaspa messages are intended
|
The following provides a quick summary of how the kaspa messages are intended
|
||||||
to interact with one another. As stated above, these interactions are not
|
to interact with one another. As stated above, these interactions are not
|
||||||
@ -45,13 +45,13 @@ interactions in no particular order.
|
|||||||
notfound message (MsgNotFound)
|
notfound message (MsgNotFound)
|
||||||
ping message (MsgPing) pong message (MsgPong)
|
ping message (MsgPing) pong message (MsgPong)
|
||||||
|
|
||||||
Common Parameters
|
# Common Parameters
|
||||||
|
|
||||||
There are several common parameters that arise when using this package to read
|
There are several common parameters that arise when using this package to read
|
||||||
and write kaspa messages. The following sections provide a quick overview of
|
and write kaspa messages. The following sections provide a quick overview of
|
||||||
these parameters so the next sections can build on them.
|
these parameters so the next sections can build on them.
|
||||||
|
|
||||||
Protocol Version
|
# Protocol Version
|
||||||
|
|
||||||
The protocol version should be negotiated with the remote peer at a higher
|
The protocol version should be negotiated with the remote peer at a higher
|
||||||
level than this package via the version (MsgVersion) message exchange, however,
|
level than this package via the version (MsgVersion) message exchange, however,
|
||||||
@ -60,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
|
for all outbound connections before a potentially lower protocol version is
|
||||||
negotiated.
|
negotiated.
|
||||||
|
|
||||||
Kaspa Network
|
# Kaspa Network
|
||||||
|
|
||||||
The kaspa network is a magic number which is used to identify the start of a
|
The kaspa network is a magic number which is used to identify the start of a
|
||||||
message and which kaspa network the message applies to. This package provides
|
message and which kaspa network the message applies to. This package provides
|
||||||
the following constants:
|
the following constants:
|
||||||
|
|
||||||
appmessage.Mainnet
|
appmessage.Mainnet
|
||||||
appmessage.Testnet (Test network)
|
appmessage.Testnet (Test network)
|
||||||
appmessage.Simnet (Simulation test network)
|
appmessage.Simnet (Simulation test network)
|
||||||
appmessage.Devnet (Development network)
|
appmessage.Devnet (Development network)
|
||||||
|
|
||||||
Determining Message Type
|
# Determining Message Type
|
||||||
|
|
||||||
As discussed in the kaspa message overview section, this package reads
|
As discussed in the kaspa message overview section, this package reads
|
||||||
and writes kaspa messages using a generic interface named Message. In
|
and writes kaspa messages using a generic interface named Message. In
|
||||||
@ -89,7 +89,7 @@ switch or type assertion. An example of a type switch follows:
|
|||||||
fmt.Printf("Number of tx in block: %d", msg.Header.TxnCount)
|
fmt.Printf("Number of tx in block: %d", msg.Header.TxnCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
Reading Messages
|
# Reading Messages
|
||||||
|
|
||||||
In order to unmarshall kaspa messages from the appmessage, use the ReadMessage
|
In order to unmarshall kaspa messages from the appmessage, use the ReadMessage
|
||||||
function. It accepts any io.Reader, but typically this will be a net.Conn to
|
function. It accepts any io.Reader, but typically this will be a net.Conn to
|
||||||
@ -104,7 +104,7 @@ a remote node running a kaspa peer. Example syntax is:
|
|||||||
// Log and handle the error
|
// Log and handle the error
|
||||||
}
|
}
|
||||||
|
|
||||||
Writing Messages
|
# Writing Messages
|
||||||
|
|
||||||
In order to marshall kaspa messages to the appmessage, use the WriteMessage
|
In order to marshall kaspa messages to the appmessage, use the WriteMessage
|
||||||
function. It accepts any io.Writer, but typically this will be a net.Conn to
|
function. It accepts any io.Writer, but typically this will be a net.Conn to
|
||||||
@ -122,7 +122,7 @@ from a remote peer is:
|
|||||||
// Log and handle the error
|
// Log and handle the error
|
||||||
}
|
}
|
||||||
|
|
||||||
Errors
|
# Errors
|
||||||
|
|
||||||
Errors returned by this package are either the raw errors provided by underlying
|
Errors returned by this package are either the raw errors provided by underlying
|
||||||
calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and
|
calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and
|
||||||
|
|||||||
@ -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{
|
var blockOne = MsgBlock{
|
||||||
Header: MsgBlockHeader{
|
Header: MsgBlockHeader{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ kaspactl is an RPC client for kaspad
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
Go 1.18 or later.
|
Go 1.19 or later.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# -- multistage docker build: stage #1: build stage
|
# -- multistage docker build: stage #1: build stage
|
||||||
FROM golang:1.18-alpine AS build
|
FROM golang:1.19-alpine AS build
|
||||||
|
|
||||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ Kaspaminer is a CPU-based miner for kaspad
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
Go 1.18 or later.
|
Go 1.19 or later.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# -- multistage docker build: stage #1: build stage
|
# -- multistage docker build: stage #1: build stage
|
||||||
FROM golang:1.18-alpine AS build
|
FROM golang:1.19-alpine AS build
|
||||||
|
|
||||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
Package base58 provides an API for working with modified base58 and Base58Check
|
Package base58 provides an API for working with modified base58 and Base58Check
|
||||||
encodings.
|
encodings.
|
||||||
|
|
||||||
Modified Base58 Encoding
|
# Modified Base58 Encoding
|
||||||
|
|
||||||
Standard base58 encoding is similar to standard base64 encoding except, as the
|
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
|
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
|
0, O, I, and l characters that look the same in many fonts and are therefore
|
||||||
hard to humans to distinguish.
|
hard to humans to distinguish.
|
||||||
|
|
||||||
Base58Check Encoding Scheme
|
# Base58Check Encoding Scheme
|
||||||
|
|
||||||
The Base58Check encoding scheme is primarily used for Bitcoin addresses at the
|
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
|
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"
|
"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) {
|
func KaspawalletdUTXOsTolibkaspawalletUTXOs(kaspawalletdUtxoEntires []*pb.UtxosByAddressesEntry) ([]*UTXO, error) {
|
||||||
UTXOs := make([]*UTXO, len(kaspawalletdUtxoEntires))
|
UTXOs := make([]*UTXO, len(kaspawalletdUtxoEntires))
|
||||||
for i, entry := range kaspawalletdUtxoEntires {
|
for i, entry := range kaspawalletdUtxoEntires {
|
||||||
|
|||||||
@ -88,7 +88,7 @@ func SerializePartiallySignedTransaction(partiallySignedTransaction *PartiallySi
|
|||||||
return proto.Marshal(partiallySignedTransactionToProto(partiallySignedTransaction))
|
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) {
|
func DeserializeDomainTransaction(serializedTransactionMessage []byte) (*externalapi.DomainTransaction, error) {
|
||||||
protoTransactionMessage := &protoserialization.TransactionMessage{}
|
protoTransactionMessage := &protoserialization.TransactionMessage{}
|
||||||
err := proto.Unmarshal(serializedTransactionMessage, protoTransactionMessage)
|
err := proto.Unmarshal(serializedTransactionMessage, protoTransactionMessage)
|
||||||
|
|||||||
6
doc.go
6
doc.go
@ -13,10 +13,12 @@ the box' for most users. However, there are also a wide variety of flags that
|
|||||||
can be used to control it.
|
can be used to control it.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
kaspad [OPTIONS]
|
|
||||||
|
kaspad [OPTIONS]
|
||||||
|
|
||||||
For an up-to-date help message:
|
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
|
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
|
file that is automatically parsed when kaspad starts up. By default, the
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# -- multistage docker build: stage #1: build stage
|
# -- multistage docker build: stage #1: build stage
|
||||||
FROM golang:1.18-alpine AS build
|
FROM golang:1.19-alpine AS build
|
||||||
|
|
||||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||||
|
|
||||||
|
|||||||
@ -10,10 +10,12 @@ package externalapi
|
|||||||
//
|
//
|
||||||
// For example, assume a selected parent chain with IDs as depicted below, and the
|
// For example, assume a selected parent chain with IDs as depicted below, and the
|
||||||
// stop block is genesis:
|
// 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:
|
// 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
|
type BlockLocator []*DomainHash
|
||||||
|
|
||||||
// Clone returns a clone of BlockLocator
|
// Clone returns a clone of BlockLocator
|
||||||
|
|||||||
@ -146,8 +146,8 @@ func (v *blockValidator) validateDifficulty(stagingArea *model.StagingArea,
|
|||||||
// target difficulty as claimed.
|
// target difficulty as claimed.
|
||||||
//
|
//
|
||||||
// The flags modify the behavior of this function as follows:
|
// The flags modify the behavior of this function as follows:
|
||||||
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
|
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
|
||||||
// difficulty is not performed.
|
// difficulty is not performed.
|
||||||
func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error {
|
func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error {
|
||||||
// The target difficulty must be larger than zero.
|
// The target difficulty must be larger than zero.
|
||||||
state := pow.NewState(header.ToMutable())
|
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.
|
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)
|
To regenerate this table, run `TestBuildSubsidyTable` in coinbasemanager_test.go (note the `deflationaryPhaseBaseSubsidy` therein)
|
||||||
*/
|
*/
|
||||||
var subsidyByDeflationaryMonthTable = []uint64{
|
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,
|
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,
|
||||||
|
|||||||
@ -159,8 +159,9 @@ func TestDoubleSpends(t *testing.T) {
|
|||||||
// TestTransactionAcceptance checks that block transactions are accepted correctly when the merge set is sorted topologically.
|
// TestTransactionAcceptance checks that block transactions are accepted correctly when the merge set is sorted topologically.
|
||||||
// DAG diagram:
|
// DAG diagram:
|
||||||
// genesis <- blockA <- blockB <- blockC <- ..(chain of k-blocks).. lastBlockInChain <- blockD <- blockE <- blockF <- blockG
|
// genesis <- blockA <- blockB <- blockC <- ..(chain of k-blocks).. lastBlockInChain <- blockD <- blockE <- blockF <- blockG
|
||||||
// ^ ^ |
|
//
|
||||||
// | redBlock <------------------------ blueChildOfRedBlock <-------------------------------
|
// ^ ^ |
|
||||||
|
// | redBlock <------------------------ blueChildOfRedBlock <-------------------------------
|
||||||
func TestTransactionAcceptance(t *testing.T) {
|
func TestTransactionAcceptance(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
stagingArea := model.NewStagingArea()
|
stagingArea := model.NewStagingArea()
|
||||||
|
|||||||
@ -30,14 +30,14 @@ func (bg *blockGHOSTDAGData) toModel() *externalapi.BlockGHOSTDAGData {
|
|||||||
//
|
//
|
||||||
// 1) |anticone-of-candidate-block ∩ blue-set-of-newBlock| ≤ K
|
// 1) |anticone-of-candidate-block ∩ blue-set-of-newBlock| ≤ K
|
||||||
//
|
//
|
||||||
// 2) For every blue block in blue-set-of-newBlock:
|
// 2. For every blue block in blue-set-of-newBlock:
|
||||||
// |(anticone-of-blue-block ∩ blue-set-newBlock) ∪ {candidate-block}| ≤ K.
|
// |(anticone-of-blue-block ∩ blue-set-newBlock) ∪ {candidate-block}| ≤ K.
|
||||||
// We validate this condition by maintaining a map BluesAnticoneSizes for
|
// We validate this condition by maintaining a map BluesAnticoneSizes for
|
||||||
// each block which holds all the blue anticone sizes that were affected by
|
// each block which holds all the blue anticone sizes that were affected by
|
||||||
// the new added blue blocks.
|
// the new added blue blocks.
|
||||||
// So to find out what is |anticone-of-blue ∩ blue-set-of-newBlock| we just iterate in
|
// 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
|
// the selected parent chain of the new block until we find an existing entry in
|
||||||
// BluesAnticoneSizes.
|
// BluesAnticoneSizes.
|
||||||
//
|
//
|
||||||
// For further details see the article https://eprint.iacr.org/2018/104.pdf
|
// For further details see the article https://eprint.iacr.org/2018/104.pdf
|
||||||
func (gm *ghostdagManager) GHOSTDAG(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) error {
|
func (gm *ghostdagManager) GHOSTDAG(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) error {
|
||||||
|
|||||||
@ -12,13 +12,13 @@ import (
|
|||||||
// interval contains B's interval, it replaces it.
|
// interval contains B's interval, it replaces it.
|
||||||
//
|
//
|
||||||
// Notes:
|
// Notes:
|
||||||
// * Intervals never intersect unless one contains the other
|
// - Intervals never intersect unless one contains the other
|
||||||
// (this follows from the tree structure and the indexing rule).
|
// (this follows from the tree structure and the indexing rule).
|
||||||
// * Since node.FutureCoveringSet is kept ordered, a binary search can be
|
// - Since node.FutureCoveringSet is kept ordered, a binary search can be
|
||||||
// used for insertion/queries.
|
// used for insertion/queries.
|
||||||
// * Although reindexing may change a block's interval, the
|
// - Although reindexing may change a block's interval, the
|
||||||
// is-superset relation will by definition
|
// is-superset relation will by definition
|
||||||
// be always preserved.
|
// be always preserved.
|
||||||
func (rt *reachabilityManager) insertToFutureCoveringSet(stagingArea *model.StagingArea, node, futureNode *externalapi.DomainHash) error {
|
func (rt *reachabilityManager) insertToFutureCoveringSet(stagingArea *model.StagingArea, node, futureNode *externalapi.DomainHash) error {
|
||||||
reachabilityData, err := rt.reachabilityDataForInsertion(stagingArea, node)
|
reachabilityData, err := rt.reachabilityDataForInsertion(stagingArea, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -161,7 +161,9 @@ func intervalSplitWithExponentialBias(ri *model.ReachabilityInterval, sizes []ui
|
|||||||
|
|
||||||
// exponentialFractions returns a fraction of each size in sizes
|
// exponentialFractions returns a fraction of each size in sizes
|
||||||
// as follows:
|
// 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)
|
// 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])
|
// to avoid exploding numbers. Note that in 1 / 2^(max(size)-size[i])
|
||||||
// we divide 1 by potentially a very large number, which will
|
// 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.
|
// and populates the provided subTreeSizeMap with the results.
|
||||||
// It is equivalent to the following recursive implementation:
|
// It is equivalent to the following recursive implementation:
|
||||||
//
|
//
|
||||||
// func (rt *reachabilityManager) countSubtrees(node *model.ReachabilityTreeNode) uint64 {
|
// func (rt *reachabilityManager) countSubtrees(node *model.ReachabilityTreeNode) uint64 {
|
||||||
// subtreeSize := uint64(0)
|
// subtreeSize := uint64(0)
|
||||||
// for _, child := range node.children {
|
// for _, child := range node.children {
|
||||||
// subtreeSize += child.countSubtrees()
|
// subtreeSize += child.countSubtrees()
|
||||||
// }
|
// }
|
||||||
// return subtreeSize + 1
|
// return subtreeSize + 1
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// However, we are expecting (linearly) deep trees, and so a
|
// However, we are expecting (linearly) deep trees, and so a
|
||||||
// recursive stack-based approach is inefficient and will hit
|
// recursive stack-based approach is inefficient and will hit
|
||||||
|
|||||||
@ -4,7 +4,7 @@ Package txscript implements the kaspa transaction script language.
|
|||||||
This package provides data structures and functions to parse and execute
|
This package provides data structures and functions to parse and execute
|
||||||
kaspa transaction scripts.
|
kaspa transaction scripts.
|
||||||
|
|
||||||
Script Overview
|
# Script Overview
|
||||||
|
|
||||||
Kaspa transaction scripts are written in a stack-base, FORTH-like language.
|
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
|
One benefit of using a scripting language is added flexibility in specifying
|
||||||
what conditions must be met in order to spend kaspa.
|
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
|
Errors returned by this package are of type txscript.Error. This allows the
|
||||||
caller to programmatically determine the specific error by examining 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
|
// Error identifies a script-related error. It is used to indicate three
|
||||||
// classes of errors:
|
// classes of errors:
|
||||||
// 1) Script execution failures due to violating one of the many requirements
|
// 1. Script execution failures due to violating one of the many requirements
|
||||||
// imposed by the script engine or evaluating to false
|
// imposed by the script engine or evaluating to false
|
||||||
// 2) Improper API usage by callers
|
// 2. Improper API usage by callers
|
||||||
// 3) Internal consistency check failures
|
// 3. Internal consistency check failures
|
||||||
//
|
//
|
||||||
// The caller can use type assertions on the returned errors to access the
|
// 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
|
// ErrorCode field to ascertain the specific reason for the error. As an
|
||||||
|
|||||||
@ -37,16 +37,17 @@ func (e ErrScriptNotCanonical) Error() string {
|
|||||||
// For example, the following would build a 2-of-3 multisig script for usage in
|
// 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
|
// a pay-to-script-hash (although in this situation MultiSigScript() would be a
|
||||||
// better choice to generate the script):
|
// better choice to generate the script):
|
||||||
// builder := txscript.NewScriptBuilder()
|
//
|
||||||
// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
|
// builder := txscript.NewScriptBuilder()
|
||||||
// builder.AddData(pubKey3).AddOp(txscript.OP_3)
|
// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
|
||||||
// builder.AddOp(txscript.OP_CHECKMULTISIG)
|
// builder.AddData(pubKey3).AddOp(txscript.OP_3)
|
||||||
// script, err := builder.Script()
|
// builder.AddOp(txscript.OP_CHECKMULTISIG)
|
||||||
// if err != nil {
|
// script, err := builder.Script()
|
||||||
// // Handle the error.
|
// if err != nil {
|
||||||
// return
|
// // Handle the error.
|
||||||
// }
|
// return
|
||||||
// fmt.Printf("Final multi-sig script: %x\n", script)
|
// }
|
||||||
|
// fmt.Printf("Final multi-sig script: %x\n", script)
|
||||||
type ScriptBuilder struct {
|
type ScriptBuilder struct {
|
||||||
script []byte
|
script []byte
|
||||||
err error
|
err error
|
||||||
|
|||||||
@ -82,18 +82,19 @@ func checkMinimalDataEncoding(v []byte) error {
|
|||||||
// Bytes returns the number serialized as a little endian with a sign bit.
|
// Bytes returns the number serialized as a little endian with a sign bit.
|
||||||
//
|
//
|
||||||
// Example encodings:
|
// Example encodings:
|
||||||
// 127 -> [0x7f]
|
//
|
||||||
// -127 -> [0xff]
|
// 127 -> [0x7f]
|
||||||
// 128 -> [0x80 0x00]
|
// -127 -> [0xff]
|
||||||
// -128 -> [0x80 0x80]
|
// 128 -> [0x80 0x00]
|
||||||
// 129 -> [0x81 0x00]
|
// -128 -> [0x80 0x80]
|
||||||
// -129 -> [0x81 0x80]
|
// 129 -> [0x81 0x00]
|
||||||
// 256 -> [0x00 0x01]
|
// -129 -> [0x81 0x80]
|
||||||
// -256 -> [0x00 0x81]
|
// 256 -> [0x00 0x01]
|
||||||
// 32767 -> [0xff 0x7f]
|
// -256 -> [0x00 0x81]
|
||||||
// -32767 -> [0xff 0xff]
|
// 32767 -> [0xff 0x7f]
|
||||||
// 32768 -> [0x00 0x80 0x00]
|
// -32767 -> [0xff 0xff]
|
||||||
// -32768 -> [0x00 0x80 0x80]
|
// 32768 -> [0x00 0x80 0x00]
|
||||||
|
// -32768 -> [0x00 0x80 0x80]
|
||||||
func (n scriptNum) Bytes() []byte {
|
func (n scriptNum) Bytes() []byte {
|
||||||
// Zero encodes as an empty byte slice.
|
// Zero encodes as an empty byte slice.
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
|||||||
@ -75,15 +75,21 @@ func subtractionWithRemainderHavingDAAScoreInPlace(collection1, collection2, res
|
|||||||
//
|
//
|
||||||
// diffFrom follows a set of rules represented by the following 3 by 3 table:
|
// 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
|
// other | toAdd | - | X | toAdd
|
||||||
// ---------+-----------+-----------+-----------+-----------
|
// ---------+-----------+-----------+-----------+-----------
|
||||||
// | toRemove | X | - | toRemove
|
//
|
||||||
|
// | toRemove | X | - | toRemove
|
||||||
|
//
|
||||||
// ---------+-----------+-----------+-----------+-----------
|
// ---------+-----------+-----------+-----------+-----------
|
||||||
// | None | toRemove | toAdd | -
|
//
|
||||||
|
// | None | toRemove | toAdd | -
|
||||||
//
|
//
|
||||||
// Key:
|
// Key:
|
||||||
// - Don't add anything to the result
|
// - Don't add anything to the result
|
||||||
@ -92,10 +98,10 @@ func subtractionWithRemainderHavingDAAScoreInPlace(collection1, collection2, res
|
|||||||
// toRemove Add the UTXO into the toRemove collection of the result
|
// toRemove Add the UTXO into the toRemove collection of the result
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// 1. This diff contains a UTXO in toAdd, and the other diff contains it in toRemove
|
// 1. This diff contains a UTXO in toAdd, and the other diff contains it in toRemove
|
||||||
// diffFrom results in an error
|
// diffFrom results in an error
|
||||||
// 2. This diff contains a UTXO in toRemove, and the other diff does not contain it
|
// 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
|
// diffFrom results in the UTXO being added to toAdd
|
||||||
func diffFrom(this, other *mutableUTXODiff) (*mutableUTXODiff, error) {
|
func diffFrom(this, other *mutableUTXODiff) (*mutableUTXODiff, error) {
|
||||||
// Note that the following cases are not accounted for, as they are impossible
|
// Note that the following cases are not accounted for, as they are impossible
|
||||||
// as long as the base utxoSet is the same:
|
// as long as the base utxoSet is the same:
|
||||||
|
|||||||
@ -3,9 +3,10 @@ Package dagconfig defines DAG configuration parameters.
|
|||||||
|
|
||||||
In addition to the main Kaspa network, which is intended for the transfer
|
In addition to the main Kaspa network, which is intended for the transfer
|
||||||
of monetary value, there also exists the following standard networks:
|
of monetary value, there also exists the following standard networks:
|
||||||
* testnet
|
- testnet
|
||||||
* simnet
|
- simnet
|
||||||
* devnet
|
- devnet
|
||||||
|
|
||||||
These networks are incompatible with each other (each sharing a different
|
These networks are incompatible with each other (each sharing a different
|
||||||
genesis block) and software should handle errors where input intended for
|
genesis block) and software should handle errors where input intended for
|
||||||
one network is used on an application instance running on a different
|
one network is used on an application instance running on a different
|
||||||
@ -19,40 +20,40 @@ one of the standard Param vars for use as the application's "active" network.
|
|||||||
When a network parameter is needed, it may then be looked up through this
|
When a network parameter is needed, it may then be looked up through this
|
||||||
variable (either directly, or hidden in a library call).
|
variable (either directly, or hidden in a library call).
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
"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.
|
// By default (without --testnet), use mainnet.
|
||||||
var dagParams = &dagconfig.MainnetParams
|
var dagParams = &dagconfig.MainnetParams
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Modify active network parameters if operating on testnet.
|
// Modify active network parameters if operating on testnet.
|
||||||
if *testnet {
|
if *testnet {
|
||||||
dagParams = &dagconfig.TestnetParams
|
dagParams = &dagconfig.TestnetParams
|
||||||
}
|
}
|
||||||
|
|
||||||
// later...
|
// later...
|
||||||
|
|
||||||
// Create and print new payment address, specific to the active network.
|
// Create and print new payment address, specific to the active network.
|
||||||
pubKey := make([]byte, 32)
|
pubKey := make([]byte, 32)
|
||||||
addr, err := util.NewAddressPubKey(pubKey, dagParams)
|
addr, err := util.NewAddressPubKey(pubKey, dagParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
fmt.Println(addr)
|
fmt.Println(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
If an application does not use one of the standard Kaspa networks, a new
|
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-
|
Params struct may be created which defines the parameters for the non-
|
||||||
|
|||||||
@ -207,10 +207,10 @@ func DefaultConfig() *Config {
|
|||||||
// line options.
|
// line options.
|
||||||
//
|
//
|
||||||
// The configuration proceeds as follows:
|
// The configuration proceeds as follows:
|
||||||
// 1) Start with a default config with sane settings
|
// 1. Start with a default config with sane settings
|
||||||
// 2) Pre-parse the command line to check for an alternative config file
|
// 2. Pre-parse the command line to check for an alternative config file
|
||||||
// 3) Load configuration file overwriting defaults with any specified options
|
// 3. Load configuration file overwriting defaults with any specified options
|
||||||
// 4) Parse CLI options and overwrite/add any specified options
|
// 4. Parse CLI options and overwrite/add any specified options
|
||||||
//
|
//
|
||||||
// The above results in kaspad functioning properly without any config settings
|
// The above results in kaspad functioning properly without any config settings
|
||||||
// while still allowing the user to override settings with config files and
|
// while still allowing the user to override settings with config files and
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Package database provides a database for kaspad.
|
Package database provides a database for kaspad.
|
||||||
|
|
||||||
Overview
|
# Overview
|
||||||
|
|
||||||
This package provides a database layer to store and retrieve data in a simple
|
This package provides a database layer to store and retrieve data in a simple
|
||||||
and efficient manner.
|
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:
|
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
|
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. 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.
|
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.
|
This defines the interface of a generic kaspad database transaction.
|
||||||
Note: transactions provide data consistency over the state of the database as it was
|
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
|
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.
|
transaction then it will be available to get within the same transaction.
|
||||||
|
|
||||||
Cursor
|
# Cursor
|
||||||
|
|
||||||
This iterates over database entries given some bucket.
|
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
|
LOGFLAGS options can be specified, separated by commas. The following options
|
||||||
are recognized:
|
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.
|
shortfile: Include the filename and line number in all log messages.
|
||||||
Overrides longfile.
|
Overrides longfile.
|
||||||
*/
|
*/
|
||||||
package logger
|
package logger
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Package addressmanager implements concurrency safe Kaspa address manager.
|
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
|
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
|
of addresses to connect to as nodes come and go. The Kaspa protocol provides
|
||||||
|
|||||||
@ -4,7 +4,7 @@ ARG KASPAMINER_IMAGE
|
|||||||
FROM ${KASPAD_IMAGE} as kaspad
|
FROM ${KASPAD_IMAGE} as kaspad
|
||||||
FROM ${KASPAMINER_IMAGE} as kaspaminer
|
FROM ${KASPAMINER_IMAGE} as kaspaminer
|
||||||
|
|
||||||
FROM golang:1.18-alpine
|
FROM golang:1.19-alpine
|
||||||
|
|
||||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||||
|
|
||||||
|
|||||||
@ -95,11 +95,12 @@ func appDir(goos, appName string, roaming bool) string {
|
|||||||
// (%LOCALAPPDATA%) that is used by default.
|
// (%LOCALAPPDATA%) that is used by default.
|
||||||
//
|
//
|
||||||
// Example results:
|
// Example results:
|
||||||
// dir := AppDir("myapp", false)
|
//
|
||||||
// POSIX (Linux/BSD): ~/.myapp
|
// dir := AppDir("myapp", false)
|
||||||
// Mac OS: $HOME/Library/Application Support/Myapp
|
// POSIX (Linux/BSD): ~/.myapp
|
||||||
// Windows: %LOCALAPPDATA%\Myapp
|
// Mac OS: $HOME/Library/Application Support/Myapp
|
||||||
// Plan 9: $home/myapp
|
// Windows: %LOCALAPPDATA%\Myapp
|
||||||
|
// Plan 9: $home/myapp
|
||||||
func AppDir(appName string, roaming bool) string {
|
func AppDir(appName string, roaming bool) string {
|
||||||
return appDir(runtime.GOOS, appName, roaming)
|
return appDir(runtime.GOOS, appName, roaming)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,18 +22,21 @@ var (
|
|||||||
// Like IEEE754 floating point, there are three basic components: the sign,
|
// Like IEEE754 floating point, there are three basic components: the sign,
|
||||||
// the exponent, and the mantissa. They are broken out as follows:
|
// 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
|
||||||
// | Exponent | Sign | Mantissa |
|
//
|
||||||
// -------------------------------------------------
|
// - the least significant 23 bits represent the 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:
|
// 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 {
|
func CompactToBig(compact uint32) *big.Int {
|
||||||
destination := big.NewInt(0)
|
destination := big.NewInt(0)
|
||||||
CompactToBigWithDestination(compact, destination)
|
CompactToBigWithDestination(compact, destination)
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
Package util provides kaspa-specific convenience functions and types.
|
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
|
A Block defines a kaspa block that provides easier and more efficient
|
||||||
manipulation of raw blocks. It also memoizes hashes for the
|
manipulation of raw blocks. It also memoizes hashes for the
|
||||||
block and its transactions on their first access so subsequent accesses don't
|
block and its transactions on their first access so subsequent accesses don't
|
||||||
have to repeat the relatively expensive hashing operations.
|
have to repeat the relatively expensive hashing operations.
|
||||||
|
|
||||||
Tx Overview
|
# Tx Overview
|
||||||
|
|
||||||
A Tx defines a kaspa transaction that provides more efficient manipulation of
|
A Tx defines a kaspa transaction that provides more efficient manipulation of
|
||||||
raw transactions. It memoizes the hash for the transaction on its
|
raw transactions. It memoizes the hash for the transaction on its
|
||||||
first access so subsequent accesses don't have to repeat the relatively
|
first access so subsequent accesses don't have to repeat the relatively
|
||||||
expensive hashing operations.
|
expensive hashing operations.
|
||||||
|
|
||||||
Address Overview
|
# Address Overview
|
||||||
|
|
||||||
The Address interface provides an abstraction for a kaspa address. While the
|
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
|
most common type is a pay-to-pubkey, kaspa already supports others and
|
||||||
|
|||||||
@ -28,6 +28,7 @@ func (t Time) UnixSeconds() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// String returns the time formatted using the format string
|
// String returns the time formatted using the format string
|
||||||
|
//
|
||||||
// "2006-01-02 15:04:05.999999999 -0700 MST"
|
// "2006-01-02 15:04:05.999999999 -0700 MST"
|
||||||
func (t Time) String() string {
|
func (t Time) String() string {
|
||||||
return t.time.String()
|
return t.time.String()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user