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"
2019-02-19 11:48:48 +00:00
"context"
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-09-30 14:39:42 +00:00
"sort"
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"
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-09-16 09:18:13 +00:00
"github.com/CityOfZion/neo-go/pkg/io"
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"
2018-03-14 09:36:59 +00:00
log "github.com/sirupsen/logrus"
2018-02-04 19:54:51 +00:00
)
2018-02-01 20:28:45 +00:00
// tuning parameters
const (
2018-03-09 15:55:25 +00:00
headerBatchCount = 2000
2018-03-25 10:45:54 +00:00
version = "0.0.1"
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
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
2018-02-01 20:28:45 +00:00
// Any object that satisfies the BlockchainStorer interface.
2018-03-17 11:53:21 +00:00
storage . Store
2018-02-01 20:28:45 +00:00
2019-09-26 15:14:00 +00:00
// In-memory storage to be persisted into the storage.Store
memStore * storage . MemoryStore
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-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
2018-03-17 11:53:21 +00:00
// All operation on headerList must be called from an
// 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
// Whether we will verify received blocks.
verifyBlocks bool
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
memPool MemPool
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
2018-03-17 11:53:21 +00:00
// NewBlockchain return a new blockchain object the will use the
// given Store as its underlying storage.
2019-09-17 12:27:40 +00:00
func NewBlockchain ( s storage . Store , cfg config . ProtocolConfiguration ) ( * Blockchain , error ) {
2018-03-09 15:55:25 +00:00
bc := & Blockchain {
2018-03-25 10:45:54 +00:00
config : cfg ,
2018-03-09 15:55:25 +00:00
Store : s ,
2019-09-26 15:14:00 +00:00
memStore : storage . NewMemoryStore ( ) ,
2018-03-09 15:55:25 +00:00
headersOp : make ( chan headersOpFunc ) ,
headersOpDone : make ( chan struct { } ) ,
2018-03-14 09:36:59 +00:00
verifyBlocks : false ,
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
memPool : NewMemPool ( 50000 ) ,
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.
ver , err := storage . Version ( bc . Store )
if err != nil {
log . Infof ( "no storage version found! creating genesis block" )
2019-01-25 11:20:35 +00:00
if err = storage . PutVersion ( bc . Store , version ) ; err != nil {
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-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.
2018-04-09 16:58:09 +00:00
log . Infof ( "restoring blockchain with version: %s" , version )
2018-03-25 10:45:54 +00:00
2018-04-09 16:58:09 +00:00
bHeight , err := storage . CurrentBlockHeight ( bc . Store )
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
2018-04-09 16:58:09 +00:00
hashes , err := storage . HeaderHashes ( bc . Store )
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
2018-04-09 16:58:09 +00:00
currHeaderHeight , currHeaderHash , err := storage . CurrentHeaderHeight ( bc . Store )
2018-03-17 11:53:21 +00:00
if err != nil {
return err
}
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.
if currHeaderHeight > bc . storedHeaderCount {
hash := currHeaderHash
targetHash := bc . headerList . Get ( bc . headerList . Len ( ) - 1 )
2018-04-09 16:58:09 +00:00
headers := make ( [ ] * 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.
func ( bc * Blockchain ) Run ( ctx context . Context ) {
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-09-26 15:14:00 +00:00
if err := bc . persist ( ctx ) ; err != nil {
log . Warnf ( "failed to persist: %s" , err )
}
// never fails
_ = bc . memStore . Close ( )
2019-09-16 15:52:47 +00:00
if err := bc . Store . Close ( ) ; err != nil {
log . Warnf ( "failed to close db: %s" , err )
}
} ( )
2018-03-09 15:55:25 +00:00
for {
select {
2019-02-19 11:48:48 +00:00
case <- ctx . Done ( ) :
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-09-24 15:51:20 +00:00
err := bc . persist ( ctx )
2019-09-22 17:06:52 +00:00
if err != nil {
log . Warnf ( "failed to persist blockchain: %s" , err )
}
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-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.
2018-02-04 19:54:51 +00:00
func ( bc * Blockchain ) AddBlock ( block * Block ) error {
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-09-30 14:35:11 +00:00
if bc . verifyBlocks {
if ! block . Verify ( false ) {
return fmt . Errorf ( "block %s is invalid" , block . Hash ( ) )
}
for _ , tx := range block . Transactions {
err := bc . Verify ( tx )
if err != nil {
return fmt . Errorf ( "transaction %s failed to verify: %s" , tx . Hash ( ) . ReverseString ( ) , err )
}
}
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
}
2018-03-14 09:36:59 +00:00
// AddHeaders will process the given headers and add them to the
// HeaderHashList.
2018-03-09 15:55:25 +00:00
func ( bc * Blockchain ) AddHeaders ( headers ... * Header ) ( err error ) {
var (
start = time . Now ( )
2019-09-26 15:14:00 +00:00
batch = bc . memStore . Batch ( )
2018-03-09 15:55:25 +00:00
)
bc . headersOp <- func ( headerList * HeaderHashList ) {
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
}
2018-03-14 09:36:59 +00:00
if batch . Len ( ) > 0 {
2019-09-26 15:14:00 +00:00
if err = bc . memStore . PutBatch ( batch ) ; err != nil {
2018-03-09 15:55:25 +00:00
return
}
2018-03-14 09:36:59 +00:00
log . WithFields ( log . Fields {
"headerIndex" : headerList . Len ( ) - 1 ,
"blockHeight" : bc . BlockHeight ( ) ,
"took" : time . Since ( start ) ,
} ) . Debug ( "done processing headers" )
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.
2018-03-17 11:53:21 +00:00
func ( bc * Blockchain ) processHeader ( h * 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
}
2018-03-17 11:53:21 +00:00
key := storage . AppendPrefix ( storage . DataBlock , h . Hash ( ) . BytesReverse ( ) )
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.
2019-09-26 15:14:00 +00:00
func ( bc * Blockchain ) storeBlock ( block * Block ) error {
2018-03-21 16:11:04 +00:00
var (
2019-09-26 15:14:00 +00:00
batch = bc . memStore . Batch ( )
2018-03-21 16:11:04 +00:00
unspentCoins = make ( UnspentCoins )
2018-04-16 20:15:30 +00:00
spentCoins = make ( SpentCoins )
2018-03-21 16:11:04 +00:00
accounts = make ( Accounts )
2018-04-16 20:15:30 +00:00
assets = make ( Assets )
2019-09-30 16:52:16 +00:00
contracts = make ( Contracts )
2018-03-21 16:11:04 +00:00
)
2018-03-14 09:36:59 +00:00
2019-01-25 11:20:35 +00:00
if err := storeAsBlock ( batch , block , 0 ) ; err != nil {
return err
}
2018-03-17 11:53:21 +00:00
storeAsCurrentBlock ( batch , block )
2018-03-14 09:36:59 +00:00
2018-03-21 16:11:04 +00:00
for _ , tx := range block . Transactions {
2019-01-25 11:20:35 +00:00
if err := storeAsTransaction ( batch , tx , block . Index ) ; err != nil {
return err
}
2018-04-16 20:15:30 +00:00
unspentCoins [ tx . Hash ( ) ] = NewUnspentCoinState ( len ( tx . Outputs ) )
2018-03-21 16:11:04 +00:00
// Process TX outputs.
for _ , output := range tx . Outputs {
2019-09-26 15:14:00 +00:00
account , err := accounts . getAndUpdate ( bc . memStore , bc . Store , output . ScriptHash )
2018-03-21 16:11:04 +00:00
if err != nil {
return err
}
if _ , ok := account . Balances [ output . AssetID ] ; ok {
account . Balances [ output . AssetID ] += output . Amount
} else {
account . Balances [ output . AssetID ] = output . Amount
}
}
// 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-09-26 15:14:00 +00:00
unspent , err := unspentCoins . getAndUpdate ( bc . memStore , bc . Store , input . PrevHash )
2018-03-21 16:11:04 +00:00
if err != nil {
return err
}
unspent . states [ input . PrevIndex ] = CoinStateSpent
prevTXOutput := prevTX . Outputs [ input . PrevIndex ]
2019-09-26 15:14:00 +00:00
account , err := accounts . getAndUpdate ( bc . memStore , bc . Store , 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
spentCoins [ input . PrevHash ] = spentCoin
}
2018-03-21 16:11:04 +00:00
account . Balances [ prevTXOutput . AssetID ] -= prevTXOutput . Amount
}
}
// 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 :
2018-04-16 20:15:30 +00:00
assets [ tx . Hash ( ) ] = & AssetState {
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 ,
2018-04-16 20:15:30 +00:00
}
2018-03-21 16:11:04 +00:00
case * transaction . IssueTX :
case * transaction . ClaimTX :
case * transaction . EnrollmentTX :
case * transaction . StateTX :
case * transaction . PublishTX :
2018-04-16 20:15:30 +00:00
contract := & ContractState {
Script : t . Script ,
ParamList : t . ParamList ,
ReturnType : t . ReturnType ,
HasStorage : t . NeedStorage ,
Name : t . Name ,
CodeVersion : t . CodeVersion ,
Author : t . Author ,
Email : t . Email ,
Description : t . Description ,
}
2019-09-30 16:52:16 +00:00
contracts [ contract . ScriptHash ( ) ] = contract
2018-04-16 20:15:30 +00:00
2018-03-21 16:11:04 +00:00
case * transaction . InvocationTX :
}
}
// Persist all to storage.
if err := accounts . commit ( batch ) ; err != nil {
return err
}
if err := unspentCoins . commit ( batch ) ; err != nil {
return err
}
2018-04-16 20:15:30 +00:00
if err := spentCoins . commit ( batch ) ; err != nil {
return err
}
if err := assets . commit ( batch ) ; err != nil {
return err
}
2019-09-30 16:52:16 +00:00
if err := contracts . commit ( batch ) ; err != nil {
return err
}
2019-09-26 15:14:00 +00:00
if err := bc . memStore . PutBatch ( batch ) ; err != nil {
2018-03-14 09:36:59 +00:00
return err
}
2018-03-21 16:11:04 +00:00
2019-09-26 15:14:00 +00:00
atomic . StoreUint32 ( & bc . blockHeight , block . Index )
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.
func ( bc * Blockchain ) persist ( ctx context . Context ) error {
2018-03-09 15:55:25 +00:00
var (
2018-03-14 09:36:59 +00:00
start = time . Now ( )
2018-03-09 15:55:25 +00:00
persisted = 0
2019-09-26 15:14:00 +00:00
err error
2018-03-09 15:55:25 +00:00
)
2019-09-26 15:14:00 +00:00
persisted , err = bc . memStore . Persist ( bc . Store )
if err != nil {
return err
2018-02-04 19:54:51 +00:00
}
2019-09-26 15:14:00 +00:00
bHeight , err := storage . CurrentBlockHeight ( bc . Store )
if err != nil {
return err
2019-02-19 11:48:48 +00:00
}
2019-09-26 15:14:00 +00:00
oldHeight := atomic . SwapUint32 ( & bc . persistedHeight , bHeight )
diff := bHeight - oldHeight
2018-03-14 09:36:59 +00:00
if persisted > 0 {
log . WithFields ( log . Fields {
2019-09-26 15:14:00 +00:00
"persistedBlocks" : diff ,
"persistedKeys" : persisted ,
"headerHeight" : bc . HeaderHeight ( ) ,
"blockHeight" : bc . BlockHeight ( ) ,
"persistedHeight" : bc . persistedHeight ,
"took" : time . Since ( start ) ,
2018-03-14 09:36:59 +00:00
} ) . Info ( "blockchain persist completed" )
}
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-09-26 15:14:00 +00:00
tx , height , err := getTransactionFromStore ( bc . memStore , hash )
if err != nil {
tx , height , err = getTransactionFromStore ( bc . Store , hash )
}
return tx , height , 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
2019-09-26 15:14:00 +00:00
// getTransactionFromStore returns Transaction and its height by the given hash
// if it exists in the store.
func getTransactionFromStore ( s storage . Store , hash util . Uint256 ) ( * transaction . Transaction , uint32 , error ) {
2018-03-21 16:11:04 +00:00
key := storage . AppendPrefix ( storage . DataTransaction , hash . BytesReverse ( ) )
2019-09-26 15:14:00 +00:00
b , err := s . Get ( key )
2018-03-21 16:11:04 +00:00
if err != nil {
return nil , 0 , err
}
2019-09-16 09:18:13 +00:00
r := io . NewBinReaderFromBuf ( b )
2018-03-21 16:11:04 +00:00
var height uint32
2019-09-16 09:18:13 +00:00
r . ReadLE ( & height )
2019-09-16 16:31:49 +00:00
tx := & transaction . Transaction { }
tx . DecodeBinary ( r )
2019-09-16 09:18:13 +00:00
if r . Err != nil {
return nil , 0 , r . Err
2018-03-21 16:11:04 +00:00
}
return tx , height , nil
}
2018-03-14 09:36:59 +00:00
// GetBlock returns a Block by the given hash.
func ( bc * Blockchain ) GetBlock ( hash util . Uint256 ) ( * Block , error ) {
2019-09-26 15:14:00 +00:00
block , err := getBlockFromStore ( bc . memStore , hash )
if err != nil {
block , err = getBlockFromStore ( bc . Store , hash )
2019-09-24 15:51:20 +00:00
if err != nil {
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
}
return block , nil
}
2019-09-26 15:14:00 +00:00
// getBlockFromStore returns Block by the given hash if it exists in the store.
func getBlockFromStore ( s storage . Store , hash util . Uint256 ) ( * Block , error ) {
key := storage . AppendPrefix ( storage . DataBlock , hash . BytesReverse ( ) )
b , err := s . Get ( key )
if err != nil {
return nil , err
}
block , err := NewBlockFromTrimmedBytes ( b )
if err != nil {
return nil , err
}
return block , err
}
2019-09-03 14:51:37 +00:00
// GetHeader returns data block header identified with the given hash value.
2019-02-20 17:39:32 +00:00
func ( bc * Blockchain ) GetHeader ( hash util . Uint256 ) ( * Header , error ) {
2019-09-26 15:14:00 +00:00
header , err := getHeaderFromStore ( bc . memStore , hash )
if err != nil {
header , err = getHeaderFromStore ( bc . Store , hash )
2019-09-24 15:51:20 +00:00
if err != nil {
return nil , err
}
2018-03-17 11:53:21 +00:00
}
2019-09-26 15:14:00 +00:00
return header , err
}
// getHeaderFromStore returns Header by the given hash from the store.
func getHeaderFromStore ( s storage . Store , hash util . Uint256 ) ( * Header , error ) {
block , err := getBlockFromStore ( s , hash )
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
}
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
// HasTransaction return 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-09-26 15:14:00 +00:00
return bc . memPool . ContainsKey ( hash ) ||
checkTransactionInStore ( bc . memStore , hash ) ||
checkTransactionInStore ( bc . Store , hash )
}
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-26 15:14:00 +00:00
// checkTransactionInStore returns true if the given store contains the given
// Transaction hash.
func checkTransactionInStore ( s storage . Store , hash util . Uint256 ) bool {
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
key := storage . AppendPrefix ( storage . DataTransaction , hash . BytesReverse ( ) )
2019-09-26 15:14:00 +00:00
if _ , err := s . Get ( key ) ; err == 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 true
}
2018-03-14 09:36:59 +00:00
return false
}
// HasBlock return true if the blockchain contains the given
// 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
}
2018-03-14 09:36:59 +00:00
// GetHeaderHash return the hash from the headerList by its
// 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-02-08 08:04:38 +00:00
// GetAssetState returns asset state from its assetID
2018-11-26 21:12:33 +00:00
func ( bc * Blockchain ) GetAssetState ( assetID util . Uint256 ) * AssetState {
2019-09-26 15:14:00 +00:00
as := getAssetStateFromStore ( bc . memStore , assetID )
if as == nil {
as = getAssetStateFromStore ( bc . Store , assetID )
}
2018-11-26 21:12:33 +00:00
return as
}
2019-09-26 15:14:00 +00:00
// getAssetStateFromStore returns given asset state as recorded in the given
// store.
func getAssetStateFromStore ( s storage . Store , assetID util . Uint256 ) * AssetState {
key := storage . AppendPrefix ( storage . STAsset , assetID . Bytes ( ) )
asEncoded , err := s . Get ( key )
if err != nil {
return nil
}
var a AssetState
r := io . NewBinReaderFromBuf ( asEncoded )
a . DecodeBinary ( r )
if r . Err != nil || a . ID != assetID {
return nil
}
return & a
}
2019-09-30 16:52:16 +00:00
// GetContractState returns contract by its script hash.
func ( bc * Blockchain ) GetContractState ( hash util . Uint160 ) * ContractState {
cs := getContractStateFromStore ( bc . memStore , hash )
if cs == nil {
cs = getContractStateFromStore ( bc . Store , hash )
}
return cs
}
// getContractStateFromStore returns contract state as recorded in the given
// store by the given script hash.
func getContractStateFromStore ( s storage . Store , hash util . Uint160 ) * ContractState {
key := storage . AppendPrefix ( storage . STContract , hash . Bytes ( ) )
contractBytes , err := s . Get ( key )
if err != nil {
return nil
}
var c ContractState
r := io . NewBinReaderFromBuf ( contractBytes )
c . DecodeBinary ( r )
if r . Err != nil || c . ScriptHash ( ) != hash {
return nil
}
return & c
}
2019-02-08 08:04:38 +00:00
// GetAccountState returns the account state from its script hash
func ( bc * Blockchain ) GetAccountState ( scriptHash util . Uint160 ) * AccountState {
2019-09-26 15:14:00 +00:00
as , err := getAccountStateFromStore ( bc . memStore , scriptHash )
if as == nil {
if err != storage . ErrKeyNotFound {
log . Warnf ( "failed to get account state: %s" , err )
2019-02-08 08:04:38 +00:00
}
2019-09-26 15:14:00 +00:00
as , err = getAccountStateFromStore ( bc . Store , scriptHash )
if as == nil && err != storage . ErrKeyNotFound {
log . Warnf ( "failed to get account state: %s" , err )
}
}
2019-02-08 08:04:38 +00:00
return as
}
2019-02-20 17:39:32 +00:00
// GetConfig returns the config stored in the blockchain
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-09-30 14:42:37 +00:00
references [ * in ] = tx . Outputs [ in . PrevIndex ]
2019-02-20 17:39:32 +00:00
}
} else {
references = nil
}
}
return references
}
// FeePerByte returns network fee divided by the size of the transaction
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
}
// NetworkFee returns network fee
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 ) )
}
// SystemFee returns system fee
func ( bc * Blockchain ) SystemFee ( t * transaction . Transaction ) util . Fixed8 {
return bc . GetConfig ( ) . SystemFee . TryGetValue ( t . Type )
}
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
// IsLowPriority flags a trnsaction as low priority if the network fee is less than
// LowPriorityThreshold
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.
func ( bc * Blockchain ) GetMemPool ( ) MemPool {
return bc . memPool
}
// Verify verifies whether a transaction is bonafide or not.
// 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 ) Verify ( t * transaction . Transaction ) 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" )
}
if ok := bc . memPool . Verify ( t ) ; ! ok {
return errors . New ( "invalid transaction due to conflicts with the memory pool" )
}
if IsDoubleSpend ( bc . Store , t ) {
return errors . New ( "invalid transaction caused by double spending" )
}
if ok := bc . verifyOutputs ( t ) ; ! ok {
return errors . New ( "invalid transaction's outputs" )
}
if ok := bc . verifyResults ( t ) ; ! ok {
return errors . New ( "invalid transaction's results" )
}
for _ , a := range t . Attributes {
if a . Usage == transaction . ECDH02 || a . Usage == transaction . ECDH03 {
return errors . Errorf ( "invalid attribute's usage = %s " , a . Usage )
}
}
return bc . VerifyWitnesses ( t )
}
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
}
func ( bc * Blockchain ) verifyOutputs ( t * transaction . Transaction ) bool {
for assetID , outputs := range t . GroupOutputByAssetID ( ) {
assetState := bc . GetAssetState ( assetID )
if assetState == nil {
return false
}
if assetState . Expiration < bc . blockHeight + 1 && assetState . AssetType != transaction . GoverningToken && assetState . AssetType != transaction . UtilityToken {
return false
}
for _ , out := range outputs {
if int64 ( out . Amount ) % int64 ( math . Pow10 ( 8 - int ( assetState . Precision ) ) ) != 0 {
return false
}
}
}
return true
}
func ( bc * Blockchain ) verifyResults ( t * transaction . Transaction ) bool {
results := bc . GetTransationResults ( t )
if results == nil {
return false
}
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 {
return false
}
if len ( resultsDestroy ) == 1 && resultsDestroy [ 0 ] . AssetID != utilityTokenTX ( ) . Hash ( ) {
return false
}
if bc . SystemFee ( t ) . GreaterThan ( util . Fixed8 ( 0 ) ) && ( len ( resultsDestroy ) == 0 || resultsDestroy [ 0 ] . Amount . LessThan ( bc . SystemFee ( t ) ) ) {
return false
}
switch t . Type {
case transaction . MinerType , transaction . ClaimType :
for _ , r := range resultsIssue {
if r . AssetID != utilityTokenTX ( ) . Hash ( ) {
return false
}
}
break
case transaction . IssueType :
for _ , r := range resultsIssue {
if r . AssetID == utilityTokenTX ( ) . Hash ( ) {
return false
}
}
break
default :
if len ( resultsIssue ) > 0 {
return false
}
break
}
return true
}
// GetTransationResults returns the transaction results aggregate by assetID.
// Golang of GetTransationResults method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L207)
func ( bc * Blockchain ) GetTransationResults ( t * transaction . Transaction ) [ ] * transaction . Result {
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 ) {
hashes := make ( [ ] util . Uint160 , 0 )
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" )
}
hashes = append ( hashes , refTx . Outputs [ input . PrevIndex ] . ScriptHash )
}
}
if len ( hashes ) > 0 {
return hashes , nil
}
return nil , fmt . Errorf ( "no hashes found" )
}
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-09-30 14:42:37 +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 {
h , err := util . Uint160DecodeBytes ( a . Data )
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-09-30 14:39:42 +00:00
// VerifyWitnesses verify the scripts (witnesses) that come with a given
// transaction. It can reorder them by ScriptHash, because that's required to
// match a slice of script hashes from the Blockchain.
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).
// Unfortunately the IVerifiable interface could not be implemented because we can't move the References method in blockchain.go to the transaction.go file
func ( bc * Blockchain ) VerifyWitnesses ( t * transaction . Transaction ) error {
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 ( ) ) } )
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 ++ {
verification := witnesses [ i ] . VerificationScript
if len ( verification ) == 0 {
2019-09-23 17:13:44 +00:00
bb := new ( bytes . Buffer )
err = vm . EmitAppCall ( bb , hashes [ i ] , false )
if 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
}
2019-09-23 17:13:44 +00:00
verification = bb . Bytes ( )
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
} else {
2019-08-23 15:50:45 +00:00
if h := witnesses [ i ] . ScriptHash ( ) ; hashes [ i ] != h {
return errors . Errorf ( "hash mismatch for script #%d" , i )
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-23 17:13:44 +00:00
vm := vm . New ( vm . ModeMute )
vm . SetCheckedHash ( t . VerificationHash ( ) . Bytes ( ) )
2019-09-30 16:52:16 +00:00
vm . SetScriptGetter ( func ( hash util . Uint160 ) [ ] byte {
cs := bc . GetContractState ( hash )
if cs == nil {
return nil
}
return cs . Script
} )
2019-09-23 17:13:44 +00:00
vm . LoadScript ( verification )
vm . LoadScript ( witnesses [ i ] . InvocationScript )
vm . Run ( )
if vm . HasFailed ( ) {
return errors . Errorf ( "vm failed to execute the script" )
}
2019-10-03 13:26:32 +00:00
resEl := vm . Estack ( ) . Pop ( )
if resEl != nil {
res , err := resEl . TryBool ( )
if err != nil {
return err
}
if ! res {
2019-09-23 17:13:44 +00:00
return errors . Errorf ( "signature check failed" )
}
2019-10-03 13:26:32 +00:00
} else {
return errors . Errorf ( "no result returned from the script" )
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
}
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 ( )
buf . WriteLE ( h . BytesReverse ( ) )
buf . WriteLE ( index )
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
}