2018-02-01 20:28:45 +00:00
package core
2018-02-04 19:54:51 +00:00
import (
2019-09-23 17:13:44 +00:00
"bytes"
2018-03-09 15:55:25 +00:00
"fmt"
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
"math"
2019-11-15 14:52:47 +00:00
"math/big"
2019-09-30 14:39:42 +00:00
"sort"
2019-11-11 15:25:28 +00:00
"strconv"
2020-02-04 15:43:21 +00:00
"sync"
2018-03-09 15:55:25 +00:00
"sync/atomic"
2018-02-04 19:54:51 +00:00
"time"
2018-03-25 10:45:54 +00:00
"github.com/CityOfZion/neo-go/config"
2020-01-14 12:32:07 +00:00
"github.com/CityOfZion/neo-go/pkg/core/block"
2020-01-15 07:52:59 +00:00
"github.com/CityOfZion/neo-go/pkg/core/mempool"
2019-11-28 16:06:09 +00:00
"github.com/CityOfZion/neo-go/pkg/core/state"
2018-03-17 11:53:21 +00:00
"github.com/CityOfZion/neo-go/pkg/core/storage"
2018-03-21 16:11:04 +00:00
"github.com/CityOfZion/neo-go/pkg/core/transaction"
2019-11-11 15:25:28 +00:00
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
2019-09-16 09:18:13 +00:00
"github.com/CityOfZion/neo-go/pkg/io"
2019-10-10 14:56:58 +00:00
"github.com/CityOfZion/neo-go/pkg/smartcontract"
2019-12-04 09:27:04 +00:00
"github.com/CityOfZion/neo-go/pkg/smartcontract/trigger"
2018-02-04 19:54:51 +00:00
"github.com/CityOfZion/neo-go/pkg/util"
2019-09-23 17:13:44 +00:00
"github.com/CityOfZion/neo-go/pkg/vm"
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
"github.com/pkg/errors"
2019-12-30 07:43:05 +00:00
"go.uber.org/zap"
2018-02-04 19:54:51 +00:00
)
2019-10-22 14:56:03 +00:00
// Tuning parameters.
2018-02-01 20:28:45 +00:00
const (
2018-03-09 15:55:25 +00:00
headerBatchCount = 2000
2019-11-26 15:24:54 +00:00
version = "0.0.3"
2019-09-30 14:27:41 +00:00
// This one comes from C# code and it's different from the constant used
// when creating an asset with Neo.Asset.Create interop call. It looks
// like 2000000 is coming from the decrementInterval, but C# code doesn't
// contain any relationship between the two, so we should follow this
// behavior.
registeredAssetLifetime = 2 * 2000000
2020-01-22 14:28:02 +00:00
defaultMemPoolSize = 50000
2018-02-01 20:28:45 +00:00
)
2020-02-04 15:43:21 +00:00
var (
// ErrAlreadyExists is returned when trying to add some already existing
// transaction into the pool (not specifying whether it exists in the
// chain or mempool).
ErrAlreadyExists = errors . New ( "already exists" )
// ErrOOM is returned when adding transaction to the memory pool because
// it reached its full capacity.
ErrOOM = errors . New ( "no space left in the memory pool" )
)
2018-02-01 20:28:45 +00:00
var (
2018-03-25 10:45:54 +00:00
genAmount = [ ] int { 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }
decrementInterval = 2000000
2018-04-13 10:14:08 +00:00
persistInterval = 1 * time . Second
2018-02-01 20:28:45 +00:00
)
2018-03-25 10:45:54 +00:00
// Blockchain represents the blockchain.
2018-02-01 20:28:45 +00:00
type Blockchain struct {
2018-03-25 10:45:54 +00:00
config config . ProtocolConfiguration
2020-02-04 15:43:21 +00:00
// The only way chain state changes is by adding blocks, so we can't
// allow concurrent block additions. It differs from the next lock in
// that it's only for AddBlock method itself, the chain state is
// protected by the lock below, but holding it during all of AddBlock
// is too expensive (because the state only changes when persisting
// change cache).
addLock sync . Mutex
// This lock ensures blockchain immutability for operations that need
// that while performing their tasks. It's mostly used as a read lock
// with the only writer being the block addition logic.
lock sync . RWMutex
2019-11-25 17:39:11 +00:00
// Data access object for CRUD operations around storage.
dao * dao
2019-09-26 15:14:00 +00:00
2018-03-09 15:55:25 +00:00
// Current index/height of the highest block.
// Read access should always be called by BlockHeight().
2019-09-26 15:14:00 +00:00
// Write access should only happen in storeBlock().
2018-03-09 15:55:25 +00:00
blockHeight uint32
2018-02-04 19:54:51 +00:00
2019-12-23 16:18:12 +00:00
// Current top Block wrapped in an atomic.Value for safe access.
topBlock atomic . Value
2019-09-24 15:51:20 +00:00
// Current persisted block count.
persistedHeight uint32
2018-03-17 11:53:21 +00:00
// Number of headers stored in the chain file.
2018-02-06 06:43:32 +00:00
storedHeaderCount uint32
2019-10-22 14:56:03 +00:00
// All operations on headerList must be called from an
2018-03-17 11:53:21 +00:00
// headersOp to be routine safe.
headerList * HeaderHashList
2018-03-09 15:55:25 +00:00
// Only for operating on the headerList.
headersOp chan headersOpFunc
headersOpDone chan struct { }
2018-03-10 12:04:06 +00:00
2019-11-07 17:47:48 +00:00
// Stop synchronization mechanisms.
stopCh chan struct { }
runToExitCh chan struct { }
2020-01-15 12:10:05 +00:00
memPool mempool . Pool
2019-12-10 16:13:29 +00:00
// cache for block verification keys.
keyCache map [ util . Uint160 ] map [ string ] * keys . PublicKey
2019-12-30 07:43:05 +00:00
log * zap . Logger
2018-02-01 20:28:45 +00:00
}
2018-03-09 15:55:25 +00:00
type headersOpFunc func ( headerList * HeaderHashList )
2018-02-06 06:43:32 +00:00
2019-10-22 14:56:03 +00:00
// NewBlockchain returns a new blockchain object the will use the
2018-03-17 11:53:21 +00:00
// given Store as its underlying storage.
2019-12-30 07:43:05 +00:00
func NewBlockchain ( s storage . Store , cfg config . ProtocolConfiguration , log * zap . Logger ) ( * Blockchain , error ) {
if log == nil {
return nil , errors . New ( "empty logger" )
}
2020-01-22 14:28:02 +00:00
if cfg . MemPoolSize <= 0 {
cfg . MemPoolSize = defaultMemPoolSize
log . Info ( "mempool size is not set or wrong, setting default value" , zap . Int ( "MemPoolSize" , cfg . MemPoolSize ) )
}
2018-03-09 15:55:25 +00:00
bc := & Blockchain {
2018-03-25 10:45:54 +00:00
config : cfg ,
2019-12-12 18:04:55 +00:00
dao : newDao ( s ) ,
2018-03-09 15:55:25 +00:00
headersOp : make ( chan headersOpFunc ) ,
headersOpDone : make ( chan struct { } ) ,
2019-11-07 17:47:48 +00:00
stopCh : make ( chan struct { } ) ,
runToExitCh : make ( chan struct { } ) ,
2020-01-22 14:28:02 +00:00
memPool : mempool . NewMemPool ( cfg . MemPoolSize ) ,
2019-12-10 16:13:29 +00:00
keyCache : make ( map [ util . Uint160 ] map [ string ] * keys . PublicKey ) ,
2019-12-30 07:43:05 +00:00
log : log ,
2018-03-09 15:55:25 +00:00
}
2018-02-06 06:43:32 +00:00
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
if err := bc . init ( ) ; err != nil {
2018-03-17 11:53:21 +00:00
return nil , err
}
return bc , nil
2018-02-04 19:54:51 +00:00
}
2018-03-17 11:53:21 +00:00
func ( bc * Blockchain ) init ( ) error {
2018-04-09 16:58:09 +00:00
// If we could not find the version in the Store, we know that there is nothing stored.
2019-11-25 17:39:11 +00:00
ver , err := bc . dao . GetVersion ( )
2018-04-09 16:58:09 +00:00
if err != nil {
2019-12-30 07:43:05 +00:00
bc . log . Info ( "no storage version found! creating genesis block" )
2019-11-25 17:39:11 +00:00
if err = bc . dao . PutVersion ( version ) ; err != nil {
2019-01-25 11:20:35 +00:00
return err
}
2019-09-11 17:28:49 +00:00
genesisBlock , err := createGenesisBlock ( bc . config )
if err != nil {
return err
}
bc . headerList = NewHeaderHashList ( genesisBlock . Hash ( ) )
2019-11-25 17:39:11 +00:00
err = bc . dao . PutCurrentHeader ( hashAndIndexToBytes ( genesisBlock . Hash ( ) , genesisBlock . Index ) )
2019-11-06 14:56:06 +00:00
if err != nil {
return err
}
2019-09-26 15:14:00 +00:00
return bc . storeBlock ( genesisBlock )
2018-04-09 16:58:09 +00:00
}
if ver != version {
return fmt . Errorf ( "storage version mismatch betweeen %s and %s" , version , ver )
2018-03-25 10:45:54 +00:00
}
// At this point there was no version found in the storage which
// implies a creating fresh storage with the version specified
// and the genesis block as first block.
2019-12-30 07:43:05 +00:00
bc . log . Info ( "restoring blockchain" , zap . String ( "version" , version ) )
2018-03-25 10:45:54 +00:00
2019-11-25 17:39:11 +00:00
bHeight , err := bc . dao . GetCurrentBlockHeight ( )
2018-03-25 10:45:54 +00:00
if err != nil {
2018-03-17 11:53:21 +00:00
return err
}
2018-04-09 16:58:09 +00:00
bc . blockHeight = bHeight
2019-09-24 15:51:20 +00:00
bc . persistedHeight = bHeight
2018-03-17 11:53:21 +00:00
2019-11-25 17:39:11 +00:00
hashes , err := bc . dao . GetHeaderHashes ( )
2018-03-17 11:53:21 +00:00
if err != nil {
return err
}
2018-03-25 10:45:54 +00:00
2019-09-11 17:28:49 +00:00
bc . headerList = NewHeaderHashList ( hashes ... )
bc . storedHeaderCount = uint32 ( len ( hashes ) )
2018-03-17 11:53:21 +00:00
2019-11-25 17:39:11 +00:00
currHeaderHeight , currHeaderHash , err := bc . dao . GetCurrentHeaderHeight ( )
2018-03-17 11:53:21 +00:00
if err != nil {
return err
}
2019-11-06 14:58:19 +00:00
if bc . storedHeaderCount == 0 && currHeaderHeight == 0 {
bc . headerList . Add ( currHeaderHash )
}
2018-03-17 11:53:21 +00:00
2018-04-09 16:58:09 +00:00
// There is a high chance that the Node is stopped before the next
2018-03-17 11:53:21 +00:00
// batch of 2000 headers was stored. Via the currentHeaders stored we can sync
// that with stored blocks.
2019-11-29 11:22:31 +00:00
if currHeaderHeight >= bc . storedHeaderCount {
2018-03-17 11:53:21 +00:00
hash := currHeaderHash
2019-10-21 05:37:01 +00:00
var targetHash util . Uint256
if bc . headerList . Len ( ) > 0 {
targetHash = bc . headerList . Get ( bc . headerList . Len ( ) - 1 )
} else {
genesisBlock , err := createGenesisBlock ( bc . config )
if err != nil {
return err
}
targetHash = genesisBlock . Hash ( )
2019-11-06 15:00:14 +00:00
bc . headerList . Add ( targetHash )
2019-10-21 05:37:01 +00:00
}
2020-01-14 12:32:07 +00:00
headers := make ( [ ] * block . Header , 0 )
2018-03-17 11:53:21 +00:00
for hash != targetHash {
2019-02-20 17:39:32 +00:00
header , err := bc . GetHeader ( hash )
2018-03-17 11:53:21 +00:00
if err != nil {
return fmt . Errorf ( "could not get header %s: %s" , hash , err )
}
headers = append ( headers , header )
hash = header . PrevHash
}
headerSliceReverse ( headers )
2019-09-25 14:52:46 +00:00
for _ , h := range headers {
if ! h . Verify ( ) {
return fmt . Errorf ( "bad header %d/%s in the storage" , h . Index , h . Hash ( ) )
}
bc . headerList . Add ( h . Hash ( ) )
2018-03-17 11:53:21 +00:00
}
}
return nil
2018-03-09 15:55:25 +00:00
}
2019-09-17 12:27:40 +00:00
// Run runs chain loop.
2019-11-07 17:47:48 +00:00
func ( bc * Blockchain ) Run ( ) {
2018-03-17 11:53:21 +00:00
persistTimer := time . NewTimer ( persistInterval )
2019-09-16 15:52:47 +00:00
defer func ( ) {
persistTimer . Stop ( )
2019-10-21 07:04:58 +00:00
if err := bc . persist ( ) ; err != nil {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "failed to persist" , zap . Error ( err ) )
2019-09-26 15:14:00 +00:00
}
2019-11-25 17:39:11 +00:00
if err := bc . dao . store . Close ( ) ; err != nil {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "failed to close db" , zap . Error ( err ) )
2019-09-16 15:52:47 +00:00
}
2019-11-07 17:47:48 +00:00
close ( bc . runToExitCh )
2019-09-16 15:52:47 +00:00
} ( )
2018-03-09 15:55:25 +00:00
for {
select {
2019-11-07 17:47:48 +00:00
case <- bc . stopCh :
2019-02-19 11:48:48 +00:00
return
2018-03-09 15:55:25 +00:00
case op := <- bc . headersOp :
2018-03-17 11:53:21 +00:00
op ( bc . headerList )
2018-03-09 15:55:25 +00:00
bc . headersOpDone <- struct { } { }
2018-03-14 09:36:59 +00:00
case <- persistTimer . C :
2019-09-18 15:21:16 +00:00
go func ( ) {
2019-10-21 07:04:58 +00:00
err := bc . persist ( )
2019-09-22 17:06:52 +00:00
if err != nil {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "failed to persist blockchain" , zap . Error ( err ) )
2019-09-22 17:06:52 +00:00
}
2019-09-18 15:21:16 +00:00
} ( )
2018-03-14 09:36:59 +00:00
persistTimer . Reset ( persistInterval )
2018-03-09 15:55:25 +00:00
}
2018-02-04 19:54:51 +00:00
}
}
2019-11-07 17:47:48 +00:00
// Close stops Blockchain's internal loop, syncs changes to persistent storage
// and closes it. The Blockchain is no longer functional after the call to Close.
func ( bc * Blockchain ) Close ( ) {
close ( bc . stopCh )
<- bc . runToExitCh
}
2019-09-26 15:14:00 +00:00
// AddBlock accepts successive block for the Blockchain, verifies it and
// stores internally. Eventually it will be persisted to the backing storage.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) AddBlock ( block * block . Block ) error {
2020-02-04 15:43:21 +00:00
bc . addLock . Lock ( )
defer bc . addLock . Unlock ( )
2019-09-26 15:14:00 +00:00
expectedHeight := bc . BlockHeight ( ) + 1
if expectedHeight != block . Index {
return fmt . Errorf ( "expected block %d, but passed block %d" , expectedHeight , block . Index )
2018-03-09 15:55:25 +00:00
}
2019-10-11 14:46:47 +00:00
if bc . config . VerifyBlocks {
2019-10-15 09:52:10 +00:00
err := block . Verify ( )
if err == nil {
err = bc . VerifyBlock ( block )
}
2019-10-11 08:40:54 +00:00
if err != nil {
2019-11-27 09:23:18 +00:00
return fmt . Errorf ( "block %s is invalid: %s" , block . Hash ( ) . StringLE ( ) , err )
2019-09-30 14:35:11 +00:00
}
2019-10-11 14:46:47 +00:00
if bc . config . VerifyTransactions {
for _ , tx := range block . Transactions {
err := bc . VerifyTx ( tx , block )
if err != nil {
2019-11-27 09:23:18 +00:00
return fmt . Errorf ( "transaction %s failed to verify: %s" , tx . Hash ( ) . StringLE ( ) , err )
2019-10-11 14:46:47 +00:00
}
2019-09-30 14:35:11 +00:00
}
}
2018-02-04 19:54:51 +00:00
}
2019-09-26 15:14:00 +00:00
headerLen := bc . headerListLen ( )
2018-02-04 19:54:51 +00:00
if int ( block . Index ) == headerLen {
2019-09-24 15:51:20 +00:00
err := bc . AddHeaders ( block . Header ( ) )
if err != nil {
return err
}
}
2019-09-26 15:14:00 +00:00
return bc . storeBlock ( block )
2018-02-04 19:54:51 +00:00
}
2019-10-22 14:56:03 +00:00
// AddHeaders processes the given headers and add them to the
2018-03-14 09:36:59 +00:00
// HeaderHashList.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) AddHeaders ( headers ... * block . Header ) ( err error ) {
2018-03-09 15:55:25 +00:00
var (
start = time . Now ( )
2019-11-25 17:39:11 +00:00
batch = bc . dao . store . Batch ( )
2018-03-09 15:55:25 +00:00
)
bc . headersOp <- func ( headerList * HeaderHashList ) {
2019-10-07 16:55:33 +00:00
oldlen := headerList . Len ( )
2018-03-09 15:55:25 +00:00
for _ , h := range headers {
if int ( h . Index - 1 ) >= headerList . Len ( ) {
err = fmt . Errorf (
2018-03-17 11:53:21 +00:00
"height of received header %d is higher then the current header %d" ,
2018-03-09 15:55:25 +00:00
h . Index , headerList . Len ( ) ,
)
return
}
if int ( h . Index ) < headerList . Len ( ) {
continue
}
if ! h . Verify ( ) {
err = fmt . Errorf ( "header %v is invalid" , h )
return
}
if err = bc . processHeader ( h , batch , headerList ) ; err != nil {
return
}
2018-02-04 19:54:51 +00:00
}
2019-10-07 16:55:33 +00:00
if oldlen != headerList . Len ( ) {
2019-11-06 13:09:45 +00:00
updateHeaderHeightMetric ( headerList . Len ( ) - 1 )
2019-11-25 17:39:11 +00:00
if err = bc . dao . store . PutBatch ( batch ) ; err != nil {
2018-03-09 15:55:25 +00:00
return
}
2019-12-30 07:43:05 +00:00
bc . log . Debug ( "done processing headers" ,
zap . Int ( "headerIndex" , headerList . Len ( ) - 1 ) ,
zap . Uint32 ( "blockHeight" , bc . BlockHeight ( ) ) ,
zap . Duration ( "took" , time . Since ( start ) ) )
2018-02-06 06:43:32 +00:00
}
2018-02-04 19:54:51 +00:00
}
2018-03-09 15:55:25 +00:00
<- bc . headersOpDone
return err
2018-02-06 06:43:32 +00:00
}
2018-02-04 19:54:51 +00:00
2018-03-09 15:55:25 +00:00
// processHeader processes the given header. Note that this is only thread safe
// if executed in headers operation.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) processHeader ( h * block . Header , batch storage . Batch , headerList * HeaderHashList ) error {
2018-03-09 15:55:25 +00:00
headerList . Add ( h . Hash ( ) )
2018-02-04 19:54:51 +00:00
2019-09-16 09:18:13 +00:00
buf := io . NewBufBinWriter ( )
2018-03-09 15:55:25 +00:00
for int ( h . Index ) - headerBatchCount >= int ( bc . storedHeaderCount ) {
2019-09-16 09:18:13 +00:00
if err := headerList . Write ( buf . BinWriter , int ( bc . storedHeaderCount ) , headerBatchCount ) ; err != nil {
2018-03-09 15:55:25 +00:00
return err
}
2018-03-17 11:53:21 +00:00
key := storage . AppendPrefixInt ( storage . IXHeaderHashList , int ( bc . storedHeaderCount ) )
2018-03-14 09:36:59 +00:00
batch . Put ( key , buf . Bytes ( ) )
2018-03-09 15:55:25 +00:00
bc . storedHeaderCount += headerBatchCount
buf . Reset ( )
2018-02-04 19:54:51 +00:00
}
2018-03-09 15:55:25 +00:00
buf . Reset ( )
2019-09-16 16:31:49 +00:00
h . EncodeBinary ( buf . BinWriter )
if buf . Err != nil {
return buf . Err
2018-02-04 19:54:51 +00:00
}
2019-11-27 09:23:18 +00:00
key := storage . AppendPrefix ( storage . DataBlock , h . Hash ( ) . BytesLE ( ) )
2018-03-14 09:36:59 +00:00
batch . Put ( key , buf . Bytes ( ) )
2018-03-17 11:53:21 +00:00
batch . Put ( storage . SYSCurrentHeader . Bytes ( ) , hashAndIndexToBytes ( h . Hash ( ) , h . Index ) )
2018-02-06 06:43:32 +00:00
2018-02-04 19:54:51 +00:00
return nil
}
2019-09-26 15:14:00 +00:00
// TODO: storeBlock needs some more love, its implemented as in the original
2018-03-21 16:11:04 +00:00
// project. This for the sake of development speed and understanding of what
// is happening here, quite allot as you can see :). If things are wired together
// and all tests are in place, we can make a more optimized and cleaner implementation.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) storeBlock ( block * block . Block ) error {
2019-12-13 15:43:46 +00:00
cache := newCachedDao ( bc . dao . store )
2019-11-25 17:39:11 +00:00
if err := cache . StoreAsBlock ( block , 0 ) ; err != nil {
2019-01-25 11:20:35 +00:00
return err
}
2019-11-25 17:39:11 +00:00
if err := cache . StoreAsCurrentBlock ( block ) ; err != nil {
2019-10-16 14:29:21 +00:00
return err
}
2018-03-14 09:36:59 +00:00
2018-03-21 16:11:04 +00:00
for _ , tx := range block . Transactions {
2019-11-25 17:39:11 +00:00
if err := cache . StoreAsTransaction ( tx , block . Index ) ; err != nil {
2019-01-25 11:20:35 +00:00
return err
}
2019-11-25 17:39:11 +00:00
if err := cache . PutUnspentCoinState ( tx . Hash ( ) , NewUnspentCoinState ( len ( tx . Outputs ) ) ) ; err != nil {
return err
}
2018-03-21 16:11:04 +00:00
// Process TX outputs.
2019-11-25 17:39:11 +00:00
if err := processOutputs ( tx , cache ) ; err != nil {
2019-11-18 12:24:48 +00:00
return err
2018-03-21 16:11:04 +00:00
}
// Process TX inputs that are grouped by previous hash.
for prevHash , inputs := range tx . GroupInputsByPrevHash ( ) {
2018-04-16 20:15:30 +00:00
prevTX , prevTXHeight , err := bc . GetTransaction ( prevHash )
2018-03-21 16:11:04 +00:00
if err != nil {
2018-03-25 10:45:54 +00:00
return fmt . Errorf ( "could not find previous TX: %s" , prevHash )
2018-03-21 16:11:04 +00:00
}
for _ , input := range inputs {
2019-11-25 17:39:11 +00:00
unspent , err := cache . GetUnspentCoinStateOrNew ( input . PrevHash )
2018-03-21 16:11:04 +00:00
if err != nil {
return err
}
2019-11-28 16:06:09 +00:00
unspent . states [ input . PrevIndex ] = state . CoinSpent
2019-11-25 17:39:11 +00:00
if err = cache . PutUnspentCoinState ( input . PrevHash , unspent ) ; err != nil {
return err
}
2018-03-21 16:11:04 +00:00
prevTXOutput := prevTX . Outputs [ input . PrevIndex ]
2019-11-25 17:39:11 +00:00
account , err := cache . GetAccountStateOrNew ( prevTXOutput . ScriptHash )
2018-03-21 16:11:04 +00:00
if err != nil {
return err
}
2018-04-16 20:15:30 +00:00
if prevTXOutput . AssetID . Equals ( governingTokenTX ( ) . Hash ( ) ) {
spentCoin := NewSpentCoinState ( input . PrevHash , prevTXHeight )
spentCoin . items [ input . PrevIndex ] = block . Index
2019-11-25 17:39:11 +00:00
if err = cache . PutSpentCoinState ( input . PrevHash , spentCoin ) ; err != nil {
return err
}
2019-12-11 10:10:51 +00:00
if err = processTXWithValidatorsSubtract ( account , cache , prevTXOutput . Amount ) ; err != nil {
return err
2019-11-11 15:25:28 +00:00
}
2018-04-16 20:15:30 +00:00
}
2019-11-15 17:35:09 +00:00
balancesLen := len ( account . Balances [ prevTXOutput . AssetID ] )
if balancesLen <= 1 {
delete ( account . Balances , prevTXOutput . AssetID )
} else {
2019-12-06 15:44:28 +00:00
var index = - 1
for i , balance := range account . Balances [ prevTXOutput . AssetID ] {
if balance . Tx . Equals ( input . PrevHash ) && balance . Index == input . PrevIndex {
index = i
break
2019-11-15 17:35:09 +00:00
}
}
2019-12-06 15:44:28 +00:00
if index >= 0 {
copy ( account . Balances [ prevTXOutput . AssetID ] [ index : ] , account . Balances [ prevTXOutput . AssetID ] [ index + 1 : ] )
account . Balances [ prevTXOutput . AssetID ] = account . Balances [ prevTXOutput . AssetID ] [ : balancesLen - 1 ]
}
2019-11-15 17:35:09 +00:00
}
2019-11-25 17:39:11 +00:00
if err = cache . PutAccountState ( account ) ; err != nil {
return err
}
2018-03-21 16:11:04 +00:00
}
}
// Process the underlying type of the TX.
2018-04-16 20:15:30 +00:00
switch t := tx . Data . ( type ) {
2018-03-21 16:11:04 +00:00
case * transaction . RegisterTX :
2019-11-28 16:06:09 +00:00
err := cache . PutAssetState ( & state . Asset {
2019-09-30 14:27:41 +00:00
ID : tx . Hash ( ) ,
AssetType : t . AssetType ,
Name : t . Name ,
Amount : t . Amount ,
Precision : t . Precision ,
Owner : t . Owner ,
Admin : t . Admin ,
Expiration : bc . BlockHeight ( ) + registeredAssetLifetime ,
2019-11-25 17:39:11 +00:00
} )
if err != nil {
return err
2018-04-16 20:15:30 +00:00
}
2018-03-21 16:11:04 +00:00
case * transaction . IssueTX :
2019-10-25 14:20:12 +00:00
for _ , res := range bc . GetTransactionResults ( tx ) {
if res . Amount < 0 {
2019-11-25 17:39:11 +00:00
asset , err := cache . GetAssetState ( res . AssetID )
if asset == nil || err != nil {
return fmt . Errorf ( "issue failed: no asset %s or error %s" , res . AssetID , err )
2019-10-25 14:20:12 +00:00
}
asset . Available -= res . Amount
2019-11-25 17:39:11 +00:00
if err := cache . PutAssetState ( asset ) ; err != nil {
return err
}
2019-10-25 14:20:12 +00:00
}
}
2018-03-21 16:11:04 +00:00
case * transaction . ClaimTX :
2019-11-11 12:35:57 +00:00
// Remove claimed NEO from spent coins making it unavalaible for
// additional claims.
for _ , input := range t . Claims {
2019-11-25 17:39:11 +00:00
scs , err := cache . GetSpentCoinsOrNew ( input . PrevHash )
2019-11-11 12:35:57 +00:00
if err != nil {
return err
}
if scs . txHash == input . PrevHash {
// Existing scs.
delete ( scs . items , input . PrevIndex )
2019-11-25 17:39:11 +00:00
if err = cache . PutSpentCoinState ( input . PrevHash , scs ) ; err != nil {
return err
}
2019-11-11 12:35:57 +00:00
} else {
// Uninitialized, new, forget about it.
2019-11-25 17:39:11 +00:00
if err = cache . DeleteSpentCoinState ( input . PrevHash ) ; err != nil {
return err
}
2019-11-11 12:35:57 +00:00
}
}
2018-03-21 16:11:04 +00:00
case * transaction . EnrollmentTX :
2019-11-25 17:39:11 +00:00
if err := processEnrollmentTX ( cache , t ) ; err != nil {
2019-11-11 15:25:28 +00:00
return err
}
2018-03-21 16:11:04 +00:00
case * transaction . StateTX :
2019-11-25 17:39:11 +00:00
if err := processStateTX ( cache , t ) ; err != nil {
2019-11-18 12:24:48 +00:00
return err
2019-11-11 15:25:28 +00:00
}
2018-03-21 16:11:04 +00:00
case * transaction . PublishTX :
2019-10-10 14:56:58 +00:00
var properties smartcontract . PropertyState
if t . NeedStorage {
properties |= smartcontract . HasStorage
}
2019-11-28 16:06:09 +00:00
contract := & state . Contract {
2018-04-16 20:15:30 +00:00
Script : t . Script ,
ParamList : t . ParamList ,
ReturnType : t . ReturnType ,
2019-10-10 14:56:58 +00:00
Properties : properties ,
2018-04-16 20:15:30 +00:00
Name : t . Name ,
CodeVersion : t . CodeVersion ,
Author : t . Author ,
Email : t . Email ,
Description : t . Description ,
}
2019-11-25 17:39:11 +00:00
if err := cache . PutContractState ( contract ) ; err != nil {
return err
}
2018-03-21 16:11:04 +00:00
case * transaction . InvocationTX :
2019-12-30 11:01:49 +00:00
systemInterop := bc . newInteropContext ( trigger . Application , cache . store , block , tx )
2019-11-15 14:52:47 +00:00
v := bc . spawnVMWithInterops ( systemInterop )
2019-11-27 09:23:18 +00:00
v . SetCheckedHash ( tx . VerificationHash ( ) . BytesBE ( ) )
2019-11-15 14:52:47 +00:00
v . LoadScript ( t . Script )
2020-01-20 12:31:12 +00:00
v . SetPriceGetter ( getPrice )
2020-01-21 13:39:48 +00:00
if bc . config . FreeGasLimit >= 0 {
v . SetGasLimit ( bc . config . FreeGasLimit + t . Gas )
}
2020-01-20 12:31:12 +00:00
2019-11-15 14:52:47 +00:00
err := v . Run ( )
if ! v . HasFailed ( ) {
2019-12-12 18:17:13 +00:00
_ , err := systemInterop . dao . Persist ( )
2019-10-11 14:02:59 +00:00
if err != nil {
return errors . Wrap ( err , "failed to persist invocation results" )
}
2019-11-15 14:52:47 +00:00
for _ , note := range systemInterop . notifications {
arr , ok := note . Item . Value ( ) . ( [ ] vm . StackItem )
if ! ok || len ( arr ) != 4 {
continue
}
op , ok := arr [ 0 ] . Value ( ) . ( [ ] byte )
if ! ok || string ( op ) != "transfer" {
continue
}
from , ok := arr [ 1 ] . Value ( ) . ( [ ] byte )
if ! ok {
continue
}
to , ok := arr [ 2 ] . Value ( ) . ( [ ] byte )
if ! ok {
continue
}
amount , ok := arr [ 3 ] . Value ( ) . ( * big . Int )
if ! ok {
continue
}
// TODO: #498
_ , _ , _ , _ = op , from , to , amount
}
2019-10-11 14:02:59 +00:00
} else {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "contract invocation failed" ,
zap . String ( "tx" , tx . Hash ( ) . StringLE ( ) ) ,
zap . Uint32 ( "block" , block . Index ) ,
zap . Error ( err ) )
2019-10-11 14:02:59 +00:00
}
2019-11-28 16:06:09 +00:00
aer := & state . AppExecResult {
2019-11-13 13:55:20 +00:00
TxHash : tx . Hash ( ) ,
2019-12-04 09:27:04 +00:00
Trigger : trigger . Application ,
2019-11-15 14:52:47 +00:00
VMState : v . State ( ) ,
2020-01-20 12:31:12 +00:00
GasConsumed : v . GasConsumed ( ) ,
2019-11-15 14:52:47 +00:00
Stack : v . Stack ( "estack" ) ,
2019-11-13 13:55:20 +00:00
Events : systemInterop . notifications ,
}
2019-11-25 17:39:11 +00:00
err = cache . PutAppExecResult ( aer )
2019-11-13 13:55:20 +00:00
if err != nil {
return errors . Wrap ( err , "failed to store notifications" )
}
2018-03-21 16:11:04 +00:00
}
}
2020-02-04 15:43:21 +00:00
bc . lock . Lock ( )
defer bc . lock . Unlock ( )
2019-12-12 18:17:13 +00:00
_ , err := cache . Persist ( )
2019-12-11 10:10:51 +00:00
if err != nil {
2018-03-21 16:11:04 +00:00
return err
}
2019-12-23 16:18:12 +00:00
bc . topBlock . Store ( block )
2019-09-26 15:14:00 +00:00
atomic . StoreUint32 ( & bc . blockHeight , block . Index )
2019-10-29 17:51:17 +00:00
updateBlockHeightMetric ( block . Index )
2019-10-24 09:29:55 +00:00
for _ , tx := range block . Transactions {
bc . memPool . Remove ( tx . Hash ( ) )
2018-03-21 16:11:04 +00:00
}
2018-03-09 15:55:25 +00:00
return nil
}
2019-11-18 12:24:48 +00:00
// processOutputs processes transaction outputs.
2019-12-13 15:43:46 +00:00
func processOutputs ( tx * transaction . Transaction , dao * cachedDao ) error {
2019-11-18 12:24:48 +00:00
for index , output := range tx . Outputs {
2019-11-25 17:39:11 +00:00
account , err := dao . GetAccountStateOrNew ( output . ScriptHash )
2019-11-18 12:24:48 +00:00
if err != nil {
return err
}
2019-11-28 16:06:09 +00:00
account . Balances [ output . AssetID ] = append ( account . Balances [ output . AssetID ] , state . UnspentBalance {
2019-11-18 12:24:48 +00:00
Tx : tx . Hash ( ) ,
Index : uint16 ( index ) ,
Value : output . Amount ,
} )
2019-11-25 17:39:11 +00:00
if err = dao . PutAccountState ( account ) ; err != nil {
return err
}
2019-12-11 10:10:51 +00:00
if err = processTXWithValidatorsAdd ( & output , account , dao ) ; err != nil {
return err
}
}
return nil
}
2019-12-13 15:43:46 +00:00
func processTXWithValidatorsAdd ( output * transaction . Output , account * state . Account , dao * cachedDao ) error {
2019-12-11 10:10:51 +00:00
if output . AssetID . Equals ( governingTokenTX ( ) . Hash ( ) ) && len ( account . Votes ) > 0 {
for _ , vote := range account . Votes {
validatorState , err := dao . GetValidatorStateOrNew ( vote )
if err != nil {
return err
}
validatorState . Votes += output . Amount
if err = dao . PutValidatorState ( validatorState ) ; err != nil {
return err
}
}
}
return nil
}
2019-12-13 15:43:46 +00:00
func processTXWithValidatorsSubtract ( account * state . Account , dao * cachedDao , toSubtract util . Fixed8 ) error {
2019-12-11 10:10:51 +00:00
for _ , vote := range account . Votes {
validator , err := dao . GetValidatorStateOrNew ( vote )
if err != nil {
return err
}
validator . Votes -= toSubtract
if ! validator . RegisteredAndHasVotes ( ) {
if err := dao . DeleteValidatorState ( validator ) ; err != nil {
return err
}
} else {
if err := dao . PutValidatorState ( validator ) ; err != nil {
return err
2019-11-18 12:24:48 +00:00
}
}
}
return nil
}
2019-12-13 15:43:46 +00:00
func processValidatorStateDescriptor ( descriptor * transaction . StateDescriptor , dao * cachedDao ) error {
2019-11-11 15:25:28 +00:00
publicKey := & keys . PublicKey { }
err := publicKey . DecodeBytes ( descriptor . Key )
if err != nil {
2018-04-16 20:15:30 +00:00
return err
}
2019-11-25 17:39:11 +00:00
validatorState , err := dao . GetValidatorStateOrNew ( publicKey )
2019-11-11 15:25:28 +00:00
if err != nil {
2018-04-16 20:15:30 +00:00
return err
}
2019-11-11 15:25:28 +00:00
if descriptor . Field == "Registered" {
isRegistered , err := strconv . ParseBool ( string ( descriptor . Value ) )
if err != nil {
return err
}
validatorState . Registered = isRegistered
2019-11-25 17:39:11 +00:00
return dao . PutValidatorState ( validatorState )
2019-11-11 15:25:28 +00:00
}
return nil
}
2019-12-13 15:43:46 +00:00
func processAccountStateDescriptor ( descriptor * transaction . StateDescriptor , dao * cachedDao ) error {
2019-11-27 09:20:31 +00:00
hash , err := util . Uint160DecodeBytesBE ( descriptor . Key )
2019-11-11 15:25:28 +00:00
if err != nil {
2019-09-30 16:52:16 +00:00
return err
}
2019-11-25 17:39:11 +00:00
account , err := dao . GetAccountStateOrNew ( hash )
2019-11-11 15:25:28 +00:00
if err != nil {
2018-03-14 09:36:59 +00:00
return err
}
2018-03-21 16:11:04 +00:00
2019-11-11 15:25:28 +00:00
if descriptor . Field == "Votes" {
balance := account . GetBalanceValues ( ) [ governingTokenTX ( ) . Hash ( ) ]
2019-12-11 10:10:51 +00:00
if err = processTXWithValidatorsSubtract ( account , dao , balance ) ; err != nil {
return err
2019-11-11 15:25:28 +00:00
}
votes := keys . PublicKeys { }
err := votes . DecodeBytes ( descriptor . Value )
if err != nil {
return err
}
if votes . Len ( ) != len ( account . Votes ) {
account . Votes = votes
for _ , vote := range votes {
2019-11-25 17:39:11 +00:00
validator , err := dao . GetValidatorStateOrNew ( vote )
2019-11-11 15:25:28 +00:00
if err != nil {
return err
}
2019-11-25 17:39:11 +00:00
if err := dao . PutValidatorState ( validator ) ; err != nil {
return err
}
2019-11-11 15:25:28 +00:00
}
}
2019-10-24 09:29:55 +00:00
}
2018-03-09 15:55:25 +00:00
return nil
}
2019-09-26 15:14:00 +00:00
// persist flushes current in-memory store contents to the persistent storage.
2019-10-21 07:04:58 +00:00
func ( bc * Blockchain ) persist ( ) error {
2018-03-09 15:55:25 +00:00
var (
2018-03-14 09:36:59 +00:00
start = time . Now ( )
2019-10-17 09:27:15 +00:00
persisted int
2019-09-26 15:14:00 +00:00
err error
2018-03-09 15:55:25 +00:00
)
2019-12-12 18:17:13 +00:00
persisted , err = bc . dao . Persist ( )
2019-09-26 15:14:00 +00:00
if err != nil {
return err
2018-02-04 19:54:51 +00:00
}
2018-03-14 09:36:59 +00:00
if persisted > 0 {
2019-11-25 17:39:11 +00:00
bHeight , err := bc . dao . GetCurrentBlockHeight ( )
2019-11-06 13:10:37 +00:00
if err != nil {
return err
}
oldHeight := atomic . SwapUint32 ( & bc . persistedHeight , bHeight )
diff := bHeight - oldHeight
2019-11-25 17:39:11 +00:00
storedHeaderHeight , _ , err := bc . dao . GetCurrentHeaderHeight ( )
2019-11-06 13:10:37 +00:00
if err != nil {
return err
}
2019-12-30 07:43:05 +00:00
bc . log . Info ( "blockchain persist completed" ,
zap . Uint32 ( "persistedBlocks" , diff ) ,
zap . Int ( "persistedKeys" , persisted ) ,
zap . Uint32 ( "headerHeight" , storedHeaderHeight ) ,
zap . Uint32 ( "blockHeight" , bHeight ) ,
zap . Duration ( "took" , time . Since ( start ) ) )
2019-10-29 17:51:17 +00:00
// update monitoring metrics.
updatePersistedHeightMetric ( bHeight )
2018-03-14 09:36:59 +00:00
}
2019-09-26 15:14:00 +00:00
return nil
2018-03-14 09:36:59 +00:00
}
func ( bc * Blockchain ) headerListLen ( ) ( n int ) {
bc . headersOp <- func ( headerList * HeaderHashList ) {
n = headerList . Len ( )
}
<- bc . headersOpDone
2018-03-09 15:55:25 +00:00
return
}
2018-02-04 19:54:51 +00:00
2018-03-21 16:11:04 +00:00
// GetTransaction returns a TX and its height by the given hash.
func ( bc * Blockchain ) GetTransaction ( hash util . Uint256 ) ( * transaction . Transaction , uint32 , error ) {
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
if tx , ok := bc . memPool . TryGetValue ( hash ) ; ok {
return tx , 0 , nil // the height is not actually defined for memPool transaction. Not sure if zero is a good number in this case.
}
2019-11-25 17:39:11 +00:00
return bc . dao . GetTransaction ( hash )
2018-03-21 16:11:04 +00:00
}
2019-10-11 11:08:21 +00:00
// GetStorageItem returns an item from storage.
2019-11-28 16:06:09 +00:00
func ( bc * Blockchain ) GetStorageItem ( scripthash util . Uint160 , key [ ] byte ) * state . StorageItem {
2019-11-25 17:39:11 +00:00
return bc . dao . GetStorageItem ( scripthash , key )
2019-10-11 11:08:21 +00:00
}
// GetStorageItems returns all storage items for a given scripthash.
2019-11-28 16:06:09 +00:00
func ( bc * Blockchain ) GetStorageItems ( hash util . Uint160 ) ( map [ string ] * state . StorageItem , error ) {
2019-11-25 17:39:11 +00:00
return bc . dao . GetStorageItems ( hash )
2019-10-11 11:08:21 +00:00
}
2018-03-14 09:36:59 +00:00
// GetBlock returns a Block by the given hash.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) GetBlock ( hash util . Uint256 ) ( * block . Block , error ) {
2019-12-23 16:18:12 +00:00
topBlock := bc . topBlock . Load ( )
if topBlock != nil {
2020-01-14 12:32:07 +00:00
if tb , ok := topBlock . ( * block . Block ) ; ok && tb . Hash ( ) . Equals ( hash ) {
2019-12-23 16:18:12 +00:00
return tb , nil
}
}
2019-11-25 17:39:11 +00:00
block , err := bc . dao . GetBlock ( hash )
2019-09-26 15:14:00 +00:00
if err != nil {
2019-10-16 13:41:50 +00:00
return nil , err
2018-03-17 11:53:21 +00:00
}
2019-09-24 15:51:20 +00:00
if len ( block . Transactions ) == 0 {
return nil , fmt . Errorf ( "only header is available" )
2018-03-17 11:53:21 +00:00
}
2019-10-10 17:02:09 +00:00
for _ , tx := range block . Transactions {
stx , _ , err := bc . GetTransaction ( tx . Hash ( ) )
if err != nil {
return nil , err
}
* tx = * stx
}
2018-03-17 11:53:21 +00:00
return block , nil
}
2019-09-03 14:51:37 +00:00
// GetHeader returns data block header identified with the given hash value.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) GetHeader ( hash util . Uint256 ) ( * block . Header , error ) {
2019-12-23 16:18:12 +00:00
topBlock := bc . topBlock . Load ( )
if topBlock != nil {
2020-01-14 12:32:07 +00:00
if tb , ok := topBlock . ( * block . Block ) ; ok && tb . Hash ( ) . Equals ( hash ) {
2019-12-23 16:18:12 +00:00
return tb . Header ( ) , nil
}
}
2019-11-25 17:39:11 +00:00
block , err := bc . dao . GetBlock ( hash )
2019-09-26 15:14:00 +00:00
if err != nil {
return nil , err
}
2018-03-17 11:53:21 +00:00
return block . Header ( ) , nil
2018-03-14 09:36:59 +00:00
}
2019-10-22 14:56:03 +00:00
// HasTransaction returns true if the blockchain contains he given
2018-03-14 09:36:59 +00:00
// transaction hash.
func ( bc * Blockchain ) HasTransaction ( hash util . Uint256 ) bool {
2019-11-25 17:39:11 +00:00
return bc . memPool . ContainsKey ( hash ) || bc . dao . HasTransaction ( hash )
2018-03-14 09:36:59 +00:00
}
2019-10-22 14:56:03 +00:00
// HasBlock returns true if the blockchain contains the given
2018-03-14 09:36:59 +00:00
// block hash.
func ( bc * Blockchain ) HasBlock ( hash util . Uint256 ) bool {
2019-02-20 17:39:32 +00:00
if header , err := bc . GetHeader ( hash ) ; err == nil {
2018-03-17 11:53:21 +00:00
return header . Index <= bc . BlockHeight ( )
}
2018-03-14 09:36:59 +00:00
return false
}
2019-02-09 15:53:58 +00:00
// CurrentBlockHash returns the highest processed block hash.
2018-03-09 15:55:25 +00:00
func ( bc * Blockchain ) CurrentBlockHash ( ) ( hash util . Uint256 ) {
bc . headersOp <- func ( headerList * HeaderHashList ) {
hash = headerList . Get ( int ( bc . BlockHeight ( ) ) )
}
<- bc . headersOpDone
return
2018-02-01 20:28:45 +00:00
}
2018-02-06 06:43:32 +00:00
2018-02-07 14:16:50 +00:00
// CurrentHeaderHash returns the hash of the latest known header.
func ( bc * Blockchain ) CurrentHeaderHash ( ) ( hash util . Uint256 ) {
2018-03-09 15:55:25 +00:00
bc . headersOp <- func ( headerList * HeaderHashList ) {
hash = headerList . Last ( )
}
<- bc . headersOpDone
return
2018-02-07 14:16:50 +00:00
}
2019-10-22 14:56:03 +00:00
// GetHeaderHash returns the hash from the headerList by its
2018-03-14 09:36:59 +00:00
// height/index.
func ( bc * Blockchain ) GetHeaderHash ( i int ) ( hash util . Uint256 ) {
bc . headersOp <- func ( headerList * HeaderHashList ) {
hash = headerList . Get ( i )
}
<- bc . headersOpDone
return
}
2018-03-09 15:55:25 +00:00
// BlockHeight returns the height/index of the highest block.
2018-02-06 06:43:32 +00:00
func ( bc * Blockchain ) BlockHeight ( ) uint32 {
2018-03-09 15:55:25 +00:00
return atomic . LoadUint32 ( & bc . blockHeight )
2018-02-06 06:43:32 +00:00
}
2018-03-09 15:55:25 +00:00
// HeaderHeight returns the index/height of the highest header.
2018-03-14 09:36:59 +00:00
func ( bc * Blockchain ) HeaderHeight ( ) uint32 {
return uint32 ( bc . headerListLen ( ) - 1 )
2018-02-06 06:43:32 +00:00
}
2019-10-22 14:56:03 +00:00
// GetAssetState returns asset state from its assetID.
2019-11-28 16:06:09 +00:00
func ( bc * Blockchain ) GetAssetState ( assetID util . Uint256 ) * state . Asset {
2019-11-25 17:39:11 +00:00
asset , err := bc . dao . GetAssetState ( assetID )
if asset == nil && err != storage . ErrKeyNotFound {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "failed to get asset state" ,
zap . Stringer ( "asset" , assetID ) ,
zap . Error ( err ) )
2019-09-26 15:14:00 +00:00
}
2019-11-25 17:39:11 +00:00
return asset
2019-09-26 15:14:00 +00:00
}
2019-09-30 16:52:16 +00:00
// GetContractState returns contract by its script hash.
2019-11-28 16:06:09 +00:00
func ( bc * Blockchain ) GetContractState ( hash util . Uint160 ) * state . Contract {
2019-12-11 10:10:51 +00:00
contract , err := bc . dao . GetContractState ( hash )
2019-11-25 17:39:11 +00:00
if contract == nil && err != storage . ErrKeyNotFound {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "failed to get contract state" , zap . Error ( err ) )
2019-09-30 16:52:16 +00:00
}
2019-11-25 17:39:11 +00:00
return contract
2019-09-30 16:52:16 +00:00
}
2019-10-22 14:56:03 +00:00
// GetAccountState returns the account state from its script hash.
2019-11-28 16:06:09 +00:00
func ( bc * Blockchain ) GetAccountState ( scriptHash util . Uint160 ) * state . Account {
2019-11-25 17:39:11 +00:00
as , err := bc . dao . GetAccountState ( scriptHash )
2019-10-16 13:41:50 +00:00
if as == nil && err != storage . ErrKeyNotFound {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "failed to get account state" , zap . Error ( err ) )
2019-09-26 15:14:00 +00:00
}
2019-02-08 08:04:38 +00:00
return as
}
2019-10-11 11:16:53 +00:00
// GetUnspentCoinState returns unspent coin state for given tx hash.
func ( bc * Blockchain ) GetUnspentCoinState ( hash util . Uint256 ) * UnspentCoinState {
2019-11-25 17:39:11 +00:00
ucs , err := bc . dao . GetUnspentCoinState ( hash )
2019-10-16 13:41:50 +00:00
if ucs == nil && err != storage . ErrKeyNotFound {
2019-12-30 07:43:05 +00:00
bc . log . Warn ( "failed to get unspent coin state" , zap . Error ( err ) )
2019-10-11 11:16:53 +00:00
}
return ucs
}
2019-10-22 14:56:03 +00:00
// GetConfig returns the config stored in the blockchain.
2019-02-20 17:39:32 +00:00
func ( bc * Blockchain ) GetConfig ( ) config . ProtocolConfiguration {
return bc . config
}
2019-09-30 14:42:37 +00:00
// References returns a map with input coin reference (prevhash and index) as key
2019-02-20 17:39:32 +00:00
// and transaction output as value from a transaction t.
// @TODO: unfortunately we couldn't attach this method to the Transaction struct in the
// transaction package because of a import cycle problem. Perhaps we should think to re-design
// the code base to avoid this situation.
2019-09-30 14:42:37 +00:00
func ( bc * Blockchain ) References ( t * transaction . Transaction ) map [ transaction . Input ] * transaction . Output {
references := make ( map [ transaction . Input ] * transaction . Output )
2019-02-20 17:39:32 +00:00
for prevHash , inputs := range t . GroupInputsByPrevHash ( ) {
if tx , _ , err := bc . GetTransaction ( prevHash ) ; err != nil {
tx = nil
} else if tx != nil {
for _ , in := range inputs {
2019-12-09 14:14:10 +00:00
references [ * in ] = & tx . Outputs [ in . PrevIndex ]
2019-02-20 17:39:32 +00:00
}
} else {
references = nil
}
}
return references
}
2019-10-22 14:56:03 +00:00
// FeePerByte returns network fee divided by the size of the transaction.
2019-02-20 17:39:32 +00:00
func ( bc * Blockchain ) FeePerByte ( t * transaction . Transaction ) util . Fixed8 {
2019-09-16 13:08:00 +00:00
return bc . NetworkFee ( t ) . Div ( int64 ( io . GetVarSize ( t ) ) )
2019-02-20 17:39:32 +00:00
}
2019-10-22 14:56:03 +00:00
// NetworkFee returns network fee.
2019-02-20 17:39:32 +00:00
func ( bc * Blockchain ) NetworkFee ( t * transaction . Transaction ) util . Fixed8 {
2019-08-23 12:41:22 +00:00
inputAmount := util . Fixed8FromInt64 ( 0 )
2019-02-20 17:39:32 +00:00
for _ , txOutput := range bc . References ( t ) {
if txOutput . AssetID == utilityTokenTX ( ) . Hash ( ) {
inputAmount . Add ( txOutput . Amount )
}
}
2019-08-23 12:41:22 +00:00
outputAmount := util . Fixed8FromInt64 ( 0 )
2019-02-20 17:39:32 +00:00
for _ , txOutput := range t . Outputs {
if txOutput . AssetID == utilityTokenTX ( ) . Hash ( ) {
outputAmount . Add ( txOutput . Amount )
}
}
return inputAmount . Sub ( outputAmount ) . Sub ( bc . SystemFee ( t ) )
}
2019-10-22 14:56:03 +00:00
// SystemFee returns system fee.
2019-02-20 17:39:32 +00:00
func ( bc * Blockchain ) SystemFee ( t * transaction . Transaction ) util . Fixed8 {
return bc . GetConfig ( ) . SystemFee . TryGetValue ( t . Type )
}
2019-10-22 14:56:03 +00:00
// IsLowPriority flags a transaction as low priority if the network fee is less than
// LowPriorityThreshold.
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
func ( bc * Blockchain ) IsLowPriority ( t * transaction . Transaction ) bool {
2019-08-23 12:41:22 +00:00
return bc . NetworkFee ( t ) < util . Fixed8FromFloat ( bc . GetConfig ( ) . LowPriorityThreshold )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
// GetMemPool returns the memory pool of the blockchain.
2020-02-04 14:36:11 +00:00
func ( bc * Blockchain ) GetMemPool ( ) * mempool . Pool {
return & bc . memPool
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-10-15 09:52:10 +00:00
// VerifyBlock verifies block against its current state.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) VerifyBlock ( block * block . Block ) error {
2019-10-15 09:52:10 +00:00
prevHeader , err := bc . GetHeader ( block . PrevHash )
if err != nil {
return errors . Wrap ( err , "unable to get previous header" )
}
if prevHeader . Index + 1 != block . Index {
return errors . New ( "previous header index doesn't match" )
}
if prevHeader . Timestamp >= block . Timestamp {
return errors . New ( "block is not newer than the previous one" )
}
return bc . verifyBlockWitnesses ( block , prevHeader )
}
2020-02-04 15:43:21 +00:00
// verifyTx verifies whether a transaction is bonafide or not.
func ( bc * Blockchain ) verifyTx ( t * transaction . Transaction , block * block . Block ) error {
2019-09-16 13:08:00 +00:00
if io . GetVarSize ( t ) > transaction . MaxTransactionSize {
return errors . Errorf ( "invalid transaction size = %d. It shoud be less then MaxTransactionSize = %d" , io . GetVarSize ( t ) , transaction . MaxTransactionSize )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
if ok := bc . verifyInputs ( t ) ; ! ok {
return errors . New ( "invalid transaction's inputs" )
}
2019-11-19 17:37:27 +00:00
if block == nil {
if ok := bc . memPool . Verify ( t ) ; ! ok {
return errors . New ( "invalid transaction due to conflicts with the memory pool" )
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-11-25 17:39:11 +00:00
if bc . dao . IsDoubleSpend ( t ) {
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
return errors . New ( "invalid transaction caused by double spending" )
}
2019-10-11 09:09:16 +00:00
if err := bc . verifyOutputs ( t ) ; err != nil {
return errors . Wrap ( err , "wrong outputs" )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-10-11 08:42:36 +00:00
if err := bc . verifyResults ( t ) ; err != nil {
return err
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
for _ , a := range t . Attributes {
if a . Usage == transaction . ECDH02 || a . Usage == transaction . ECDH03 {
return errors . Errorf ( "invalid attribute's usage = %s " , a . Usage )
}
}
2019-10-15 09:52:10 +00:00
return bc . verifyTxWitnesses ( t , block )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2020-02-04 15:43:21 +00:00
// VerifyTx verifies whether a transaction is bonafide or not. Block parameter
// is used for easy interop access and can be omitted for transactions that are
// not yet added into any block.
// Golang implementation of Verify method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L270).
func ( bc * Blockchain ) VerifyTx ( t * transaction . Transaction , block * block . Block ) error {
bc . lock . RLock ( )
defer bc . lock . RUnlock ( )
return bc . verifyTx ( t , block )
}
// PoolTx verifies and tries to add given transaction into the mempool.
func ( bc * Blockchain ) PoolTx ( t * transaction . Transaction ) error {
bc . lock . RLock ( )
defer bc . lock . RUnlock ( )
if bc . HasTransaction ( t . Hash ( ) ) {
return ErrAlreadyExists
}
if err := bc . verifyTx ( t , nil ) ; err != nil {
return err
}
2020-02-05 11:24:36 +00:00
if err := bc . memPool . Add ( t , bc ) ; err != nil {
2020-02-04 15:43:21 +00:00
switch err {
case mempool . ErrOOM :
return ErrOOM
case mempool . ErrConflict :
return ErrAlreadyExists
default :
return err
}
}
return nil
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
func ( bc * Blockchain ) verifyInputs ( t * transaction . Transaction ) bool {
for i := 1 ; i < len ( t . Inputs ) ; i ++ {
for j := 0 ; j < i ; j ++ {
if t . Inputs [ i ] . PrevHash == t . Inputs [ j ] . PrevHash && t . Inputs [ i ] . PrevIndex == t . Inputs [ j ] . PrevIndex {
return false
}
}
}
return true
}
2019-10-11 09:09:16 +00:00
func ( bc * Blockchain ) verifyOutputs ( t * transaction . Transaction ) error {
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
for assetID , outputs := range t . GroupOutputByAssetID ( ) {
assetState := bc . GetAssetState ( assetID )
if assetState == nil {
2019-11-27 09:23:18 +00:00
return fmt . Errorf ( "no asset state for %s" , assetID . StringLE ( ) )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
if assetState . Expiration < bc . blockHeight + 1 && assetState . AssetType != transaction . GoverningToken && assetState . AssetType != transaction . UtilityToken {
2019-11-27 09:23:18 +00:00
return fmt . Errorf ( "asset %s expired" , assetID . StringLE ( ) )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
for _ , out := range outputs {
if int64 ( out . Amount ) % int64 ( math . Pow10 ( 8 - int ( assetState . Precision ) ) ) != 0 {
2019-11-27 09:23:18 +00:00
return fmt . Errorf ( "output is not compliant with %s asset precision" , assetID . StringLE ( ) )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
}
}
2019-10-11 09:09:16 +00:00
return nil
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-10-11 08:42:36 +00:00
func ( bc * Blockchain ) verifyResults ( t * transaction . Transaction ) error {
2019-10-11 08:57:48 +00:00
results := bc . GetTransactionResults ( t )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
if results == nil {
2019-10-11 08:42:36 +00:00
return errors . New ( "tx has no results" )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
var resultsDestroy [ ] * transaction . Result
var resultsIssue [ ] * transaction . Result
for _ , re := range results {
if re . Amount . GreaterThan ( util . Fixed8 ( 0 ) ) {
resultsDestroy = append ( resultsDestroy , re )
}
if re . Amount . LessThan ( util . Fixed8 ( 0 ) ) {
resultsIssue = append ( resultsIssue , re )
}
}
if len ( resultsDestroy ) > 1 {
2019-10-11 08:42:36 +00:00
return errors . New ( "tx has more than 1 destroy output" )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
if len ( resultsDestroy ) == 1 && resultsDestroy [ 0 ] . AssetID != utilityTokenTX ( ) . Hash ( ) {
2019-10-11 08:42:36 +00:00
return errors . New ( "tx destroys non-utility token" )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-10-11 08:42:36 +00:00
sysfee := bc . SystemFee ( t )
if sysfee . GreaterThan ( util . Fixed8 ( 0 ) ) {
if len ( resultsDestroy ) == 0 {
return fmt . Errorf ( "system requires to pay %s fee, but tx pays nothing" , sysfee . String ( ) )
}
if resultsDestroy [ 0 ] . Amount . LessThan ( sysfee ) {
return fmt . Errorf ( "system requires to pay %s fee, but tx pays %s only" , sysfee . String ( ) , resultsDestroy [ 0 ] . Amount . String ( ) )
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
switch t . Type {
case transaction . MinerType , transaction . ClaimType :
for _ , r := range resultsIssue {
if r . AssetID != utilityTokenTX ( ) . Hash ( ) {
2019-10-11 08:42:36 +00:00
return errors . New ( "miner or claim tx issues non-utility tokens" )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
}
break
case transaction . IssueType :
for _ , r := range resultsIssue {
if r . AssetID == utilityTokenTX ( ) . Hash ( ) {
2019-10-11 08:42:36 +00:00
return errors . New ( "issue tx issues utility tokens" )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
}
break
default :
if len ( resultsIssue ) > 0 {
2019-10-11 08:42:36 +00:00
return errors . New ( "non issue/miner/claim tx issues tokens" )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
break
}
2019-10-11 08:42:36 +00:00
return nil
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-10-11 08:57:48 +00:00
// GetTransactionResults returns the transaction results aggregate by assetID.
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
// Golang of GetTransationResults method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L207)
2019-10-11 08:57:48 +00:00
func ( bc * Blockchain ) GetTransactionResults ( t * transaction . Transaction ) [ ] * transaction . Result {
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
var tempResults [ ] * transaction . Result
var results [ ] * transaction . Result
tempGroupResult := make ( map [ util . Uint256 ] util . Fixed8 )
2019-09-03 15:03:13 +00:00
references := bc . References ( t )
if references == nil {
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
return nil
2019-09-03 15:03:13 +00:00
}
for _ , output := range references {
tempResults = append ( tempResults , & transaction . Result {
AssetID : output . AssetID ,
Amount : output . Amount ,
} )
}
for _ , output := range t . Outputs {
tempResults = append ( tempResults , & transaction . Result {
AssetID : output . AssetID ,
Amount : - output . Amount ,
} )
}
for _ , r := range tempResults {
if amount , ok := tempGroupResult [ r . AssetID ] ; ok {
tempGroupResult [ r . AssetID ] = amount . Add ( r . Amount )
} else {
tempGroupResult [ r . AssetID ] = r . Amount
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-09-03 15:03:13 +00:00
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
2019-09-03 15:03:13 +00:00
results = [ ] * transaction . Result { } // this assignment is necessary. (Most of the time amount == 0 and results is the empty slice.)
for assetID , amount := range tempGroupResult {
if amount != util . Fixed8 ( 0 ) {
results = append ( results , & transaction . Result {
AssetID : assetID ,
Amount : amount ,
} )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
}
2019-09-03 15:03:13 +00:00
return results
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
2019-09-30 14:37:04 +00:00
// GetScriptHashesForVerifyingClaim returns all ScriptHashes of Claim transaction
// which has a different implementation from generic GetScriptHashesForVerifying.
func ( bc * Blockchain ) GetScriptHashesForVerifyingClaim ( t * transaction . Transaction ) ( [ ] util . Uint160 , error ) {
2019-10-11 09:21:09 +00:00
// Avoiding duplicates.
hashmap := make ( map [ util . Uint160 ] bool )
2019-09-30 14:37:04 +00:00
claim := t . Data . ( * transaction . ClaimTX )
clGroups := make ( map [ util . Uint256 ] [ ] * transaction . Input )
for _ , in := range claim . Claims {
clGroups [ in . PrevHash ] = append ( clGroups [ in . PrevHash ] , in )
}
for group , inputs := range clGroups {
refTx , _ , err := bc . GetTransaction ( group )
if err != nil {
return nil , err
}
for _ , input := range inputs {
if len ( refTx . Outputs ) <= int ( input . PrevIndex ) {
return nil , fmt . Errorf ( "wrong PrevIndex reference" )
}
2019-10-11 09:21:09 +00:00
hashmap [ refTx . Outputs [ input . PrevIndex ] . ScriptHash ] = true
2019-09-30 14:37:04 +00:00
}
}
2019-10-11 09:21:09 +00:00
if len ( hashmap ) > 0 {
hashes := make ( [ ] util . Uint160 , 0 , len ( hashmap ) )
for k := range hashmap {
hashes = append ( hashes , k )
}
2019-09-30 14:37:04 +00:00
return hashes , nil
}
return nil , fmt . Errorf ( "no hashes found" )
}
2019-11-11 15:25:28 +00:00
//GetStandByValidators returns validators from the configuration.
func ( bc * Blockchain ) GetStandByValidators ( ) ( keys . PublicKeys , error ) {
return getValidators ( bc . config )
}
// GetValidators returns validators.
// Golang implementation of GetValidators method in C# (https://github.com/neo-project/neo/blob/c64748ecbac3baeb8045b16af0d518398a6ced24/neo/Persistence/Snapshot.cs#L182)
2019-11-27 10:27:47 +00:00
func ( bc * Blockchain ) GetValidators ( txes ... * transaction . Transaction ) ( [ ] * keys . PublicKey , error ) {
2019-12-13 15:43:46 +00:00
cache := newCachedDao ( bc . dao . store )
2019-11-11 15:25:28 +00:00
if len ( txes ) > 0 {
for _ , tx := range txes {
// iterate through outputs
for index , output := range tx . Outputs {
2019-11-25 17:39:11 +00:00
accountState , err := cache . GetAccountState ( output . ScriptHash )
if err != nil {
return nil , err
}
2019-11-28 16:06:09 +00:00
accountState . Balances [ output . AssetID ] = append ( accountState . Balances [ output . AssetID ] , state . UnspentBalance {
2019-11-11 15:25:28 +00:00
Tx : tx . Hash ( ) ,
Index : uint16 ( index ) ,
Value : output . Amount ,
} )
2019-11-25 17:39:11 +00:00
if err := cache . PutAccountState ( accountState ) ; err != nil {
return nil , err
}
2019-12-11 10:10:51 +00:00
if err = processTXWithValidatorsAdd ( & output , accountState , cache ) ; err != nil {
return nil , err
2019-11-11 15:25:28 +00:00
}
}
// group inputs by the same previous hash and iterate through inputs
group := make ( map [ util . Uint256 ] [ ] * transaction . Input )
2019-12-09 14:14:10 +00:00
for i := range tx . Inputs {
hash := tx . Inputs [ i ] . PrevHash
group [ hash ] = append ( group [ hash ] , & tx . Inputs [ i ] )
2019-11-11 15:25:28 +00:00
}
for hash , inputs := range group {
2019-11-25 17:39:11 +00:00
prevTx , _ , err := cache . GetTransaction ( hash )
2019-11-11 15:25:28 +00:00
if err != nil {
return nil , err
}
2019-11-18 12:24:48 +00:00
// process inputs
2019-11-11 15:25:28 +00:00
for _ , input := range inputs {
prevOutput := prevTx . Outputs [ input . PrevIndex ]
2019-11-25 17:39:11 +00:00
accountState , err := cache . GetAccountStateOrNew ( prevOutput . ScriptHash )
2019-11-11 15:25:28 +00:00
if err != nil {
return nil , err
}
2019-11-18 12:24:48 +00:00
// process account state votes: if there are any -> validators will be updated.
2019-12-11 10:10:51 +00:00
if err = processTXWithValidatorsSubtract ( accountState , cache , prevOutput . Amount ) ; err != nil {
return nil , err
2019-11-11 15:25:28 +00:00
}
delete ( accountState . Balances , prevOutput . AssetID )
2019-11-25 17:39:11 +00:00
if err = cache . PutAccountState ( accountState ) ; err != nil {
return nil , err
}
2019-11-11 15:25:28 +00:00
}
}
switch t := tx . Data . ( type ) {
case * transaction . EnrollmentTX :
2019-11-25 17:39:11 +00:00
if err := processEnrollmentTX ( cache , t ) ; err != nil {
2019-11-11 15:25:28 +00:00
return nil , err
}
case * transaction . StateTX :
2019-11-25 17:39:11 +00:00
if err := processStateTX ( cache , t ) ; err != nil {
2019-11-18 12:24:48 +00:00
return nil , err
2019-11-11 15:25:28 +00:00
}
}
}
}
2019-11-25 17:39:11 +00:00
validators := cache . GetValidators ( )
2019-11-18 14:59:43 +00:00
2019-11-28 16:06:09 +00:00
count := state . GetValidatorsWeightedAverage ( validators )
2019-11-11 15:25:28 +00:00
standByValidators , err := bc . GetStandByValidators ( )
if err != nil {
return nil , err
}
if count < len ( standByValidators ) {
count = len ( standByValidators )
}
uniqueSBValidators := standByValidators . Unique ( )
pubKeys := keys . PublicKeys { }
for _ , validator := range validators {
if validator . RegisteredAndHasVotes ( ) || uniqueSBValidators . Contains ( validator . PublicKey ) {
pubKeys = append ( pubKeys , validator . PublicKey )
}
}
sort . Sort ( sort . Reverse ( pubKeys ) )
if pubKeys . Len ( ) >= count {
return pubKeys [ : count ] , nil
}
result := pubKeys . Unique ( )
for i := 0 ; i < uniqueSBValidators . Len ( ) && result . Len ( ) < count ; i ++ {
result = append ( result , uniqueSBValidators [ i ] )
}
return result , nil
}
2019-12-13 15:43:46 +00:00
func processStateTX ( dao * cachedDao , tx * transaction . StateTX ) error {
2019-11-18 12:24:48 +00:00
for _ , desc := range tx . Descriptors {
switch desc . Type {
case transaction . Account :
2019-11-25 17:39:11 +00:00
if err := processAccountStateDescriptor ( desc , dao ) ; err != nil {
2019-11-18 12:24:48 +00:00
return err
}
case transaction . Validator :
2019-11-25 17:39:11 +00:00
if err := processValidatorStateDescriptor ( desc , dao ) ; err != nil {
2019-11-18 12:24:48 +00:00
return err
}
}
}
return nil
}
2019-12-13 15:43:46 +00:00
func processEnrollmentTX ( dao * cachedDao , tx * transaction . EnrollmentTX ) error {
2019-11-25 17:39:11 +00:00
validatorState , err := dao . GetValidatorStateOrNew ( & tx . PublicKey )
2019-11-18 12:24:48 +00:00
if err != nil {
return err
}
validatorState . Registered = true
2019-11-25 17:39:11 +00:00
return dao . PutValidatorState ( validatorState )
2019-11-18 12:24:48 +00:00
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
// GetScriptHashesForVerifying returns all the ScriptHashes of a transaction which will be use
// to verify whether the transaction is bonafide or not.
// Golang implementation of GetScriptHashesForVerifying method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L190)
func ( bc * Blockchain ) GetScriptHashesForVerifying ( t * transaction . Transaction ) ( [ ] util . Uint160 , error ) {
2019-09-30 14:37:04 +00:00
if t . Type == transaction . ClaimType {
return bc . GetScriptHashesForVerifyingClaim ( t )
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
references := bc . References ( t )
if references == nil {
return nil , errors . New ( "Invalid operation" )
}
hashes := make ( map [ util . Uint160 ] bool )
for _ , i := range t . Inputs {
2019-12-09 14:14:10 +00:00
h := references [ i ] . ScriptHash
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
if _ , ok := hashes [ h ] ; ! ok {
hashes [ h ] = true
}
}
for _ , a := range t . Attributes {
if a . Usage == transaction . Script {
2019-11-27 09:20:31 +00:00
h , err := util . Uint160DecodeBytesBE ( a . Data )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
if err != nil {
return nil , err
}
if _ , ok := hashes [ h ] ; ! ok {
hashes [ h ] = true
}
}
}
for a , outputs := range t . GroupOutputByAssetID ( ) {
as := bc . GetAssetState ( a )
if as == nil {
return nil , errors . New ( "Invalid operation" )
}
2019-09-30 13:57:24 +00:00
if as . AssetType & transaction . DutyFlag != 0 {
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
for _ , o := range outputs {
h := o . ScriptHash
if _ , ok := hashes [ h ] ; ! ok {
hashes [ h ] = true
}
}
}
}
// convert hashes to []util.Uint160
hashesResult := make ( [ ] util . Uint160 , 0 , len ( hashes ) )
for h := range hashes {
hashesResult = append ( hashesResult , h )
}
return hashesResult , nil
}
2019-10-29 14:10:50 +00:00
// spawnVMWithInterops returns a VM with script getter and interop functions set
// up for current blockchain.
func ( bc * Blockchain ) spawnVMWithInterops ( interopCtx * interopContext ) * vm . VM {
vm := vm . New ( )
vm . SetScriptGetter ( func ( hash util . Uint160 ) [ ] byte {
2019-12-13 14:10:51 +00:00
cs , err := interopCtx . dao . GetContractState ( hash )
if err != nil {
2019-10-29 14:10:50 +00:00
return nil
}
return cs . Script
} )
2019-12-18 16:49:56 +00:00
vm . RegisterInteropGetter ( interopCtx . getSystemInterop )
vm . RegisterInteropGetter ( interopCtx . getNeoInterop )
2019-10-29 14:10:50 +00:00
return vm
}
2019-10-29 15:31:39 +00:00
// GetTestVM returns a VM and a Store setup for a test run of some sort of code.
func ( bc * Blockchain ) GetTestVM ( ) ( * vm . VM , storage . Store ) {
2019-11-25 17:39:11 +00:00
tmpStore := storage . NewMemCachedStore ( bc . dao . store )
2019-12-30 11:01:49 +00:00
systemInterop := bc . newInteropContext ( trigger . Application , tmpStore , nil , nil )
2019-10-29 15:31:39 +00:00
vm := bc . spawnVMWithInterops ( systemInterop )
2020-01-21 12:37:47 +00:00
vm . SetPriceGetter ( getPrice )
2019-10-29 15:31:39 +00:00
return vm , tmpStore
}
2019-12-25 15:18:17 +00:00
// ScriptFromWitness returns verification script for provided witness.
// If hash is not equal to the witness script hash, error is returned.
func ScriptFromWitness ( hash util . Uint160 , witness * transaction . Witness ) ( [ ] byte , error ) {
2019-10-15 09:52:10 +00:00
verification := witness . VerificationScript
if len ( verification ) == 0 {
bb := new ( bytes . Buffer )
err := vm . EmitAppCall ( bb , hash , false )
if err != nil {
2019-12-25 15:18:17 +00:00
return nil , err
2019-10-15 09:52:10 +00:00
}
verification = bb . Bytes ( )
2019-12-25 15:18:17 +00:00
} else if h := witness . ScriptHash ( ) ; hash != h {
return nil , errors . New ( "witness hash mismatch" )
}
return verification , nil
}
// verifyHashAgainstScript verifies given hash against the given witness.
func ( bc * Blockchain ) verifyHashAgainstScript ( hash util . Uint160 , witness * transaction . Witness , checkedHash util . Uint256 , interopCtx * interopContext , useKeys bool ) error {
verification , err := ScriptFromWitness ( hash , witness )
if err != nil {
return err
2019-10-15 09:52:10 +00:00
}
2019-10-29 14:10:50 +00:00
vm := bc . spawnVMWithInterops ( interopCtx )
2019-11-27 09:23:18 +00:00
vm . SetCheckedHash ( checkedHash . BytesBE ( ) )
2019-10-15 09:52:10 +00:00
vm . LoadScript ( verification )
vm . LoadScript ( witness . InvocationScript )
2019-12-10 16:13:29 +00:00
if useKeys && bc . keyCache [ hash ] != nil {
vm . SetPublicKeys ( bc . keyCache [ hash ] )
}
2019-12-25 15:18:17 +00:00
err = vm . Run ( )
2019-10-15 09:52:10 +00:00
if vm . HasFailed ( ) {
2019-10-22 10:44:14 +00:00
return errors . Errorf ( "vm failed to execute the script with error: %s" , err )
2019-10-15 09:52:10 +00:00
}
resEl := vm . Estack ( ) . Pop ( )
if resEl != nil {
res , err := resEl . TryBool ( )
if err != nil {
return err
}
if ! res {
return errors . Errorf ( "signature check failed" )
}
2019-12-10 16:13:29 +00:00
if useKeys && bc . keyCache [ hash ] == nil {
bc . keyCache [ hash ] = vm . GetPublicKeys ( )
}
2019-10-15 09:52:10 +00:00
} else {
return errors . Errorf ( "no result returned from the script" )
}
return nil
}
2019-10-22 14:56:03 +00:00
// verifyTxWitnesses verifies the scripts (witnesses) that come with a given
2019-09-30 14:39:42 +00:00
// transaction. It can reorder them by ScriptHash, because that's required to
2019-10-11 14:00:11 +00:00
// match a slice of script hashes from the Blockchain. Block parameter
// is used for easy interop access and can be omitted for transactions that are
// not yet added into any block.
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
// Golang implementation of VerifyWitnesses method in C# (https://github.com/neo-project/neo/blob/master/neo/SmartContract/Helper.cs#L87).
2019-10-22 14:56:03 +00:00
// Unfortunately the IVerifiable interface could not be implemented because we can't move the References method in blockchain.go to the transaction.go file.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) verifyTxWitnesses ( t * transaction . Transaction , block * block . Block ) error {
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
hashes , err := bc . GetScriptHashesForVerifying ( t )
if err != nil {
return err
}
witnesses := t . Scripts
if len ( hashes ) != len ( witnesses ) {
return errors . Errorf ( "expected len(hashes) == len(witnesses). got: %d != %d" , len ( hashes ) , len ( witnesses ) )
}
2019-09-30 14:39:42 +00:00
sort . Slice ( hashes , func ( i , j int ) bool { return hashes [ i ] . Less ( hashes [ j ] ) } )
sort . Slice ( witnesses , func ( i , j int ) bool { return witnesses [ i ] . ScriptHash ( ) . Less ( witnesses [ j ] . ScriptHash ( ) ) } )
2019-12-30 11:01:49 +00:00
interopCtx := bc . newInteropContext ( trigger . Verification , bc . dao . store , block , t )
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
for i := 0 ; i < len ( hashes ) ; i ++ {
2019-12-10 16:13:29 +00:00
err := bc . verifyHashAgainstScript ( hashes [ i ] , & witnesses [ i ] , t . VerificationHash ( ) , interopCtx , false )
2019-10-15 09:52:10 +00:00
if err != nil {
numStr := fmt . Sprintf ( "witness #%d" , i )
return errors . Wrap ( err , numStr )
2019-09-23 17:13:44 +00:00
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
}
return nil
}
2019-10-15 09:52:10 +00:00
// verifyBlockWitnesses is a block-specific implementation of VerifyWitnesses logic.
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) verifyBlockWitnesses ( block * block . Block , prevHeader * block . Header ) error {
2019-10-15 09:52:10 +00:00
var hash util . Uint160
if prevHeader == nil && block . PrevHash . Equals ( util . Uint256 { } ) {
hash = block . Script . ScriptHash ( )
} else {
hash = prevHeader . NextConsensus
}
2019-12-30 11:01:49 +00:00
interopCtx := bc . newInteropContext ( trigger . Verification , bc . dao . store , nil , nil )
2019-12-10 16:13:29 +00:00
return bc . verifyHashAgainstScript ( hash , & block . Script , block . VerificationHash ( ) , interopCtx , true )
2019-10-15 09:52:10 +00:00
}
2018-02-06 06:43:32 +00:00
func hashAndIndexToBytes ( h util . Uint256 , index uint32 ) [ ] byte {
2019-09-16 09:18:13 +00:00
buf := io . NewBufBinWriter ( )
2019-11-27 09:23:18 +00:00
buf . WriteBytes ( h . BytesLE ( ) )
2019-12-12 15:52:23 +00:00
buf . WriteU32LE ( index )
2019-09-16 09:18:13 +00:00
return buf . Bytes ( )
2018-02-06 06:43:32 +00:00
}
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
func ( bc * Blockchain ) secondsPerBlock ( ) int {
return bc . config . SecondsPerBlock
}
2019-12-30 11:01:49 +00:00
2020-01-14 12:32:07 +00:00
func ( bc * Blockchain ) newInteropContext ( trigger byte , s storage . Store , block * block . Block , tx * transaction . Transaction ) * interopContext {
2019-12-30 11:01:49 +00:00
return newInteropContext ( trigger , bc , s , block , tx , bc . log )
}