2018-02-01 20:28:45 +00:00
package core
2018-02-04 19:54:51 +00:00
import (
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"
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"
2020-03-25 15:30:21 +00:00
"github.com/nspcc-dev/neo-go/pkg/config"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/core/block"
2020-04-07 09:41:12 +00:00
"github.com/nspcc-dev/neo-go/pkg/core/dao"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
2020-05-29 14:20:00 +00:00
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
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
2020-03-23 12:03:37 +00:00
version = "0.0.9"
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" )
2020-02-18 17:16:38 +00:00
// ErrPolicy is returned on attempt to add transaction that doesn't
// comply with node's configured policy into the mempool.
ErrPolicy = errors . New ( "not allowed by policy" )
2020-03-04 10:06:18 +00:00
// ErrInvalidBlockIndex is returned when trying to add block with index
// other than expected height of the blockchain.
ErrInvalidBlockIndex error = errors . New ( "invalid block index" )
2020-02-04 15:43:21 +00:00
)
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
)
2020-05-07 19:04:10 +00:00
// Blockchain represents the blockchain. It maintans internal state representing
// the state of the ledger that can be accessed in various ways and changed by
// adding new blocks or headers.
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.
2020-04-07 09:41:12 +00:00
dao * dao . Simple
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
2020-02-25 13:15:17 +00:00
generationAmount [ ] int
decrementInterval int
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
core: protect (*Blockchain).keyCache with a lock
Avoid failures like this:
fatal error: concurrent map writes
goroutine 103 [running]:
runtime.throw(0xca6fe3, 0x15)
/usr/lib64/go/1.12/src/runtime/panic.go:617 +0x72 fp=0xc000687988 sp=0xc000687958 pc=0x42d8d2
runtime.mapassign(0xb9d4a0, 0xc0000b1f80, 0xc000687a6c, 0x13bd940)
/usr/lib64/go/1.12/src/runtime/map.go:590 +0x5e3 fp=0xc000687a10 sp=0xc000687988 pc=0x40e2a3
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHashAgainstScript(0xc0000f8000, 0x1300d1f5a3d348be, 0x78607089e4fe9fab, 0xc0a21e4f71, 0xc000d16070, 0x1e2b8881f8178e92, 0xd589cfa965287bb8, 0x24a4e4f292ebc797, 0xb90d3120d878e619, 0xc0001d01e0, ...)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1866 +0x371 fp=0xc000687ad8 sp=0xc000687a10 pc=0x984ed1
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHeaderWitnesses(0xc0000f8000, 0xc000d16000, 0xc00042d950, 0x1, 0xc00008a6c0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1914 +0x209 fp=0xc000687c90 sp=0xc000687ad8 pc=0x985999
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHeader(0xc0000f8000, 0xc000d16000, 0xc00042d950, 0xf0ee0049d611101f, 0xf8967398a8f9351b)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1254 +0x235 fp=0xc000687d70 sp=0xc000687c90 pc=0x97e4e5
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000f8000, 0x1, 0xc000d12000, 0x7d0, 0x7d0, 0x0, 0x1)
/home/rik/dev/neo-go/pkg/core/blockchain.go:369 +0x266 fp=0xc000687e68 sp=0xc000687d70 pc=0x973f46
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddHeaders(0xc0000f8000, 0xc000d12000, 0x7d0, 0x7d0, 0x0, 0xc0003640c0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:338 +0x51 fp=0xc000687eb0 sp=0xc000687e68 pc=0x973cb1
github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleHeadersCmd(0xc00022c140, 0xdd0ca0, 0xc000374000, 0xc00000c020)
/home/rik/dev/neo-go/pkg/network/server.go:431 +0x74 fp=0xc000687fc0 sp=0xc000687eb0 pc=0x9ce5e4
runtime.goexit()
/usr/lib64/go/1.12/src/runtime/asm_amd64.s:1337 +0x1 fp=0xc000687fc8 sp=0xc000687fc0 pc=0x45ca51
created by github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage
/home/rik/dev/neo-go/pkg/network/server.go:705 +0xa4a
...
2020-03-04 17:26:18 +00:00
// This lock protects concurrent access to keyCache.
keyCacheLock sync . RWMutex
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
2020-02-06 15:47:03 +00:00
lastBatch * storage . MemBatch
2020-05-12 14:20:41 +00:00
// Notification subsystem.
events chan bcEvent
subCh chan interface { }
unsubCh chan interface { }
}
// bcEvent is an internal event generated by the Blockchain and then
// broadcasted to other parties. It joins the new block and associated
// invocation logs, all the other events visible from outside can be produced
// from this combination.
type bcEvent struct {
block * block . Block
appExecResults [ ] * state . AppExecResult
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
2020-05-07 19:04:10 +00:00
// given Store as its underlying storage. For it to work correctly you need
// to spawn a goroutine for its Run method after this initialization.
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 ) )
}
2020-02-18 17:16:38 +00:00
if cfg . MaxTransactionsPerBlock <= 0 {
cfg . MaxTransactionsPerBlock = 0
log . Info ( "MaxTransactionsPerBlock is not set or wrong, setting default value (unlimited)" , zap . Int ( "MaxTransactionsPerBlock" , cfg . MaxTransactionsPerBlock ) )
}
if cfg . MaxFreeTransactionsPerBlock <= 0 {
cfg . MaxFreeTransactionsPerBlock = 0
log . Info ( "MaxFreeTransactionsPerBlock is not set or wrong, setting default value (unlimited)" , zap . Int ( "MaxFreeTransactionsPerBlock" , cfg . MaxFreeTransactionsPerBlock ) )
}
if cfg . MaxFreeTransactionSize <= 0 {
cfg . MaxFreeTransactionSize = 0
log . Info ( "MaxFreeTransactionSize is not set or wrong, setting default value (unlimited)" , zap . Int ( "MaxFreeTransactionSize" , cfg . MaxFreeTransactionSize ) )
}
if cfg . FeePerExtraByte <= 0 {
cfg . FeePerExtraByte = 0
log . Info ( "FeePerExtraByte is not set or wrong, setting default value" , zap . Float64 ( "FeePerExtraByte" , cfg . FeePerExtraByte ) )
}
2018-03-09 15:55:25 +00:00
bc := & Blockchain {
2018-03-25 10:45:54 +00:00
config : cfg ,
2020-04-07 09:41:12 +00:00
dao : dao . NewSimple ( 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 ,
2020-05-12 14:20:41 +00:00
events : make ( chan bcEvent ) ,
subCh : make ( chan interface { } ) ,
unsubCh : make ( chan interface { } ) ,
2020-02-25 13:15:17 +00:00
generationAmount : genAmount ,
decrementInterval : decrementInterval ,
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
2020-05-29 14:20:00 +00:00
if err = bc . dao . InitMPT ( bHeight ) ; err != nil {
return errors . Wrapf ( err , "can't init MPT at height %d" , 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
}
2020-05-07 19:04:10 +00:00
// Run runs chain loop, it needs to be run as goroutine and executing it is
// critical for correct Blockchain operation.
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
}
2020-04-07 09:41:12 +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
} ( )
2020-05-12 14:20:41 +00:00
go bc . notificationDispatcher ( )
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
}
2020-02-24 14:17:25 +00:00
persistTimer . Reset ( persistInterval )
2019-09-18 15:21:16 +00:00
} ( )
2018-03-09 15:55:25 +00:00
}
2018-02-04 19:54:51 +00:00
}
}
2020-05-12 14:20:41 +00:00
// notificationDispatcher manages subscription to events and broadcasts new events.
func ( bc * Blockchain ) notificationDispatcher ( ) {
var (
// These are just sets of subscribers, though modelled as maps
// for ease of management (not a lot of subscriptions is really
// expected, but maps are convenient for adding/deleting elements).
blockFeed = make ( map [ chan <- * block . Block ] bool )
txFeed = make ( map [ chan <- * transaction . Transaction ] bool )
notificationFeed = make ( map [ chan <- * state . NotificationEvent ] bool )
executionFeed = make ( map [ chan <- * state . AppExecResult ] bool )
)
for {
select {
case <- bc . stopCh :
return
case sub := <- bc . subCh :
switch ch := sub . ( type ) {
case chan <- * block . Block :
blockFeed [ ch ] = true
case chan <- * transaction . Transaction :
txFeed [ ch ] = true
case chan <- * state . NotificationEvent :
notificationFeed [ ch ] = true
case chan <- * state . AppExecResult :
executionFeed [ ch ] = true
default :
panic ( fmt . Sprintf ( "bad subscription: %T" , sub ) )
}
case unsub := <- bc . unsubCh :
switch ch := unsub . ( type ) {
case chan <- * block . Block :
delete ( blockFeed , ch )
case chan <- * transaction . Transaction :
delete ( txFeed , ch )
case chan <- * state . NotificationEvent :
delete ( notificationFeed , ch )
case chan <- * state . AppExecResult :
delete ( executionFeed , ch )
default :
panic ( fmt . Sprintf ( "bad unsubscription: %T" , unsub ) )
}
case event := <- bc . events :
// We don't want to waste time looping through transactions when there are no
// subscribers.
if len ( txFeed ) != 0 || len ( notificationFeed ) != 0 || len ( executionFeed ) != 0 {
var aerIdx int
for _ , tx := range event . block . Transactions {
if tx . Type == transaction . InvocationType {
aer := event . appExecResults [ aerIdx ]
if ! aer . TxHash . Equals ( tx . Hash ( ) ) {
panic ( "inconsistent application execution results" )
}
aerIdx ++
for ch := range executionFeed {
ch <- aer
}
if aer . VMState == "HALT" {
for i := range aer . Events {
for ch := range notificationFeed {
ch <- & aer . Events [ i ]
}
}
}
}
for ch := range txFeed {
ch <- tx
}
}
}
for ch := range blockFeed {
ch <- event . block
}
}
}
}
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 {
2020-03-04 10:06:18 +00:00
return ErrInvalidBlockIndex
2018-03-09 15:55:25 +00:00
}
2020-02-29 14:52:09 +00:00
headerLen := bc . headerListLen ( )
if int ( block . Index ) == headerLen {
err := bc . addHeaders ( bc . config . VerifyBlocks , block . Header ( ) )
if err != nil {
return err
}
}
2019-10-11 14:46:47 +00:00
if bc . config . VerifyBlocks {
2019-10-15 09:52:10 +00:00
err := block . Verify ( )
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
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
2020-03-03 12:34:03 +00:00
// HeaderHashList. It expects headers to be sorted by index.
2020-02-29 14:52:09 +00:00
func ( bc * Blockchain ) AddHeaders ( headers ... * block . Header ) error {
return bc . addHeaders ( bc . config . VerifyBlocks , headers ... )
}
2020-03-03 12:34:03 +00:00
// addHeaders is an internal implementation of AddHeaders (`verify` parameter
// tells it to verify or not verify given headers).
2020-02-29 14:52:09 +00:00
func ( bc * Blockchain ) addHeaders ( verify bool , headers ... * block . Header ) ( err error ) {
2018-03-09 15:55:25 +00:00
var (
start = time . Now ( )
2020-04-07 09:41:12 +00:00
batch = bc . dao . Store . Batch ( )
2018-03-09 15:55:25 +00:00
)
2020-03-03 12:34:03 +00:00
if len ( headers ) > 0 {
var i int
curHeight := bc . HeaderHeight ( )
for i = range headers {
if headers [ i ] . Index > curHeight {
break
}
}
headers = headers [ i : ]
}
2020-02-29 14:52:09 +00:00
if len ( headers ) == 0 {
return nil
} else if verify {
// Verify that the chain of the headers is consistent.
var lastHeader * block . Header
if lastHeader , err = bc . GetHeader ( headers [ 0 ] . PrevHash ) ; err != nil {
return fmt . Errorf ( "previous header was not found: %v" , err )
}
for _ , h := range headers {
if err = bc . verifyHeader ( h , lastHeader ) ; err != nil {
return
}
lastHeader = h
}
}
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 )
2020-04-07 09:41:12 +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 ( )
2020-02-27 13:31:28 +00:00
buf . BinWriter . WriteU32LE ( 0 ) // sys fee is yet to be calculated
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
}
2020-02-27 13:42:17 +00:00
// bc.GetHeaderHash(int(endHeight)) returns sum of all system fees for blocks up to h.
// and 0 if no such block exists.
func ( bc * Blockchain ) getSystemFeeAmount ( h util . Uint256 ) uint32 {
_ , sf , _ := bc . dao . GetBlock ( h )
return sf
}
2020-05-29 14:20:00 +00:00
// GetStateRoot returns state root for a given height.
func ( bc * Blockchain ) GetStateRoot ( height uint32 ) ( * state . MPTRootState , error ) {
return bc . dao . GetStateRoot ( height )
}
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 {
2020-04-07 09:41:12 +00:00
cache := dao . NewCached ( bc . dao )
2020-05-12 14:20:41 +00:00
appExecResults := make ( [ ] * state . AppExecResult , 0 , len ( block . Transactions ) )
2020-02-27 13:42:17 +00:00
fee := bc . getSystemFeeAmount ( block . PrevHash )
for _ , tx := range block . Transactions {
2020-03-04 10:26:08 +00:00
fee += uint32 ( bc . SystemFee ( tx ) . IntegralValue ( ) )
2020-02-27 13:42:17 +00:00
}
if err := cache . StoreAsBlock ( block , fee ) ; 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
}
2020-03-09 15:56:24 +00:00
if err := cache . PutUnspentCoinState ( tx . Hash ( ) , state . NewUnspentCoin ( block . Index , tx ) ) ; err != nil {
2019-11-25 17:39:11 +00:00
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.
2020-02-25 15:32:10 +00:00
for _ , inputs := range transaction . GroupInputsByPrevHash ( tx . Inputs ) {
prevHash := inputs [ 0 ] . PrevHash
2020-03-09 15:56:24 +00:00
unspent , err := cache . GetUnspentCoinState ( prevHash )
2020-02-24 15:52:09 +00:00
if err != nil {
return err
}
2018-03-21 16:11:04 +00:00
for _ , input := range inputs {
2020-03-09 15:56:24 +00:00
if len ( unspent . States ) <= int ( input . PrevIndex ) {
return fmt . Errorf ( "bad input: %s/%d" , input . PrevHash . StringLE ( ) , input . PrevIndex )
}
if unspent . States [ input . PrevIndex ] . State & state . CoinSpent != 0 {
return fmt . Errorf ( "double spend: %s/%d" , input . PrevHash . StringLE ( ) , input . PrevIndex )
}
unspent . States [ input . PrevIndex ] . State |= state . CoinSpent
unspent . States [ input . PrevIndex ] . SpendHeight = block . Index
prevTXOutput := & unspent . States [ input . PrevIndex ] . Output
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
}
2020-02-14 14:44:46 +00:00
if prevTXOutput . AssetID . Equals ( GoverningTokenID ( ) ) {
2020-03-13 10:54:13 +00:00
err = account . Unclaimed . Put ( & state . UnclaimedBalance {
2020-03-09 15:56:24 +00:00
Tx : input . PrevHash ,
2020-02-25 14:29:37 +00:00
Index : input . PrevIndex ,
2020-03-09 15:56:24 +00:00
Start : unspent . Height ,
2020-02-25 14:29:37 +00:00
End : block . Index ,
Value : prevTXOutput . Amount ,
} )
2020-03-13 10:54:13 +00:00
if err != nil {
return err
}
2020-03-09 15:56:24 +00:00
if err = processTXWithValidatorsSubtract ( prevTXOutput , account , cache ) ; err != nil {
2019-12-11 10:10:51 +00:00
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 {
2020-03-05 17:42:18 +00:00
last := balancesLen - 1
if last > index {
account . Balances [ prevTXOutput . AssetID ] [ index ] = account . Balances [ prevTXOutput . AssetID ] [ last ]
}
account . Balances [ prevTXOutput . AssetID ] = account . Balances [ prevTXOutput . AssetID ] [ : last ]
2019-12-06 15:44:28 +00:00
}
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
}
2020-02-24 15:52:09 +00:00
if err = cache . PutUnspentCoinState ( prevHash , unspent ) ; 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 {
2020-03-09 15:56:24 +00:00
scs , err := cache . GetUnspentCoinState ( input . PrevHash )
2020-02-24 16:05:55 +00:00
if err == nil {
2020-03-09 15:56:24 +00:00
if len ( scs . States ) <= int ( input . PrevIndex ) {
err = errors . New ( "invalid claim index" )
} else if scs . States [ input . PrevIndex ] . State & state . CoinClaimed != 0 {
err = errors . New ( "double claim" )
2020-02-24 16:05:55 +00:00
}
}
2019-11-11 12:35:57 +00:00
if err != nil {
2020-02-24 16:05:55 +00:00
// We can't really do anything about it
// as it's a transaction in a signed block.
2020-03-09 15:56:24 +00:00
bc . log . Warn ( "FALSE OR DOUBLE CLAIM" ,
2020-02-24 16:05:55 +00:00
zap . String ( "PrevHash" , input . PrevHash . StringLE ( ) ) ,
zap . Uint16 ( "PrevIndex" , input . PrevIndex ) ,
zap . String ( "tx" , tx . Hash ( ) . StringLE ( ) ) ,
zap . Uint32 ( "block" , block . Index ) ,
)
// "Strict" mode.
if bc . config . VerifyTransactions {
return err
}
break
2019-11-11 12:35:57 +00:00
}
2020-02-25 14:29:37 +00:00
2020-03-09 15:56:24 +00:00
acc , err := cache . GetAccountState ( scs . States [ input . PrevIndex ] . ScriptHash )
2020-02-25 14:29:37 +00:00
if err != nil {
return err
}
2020-03-09 15:56:24 +00:00
scs . States [ input . PrevIndex ] . State |= state . CoinClaimed
if err = cache . PutUnspentCoinState ( input . PrevHash , scs ) ; err != nil {
2020-02-25 14:29:37 +00:00
return err
}
2020-03-13 10:54:13 +00:00
changed := acc . Unclaimed . Remove ( input . PrevHash , input . PrevIndex )
2020-02-25 14:29:37 +00:00
if ! changed {
bc . log . Warn ( "no spent coin in the account" ,
zap . String ( "tx" , tx . Hash ( ) . StringLE ( ) ) ,
zap . String ( "input" , input . PrevHash . StringLE ( ) ) ,
zap . String ( "account" , acc . ScriptHash . String ( ) ) )
} else if err := cache . PutAccountState ( acc ) ; 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 :
2020-04-03 06:49:01 +00:00
systemInterop := bc . newInteropContext ( trigger . Application , cache , block , tx )
2020-04-07 09:54:43 +00:00
v := systemInterop . SpawnVM ( )
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-02-10 14:12:38 +00:00
if bc . config . FreeGasLimit > 0 {
2020-01-21 13:39:48 +00:00
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 {
2020-03-05 08:51:19 +00:00
bs , ok := arr [ 3 ] . Value ( ) . ( [ ] byte )
if ! ok {
continue
}
amount = emit . BytesToInt ( bs )
2019-11-15 14:52:47 +00:00
}
2020-03-05 07:45:50 +00:00
bc . processNEP5Transfer ( cache , tx , block , note . ScriptHash , from , to , amount . Int64 ( ) )
2019-11-15 14:52:47 +00:00
}
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 ( ) ,
2020-03-23 12:03:37 +00:00
Stack : v . Estack ( ) . ToContractParameters ( ) ,
2019-11-13 13:55:20 +00:00
Events : systemInterop . notifications ,
}
2020-05-12 14:20:41 +00:00
appExecResults = append ( appExecResults , aer )
2019-11-25 17:39:11 +00:00
err = cache . PutAppExecResult ( aer )
2019-11-13 13:55:20 +00:00
if err != nil {
2020-04-07 09:41:12 +00:00
return errors . Wrap ( err , "failed to Store notifications" )
2019-11-13 13:55:20 +00:00
}
2018-03-21 16:11:04 +00:00
}
}
2020-02-04 15:43:21 +00:00
2020-05-29 14:20:00 +00:00
root := bc . dao . MPT . StateRoot ( )
var prevHash util . Uint256
if block . Index > 0 {
prev , err := bc . dao . GetStateRoot ( block . Index - 1 )
if err != nil {
return errors . WithMessagef ( err , "can't get previous state root" )
}
2020-06-04 14:19:30 +00:00
prevHash = hash . DoubleSha256 ( prev . GetSignedPart ( ) )
2020-05-29 14:20:00 +00:00
}
err := bc . AddStateRoot ( & state . MPTRoot {
MPTRootBase : state . MPTRootBase {
Index : block . Index ,
PrevHash : prevHash ,
Root : root ,
} ,
} )
if err != nil {
return err
}
2020-02-06 15:47:03 +00:00
if bc . config . SaveStorageBatch {
2020-04-07 09:41:12 +00:00
bc . lastBatch = cache . DAO . GetBatch ( )
2020-02-06 15:47:03 +00:00
}
2020-05-12 14:45:17 +00:00
bc . lock . Lock ( )
2020-05-29 14:20:00 +00:00
_ , err = cache . Persist ( )
2019-12-11 10:10:51 +00:00
if err != nil {
2020-05-12 14:45:17 +00:00
bc . lock . Unlock ( )
2018-03-21 16:11:04 +00:00
return err
}
2020-05-29 14:20:00 +00:00
bc . dao . MPT . Flush ( )
2020-06-04 14:25:57 +00:00
// Every persist cycle we also compact our in-memory MPT.
persistedHeight := atomic . LoadUint32 ( & bc . persistedHeight )
if persistedHeight == block . Index - 1 {
// 10 is good and roughly estimated to fit remaining trie into 1M of memory.
bc . dao . MPT . Collapse ( 10 )
}
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 )
2020-02-05 21:23:49 +00:00
bc . memPool . RemoveStale ( bc . isTxStillRelevant )
2020-05-12 14:45:17 +00:00
bc . lock . Unlock ( )
updateBlockHeightMetric ( block . Index )
2020-05-12 14:20:41 +00:00
// Genesis block is stored when Blockchain is not yet running, so there
// is no one to read this event. And it doesn't make much sense as event
// anyway.
if block . Index != 0 {
bc . events <- bcEvent { block , appExecResults }
}
2018-03-09 15:55:25 +00:00
return nil
}
2020-03-05 14:11:58 +00:00
func parseUint160 ( addr [ ] byte ) util . Uint160 {
2020-03-05 07:45:50 +00:00
if u , err := util . Uint160DecodeBytesBE ( addr ) ; err == nil {
2020-03-05 14:11:58 +00:00
return u
2020-03-05 07:45:50 +00:00
}
2020-03-05 14:11:58 +00:00
return util . Uint160 { }
2020-03-05 07:45:50 +00:00
}
2020-04-07 09:41:12 +00:00
func ( bc * Blockchain ) processNEP5Transfer ( cache * dao . Cached , tx * transaction . Transaction , b * block . Block , sc util . Uint160 , from , to [ ] byte , amount int64 ) {
2020-03-05 07:45:50 +00:00
toAddr := parseUint160 ( to )
fromAddr := parseUint160 ( from )
2020-03-05 14:11:58 +00:00
transfer := & state . NEP5Transfer {
Asset : sc ,
From : fromAddr ,
To : toAddr ,
Block : b . Index ,
Timestamp : b . Timestamp ,
Tx : tx . Hash ( ) ,
}
if ! fromAddr . Equals ( util . Uint160 { } ) {
2020-03-11 15:22:46 +00:00
balances , err := cache . GetNEP5Balances ( fromAddr )
2020-03-05 07:45:50 +00:00
if err != nil {
return
}
2020-03-11 15:22:46 +00:00
bs := balances . Trackers [ sc ]
2020-03-05 07:45:50 +00:00
bs . Balance -= amount
bs . LastUpdatedBlock = b . Index
2020-03-11 15:22:46 +00:00
balances . Trackers [ sc ] = bs
2020-03-05 14:11:58 +00:00
transfer . Amount = - amount
2020-03-12 09:43:21 +00:00
isBig , err := cache . AppendNEP5Transfer ( fromAddr , balances . NextTransferBatch , transfer )
if err != nil {
return
}
if isBig {
balances . NextTransferBatch ++
}
if err := cache . PutNEP5Balances ( fromAddr , balances ) ; err != nil {
2020-03-05 14:11:58 +00:00
return
}
2020-03-05 07:45:50 +00:00
}
2020-03-05 14:11:58 +00:00
if ! toAddr . Equals ( util . Uint160 { } ) {
2020-03-11 15:22:46 +00:00
balances , err := cache . GetNEP5Balances ( toAddr )
2020-03-05 07:45:50 +00:00
if err != nil {
return
}
2020-03-11 15:22:46 +00:00
bs := balances . Trackers [ sc ]
2020-03-05 07:45:50 +00:00
bs . Balance += amount
bs . LastUpdatedBlock = b . Index
2020-03-11 15:22:46 +00:00
balances . Trackers [ sc ] = bs
2020-03-05 14:11:58 +00:00
transfer . Amount = amount
2020-03-12 09:43:21 +00:00
isBig , err := cache . AppendNEP5Transfer ( toAddr , balances . NextTransferBatch , transfer )
if err != nil {
return
}
if isBig {
balances . NextTransferBatch ++
}
if err := cache . PutNEP5Balances ( toAddr , balances ) ; err != nil {
2020-03-05 14:11:58 +00:00
return
}
2020-03-05 07:45:50 +00:00
}
}
2020-03-05 12:16:03 +00:00
// GetNEP5TransferLog returns NEP5 transfer log for the acc.
func ( bc * Blockchain ) GetNEP5TransferLog ( acc util . Uint160 ) * state . NEP5TransferLog {
2020-03-12 09:43:21 +00:00
balances , err := bc . dao . GetNEP5Balances ( acc )
2020-03-05 12:16:03 +00:00
if err != nil {
return nil
}
2020-03-12 09:43:21 +00:00
result := new ( state . NEP5TransferLog )
for i := uint32 ( 0 ) ; i <= balances . NextTransferBatch ; i ++ {
lg , err := bc . dao . GetNEP5TransferLog ( acc , i )
if err != nil {
return nil
}
result . Raw = append ( result . Raw , lg . Raw ... )
}
return result
2020-03-05 12:16:03 +00:00
}
2020-03-11 15:22:46 +00:00
// GetNEP5Balances returns NEP5 balances for the acc.
func ( bc * Blockchain ) GetNEP5Balances ( acc util . Uint160 ) * state . NEP5Balances {
bs , err := bc . dao . GetNEP5Balances ( acc )
if err != nil {
return nil
}
return bs
}
2020-02-06 15:47:03 +00:00
// LastBatch returns last persisted storage batch.
func ( bc * Blockchain ) LastBatch ( ) * storage . MemBatch {
return bc . lastBatch
}
2019-11-18 12:24:48 +00:00
// processOutputs processes transaction outputs.
2020-04-07 09:41:12 +00:00
func processOutputs ( tx * transaction . Transaction , dao * dao . Cached ) 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
}
2020-04-07 09:41:12 +00:00
func processTXWithValidatorsAdd ( output * transaction . Output , account * state . Account , dao * dao . Cached ) error {
2020-02-14 14:44:46 +00:00
if output . AssetID . Equals ( GoverningTokenID ( ) ) && len ( account . Votes ) > 0 {
2020-02-12 18:12:39 +00:00
return modAccountVotes ( account , dao , output . Amount )
}
return nil
}
2020-04-07 09:41:12 +00:00
func processTXWithValidatorsSubtract ( output * transaction . Output , account * state . Account , dao * dao . Cached ) error {
2020-02-14 14:44:46 +00:00
if output . AssetID . Equals ( GoverningTokenID ( ) ) && len ( account . Votes ) > 0 {
2020-02-12 18:12:39 +00:00
return modAccountVotes ( account , dao , - output . Amount )
2019-12-11 10:10:51 +00:00
}
return nil
}
2020-02-12 18:12:39 +00:00
// modAccountVotes adds given value to given account voted validators.
2020-04-07 09:41:12 +00:00
func modAccountVotes ( account * state . Account , dao * dao . Cached , value 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
}
2020-02-12 18:12:39 +00:00
validator . Votes += value
2020-02-12 15:10:23 +00:00
if validator . UnregisteredAndHasNoVotes ( ) {
2019-12-11 10:10:51 +00:00
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
}
}
}
2020-02-12 17:54:48 +00:00
if len ( account . Votes ) > 0 {
vc , err := dao . GetValidatorsCount ( )
if err != nil {
return err
}
2020-02-12 18:12:39 +00:00
vc [ len ( account . Votes ) - 1 ] += value
2020-02-12 17:54:48 +00:00
err = dao . PutValidatorsCount ( vc )
if err != nil {
return err
}
}
2019-11-18 12:24:48 +00:00
return nil
}
2020-04-07 09:41:12 +00:00
func processValidatorStateDescriptor ( descriptor * transaction . StateDescriptor , dao * dao . Cached ) 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" {
2020-02-12 11:56:40 +00:00
if len ( descriptor . Value ) == 1 {
validatorState . Registered = descriptor . Value [ 0 ] != 0
return dao . PutValidatorState ( validatorState )
2019-11-11 15:25:28 +00:00
}
2020-02-12 11:56:40 +00:00
return errors . New ( "bad descriptor value" )
2019-11-11 15:25:28 +00:00
}
return nil
}
2020-04-07 09:41:12 +00:00
func processAccountStateDescriptor ( descriptor * transaction . StateDescriptor , dao * dao . Cached ) 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" {
2020-02-14 14:44:46 +00:00
balance := account . GetBalanceValues ( ) [ GoverningTokenID ( ) ]
2020-02-12 18:12:39 +00:00
if err = modAccountVotes ( account , dao , - balance ) ; err != nil {
2019-12-11 10:10:51 +00:00
return err
2019-11-11 15:25:28 +00:00
}
votes := keys . PublicKeys { }
err := votes . DecodeBytes ( descriptor . Value )
if err != nil {
return err
}
2020-02-12 17:54:48 +00:00
if len ( votes ) > state . MaxValidatorsVoted {
return errors . New ( "voting candidate limit exceeded" )
}
if len ( votes ) > 0 {
account . Votes = votes
for _ , vote := range account . Votes {
validatorState , err := dao . GetValidatorStateOrNew ( vote )
if err != nil {
return err
}
validatorState . Votes += balance
if err = dao . PutValidatorState ( validatorState ) ; err != nil {
return err
}
}
vc , err := dao . GetValidatorsCount ( )
2020-02-12 15:16:57 +00:00
if err != nil {
return err
}
2020-02-12 17:54:48 +00:00
vc [ len ( account . Votes ) - 1 ] += balance
err = dao . PutValidatorsCount ( vc )
if err != nil {
2020-02-12 15:16:57 +00:00
return err
2019-11-11 15:25:28 +00:00
}
2020-02-12 17:54:48 +00:00
} else {
account . Votes = nil
2019-11-11 15:25:28 +00:00
}
2020-02-12 15:14:28 +00:00
return dao . PutAccountState ( account )
2019-10-24 09:29:55 +00:00
}
2018-03-09 15:55:25 +00:00
return nil
}
2020-04-07 09:41:12 +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 ) {
2020-02-18 15:56:41 +00:00
if tx , _ , ok := bc . memPool . TryGetValue ( hash ) ; ok {
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 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
}
2020-02-21 14:56:28 +00:00
// GetAppExecResult returns application execution result by the given
// tx hash.
func ( bc * Blockchain ) GetAppExecResult ( hash util . Uint256 ) ( * state . AppExecResult , error ) {
return bc . dao . GetAppExecResult ( hash )
}
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 ) {
2020-05-27 07:56:47 +00:00
siMap , err := bc . dao . GetStorageItems ( hash , nil )
2020-05-06 11:34:17 +00:00
if err != nil {
return nil , err
}
m := make ( map [ string ] * state . StorageItem )
for i := range siMap {
val := siMap [ i ] . StorageItem
m [ string ( siMap [ i ] . Key ) ] = & val
}
return m , nil
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
}
}
2020-02-27 13:31:28 +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 {
2020-02-10 15:53:22 +00:00
stx , _ , err := bc . dao . GetTransaction ( tx . Hash ( ) )
2019-10-10 17:02:09 +00:00
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
}
}
2020-02-27 13:31:28 +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.
2020-03-09 13:56:37 +00:00
func ( bc * Blockchain ) GetUnspentCoinState ( hash util . Uint256 ) * state . UnspentCoin {
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
}
2020-05-12 14:20:41 +00:00
// SubscribeForBlocks adds given channel to new block event broadcasting, so when
// there is a new block added to the chain you'll receive it via this channel.
// Make sure it's read from regularly as not reading these events might affect
// other Blockchain functions.
func ( bc * Blockchain ) SubscribeForBlocks ( ch chan <- * block . Block ) {
bc . subCh <- ch
}
// SubscribeForTransactions adds given channel to new transaction event
// broadcasting, so when there is a new transaction added to the chain (in a
// block) you'll receive it via this channel. Make sure it's read from regularly
// as not reading these events might affect other Blockchain functions.
func ( bc * Blockchain ) SubscribeForTransactions ( ch chan <- * transaction . Transaction ) {
bc . subCh <- ch
}
// SubscribeForNotifications adds given channel to new notifications event
// broadcasting, so when an in-block transaction execution generates a
// notification you'll receive it via this channel. Only notifications from
// successful transactions are broadcasted, if you're interested in failed
// transactions use SubscribeForExecutions instead. Make sure this channel is
// read from regularly as not reading these events might affect other Blockchain
// functions.
func ( bc * Blockchain ) SubscribeForNotifications ( ch chan <- * state . NotificationEvent ) {
bc . subCh <- ch
}
// SubscribeForExecutions adds given channel to new transaction execution event
// broadcasting, so when an in-block transaction execution happens you'll receive
// the result of it via this channel. Make sure it's read from regularly as not
// reading these events might affect other Blockchain functions.
func ( bc * Blockchain ) SubscribeForExecutions ( ch chan <- * state . AppExecResult ) {
bc . subCh <- ch
}
// UnsubscribeFromBlocks unsubscribes given channel from new block notifications,
// you can close it afterwards. Passing non-subscribed channel is a no-op.
func ( bc * Blockchain ) UnsubscribeFromBlocks ( ch chan <- * block . Block ) {
bc . unsubCh <- ch
}
// UnsubscribeFromTransactions unsubscribes given channel from new transaction
// notifications, you can close it afterwards. Passing non-subscribed channel is
// a no-op.
func ( bc * Blockchain ) UnsubscribeFromTransactions ( ch chan <- * transaction . Transaction ) {
bc . unsubCh <- ch
}
// UnsubscribeFromNotifications unsubscribes given channel from new
// execution-generated notifications, you can close it afterwards. Passing
// non-subscribed channel is a no-op.
func ( bc * Blockchain ) UnsubscribeFromNotifications ( ch chan <- * state . NotificationEvent ) {
bc . unsubCh <- ch
}
// UnsubscribeFromExecutions unsubscribes given channel from new execution
// notifications, you can close it afterwards. Passing non-subscribed channel is
// a no-op.
func ( bc * Blockchain ) UnsubscribeFromExecutions ( ch chan <- * state . AppExecResult ) {
bc . unsubCh <- ch
}
2020-02-25 13:15:17 +00:00
// CalculateClaimable calculates the amount of GAS which can be claimed for a transaction with value.
// First return value is GAS generated between startHeight and endHeight.
// Second return value is GAS returned from accumulated SystemFees between startHeight and endHeight.
func ( bc * Blockchain ) CalculateClaimable ( value util . Fixed8 , startHeight , endHeight uint32 ) ( util . Fixed8 , util . Fixed8 , error ) {
var amount util . Fixed8
di := uint32 ( bc . decrementInterval )
ustart := startHeight / di
if genSize := uint32 ( len ( bc . generationAmount ) ) ; ustart < genSize {
uend := endHeight / di
iend := endHeight % di
if uend >= genSize {
uend = genSize - 1
iend = di
} else if iend == 0 {
uend --
iend = di
}
istart := startHeight % di
for ustart < uend {
amount += util . Fixed8 ( di - istart ) * util . Fixed8 ( bc . generationAmount [ ustart ] )
ustart ++
istart = 0
}
amount += util . Fixed8 ( iend - istart ) * util . Fixed8 ( bc . generationAmount [ ustart ] )
}
if startHeight == 0 {
startHeight ++
}
2020-02-27 13:48:24 +00:00
h := bc . GetHeaderHash ( int ( startHeight - 1 ) )
feeStart := bc . getSystemFeeAmount ( h )
h = bc . GetHeaderHash ( int ( endHeight - 1 ) )
feeEnd := bc . getSystemFeeAmount ( h )
2020-02-25 13:15:17 +00:00
2020-02-27 13:48:24 +00:00
sysFeeTotal := util . Fixed8 ( feeEnd - feeStart )
2020-02-25 13:15:17 +00:00
ratio := value / 100000000
return amount * ratio , sysFeeTotal * ratio , nil
}
2020-02-26 07:58:20 +00:00
// References maps transaction's inputs into a slice of InOuts, effectively
// joining each Input with the corresponding Output.
2019-02-20 17:39:32 +00:00
// @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.
2020-02-26 07:58:20 +00:00
func ( bc * Blockchain ) References ( t * transaction . Transaction ) ( [ ] transaction . InOut , error ) {
2020-02-26 08:10:37 +00:00
return bc . references ( t . Inputs )
}
2019-02-20 17:39:32 +00:00
2020-02-26 08:10:37 +00:00
// references is an internal implementation of References that operates directly
// on a slice of Input.
func ( bc * Blockchain ) references ( ins [ ] transaction . Input ) ( [ ] transaction . InOut , error ) {
references := make ( [ ] transaction . InOut , 0 , len ( ins ) )
2019-02-20 17:39:32 +00:00
2020-02-26 08:10:37 +00:00
for _ , inputs := range transaction . GroupInputsByPrevHash ( ins ) {
2020-02-25 15:32:10 +00:00
prevHash := inputs [ 0 ] . PrevHash
2020-03-09 15:56:24 +00:00
unspent , err := bc . dao . GetUnspentCoinState ( prevHash )
2020-02-13 17:59:03 +00:00
if err != nil {
2020-02-26 07:58:20 +00:00
return nil , errors . New ( "bad input reference" )
2020-02-13 17:59:03 +00:00
}
for _ , in := range inputs {
2020-03-09 15:56:24 +00:00
if int ( in . PrevIndex ) > len ( unspent . States ) - 1 {
2020-02-26 07:58:20 +00:00
return nil , errors . New ( "bad input reference" )
2019-02-20 17:39:32 +00:00
}
2020-03-09 15:56:24 +00:00
references = append ( references , transaction . InOut { In : * in , Out : unspent . States [ in . PrevIndex ] . Output } )
2019-02-20 17:39:32 +00:00
}
}
2020-02-26 07:58:20 +00:00
return references , nil
2019-02-20 17:39:32 +00:00
}
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 {
2020-02-28 08:49:14 +00:00
// https://github.com/neo-project/neo/blob/master-2.x/neo/Network/P2P/Payloads/ClaimTransaction.cs#L16
if t . Type == transaction . ClaimType || t . Type == transaction . MinerType {
return 0
}
2019-08-23 12:41:22 +00:00
inputAmount := util . Fixed8FromInt64 ( 0 )
2020-02-26 07:58:20 +00:00
refs , err := bc . References ( t )
if err != nil {
return inputAmount
}
for i := range refs {
if refs [ i ] . Out . AssetID == UtilityTokenID ( ) {
2020-02-27 08:57:31 +00:00
inputAmount = inputAmount . Add ( refs [ i ] . Out . Amount )
2019-02-20 17:39:32 +00:00
}
}
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 {
2020-02-14 14:44:46 +00:00
if txOutput . AssetID == UtilityTokenID ( ) {
2020-02-27 08:57:31 +00:00
outputAmount = outputAmount . Add ( txOutput . Amount )
2019-02-20 17:39:32 +00:00
}
}
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 {
2020-03-04 14:45:29 +00:00
if t . Type == transaction . InvocationType {
inv := t . Data . ( * transaction . InvocationTX )
if inv . Version >= 1 {
return inv . Gas
}
}
2019-02-20 17:39:32 +00:00
return bc . GetConfig ( ) . SystemFee . TryGetValue ( t . Type )
}
2020-02-18 15:42:11 +00:00
// IsLowPriority checks given fee for being less than configured
2019-10-22 14:56:03 +00:00
// LowPriorityThreshold.
2020-02-18 15:42:11 +00:00
func ( bc * Blockchain ) IsLowPriority ( fee util . Fixed8 ) bool {
return fee < 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
}
2020-02-18 17:16:38 +00:00
// ApplyPolicyToTxSet applies configured policies to given transaction set. It
// expects slice to be ordered by fee and returns a subslice of it.
func ( bc * Blockchain ) ApplyPolicyToTxSet ( txes [ ] mempool . TxWithFee ) [ ] mempool . TxWithFee {
if bc . config . MaxTransactionsPerBlock != 0 && len ( txes ) > bc . config . MaxTransactionsPerBlock {
txes = txes [ : bc . config . MaxTransactionsPerBlock ]
}
maxFree := bc . config . MaxFreeTransactionsPerBlock
if maxFree != 0 {
lowStart := sort . Search ( len ( txes ) , func ( i int ) bool {
return bc . IsLowPriority ( txes [ i ] . Fee )
} )
if lowStart + maxFree < len ( txes ) {
txes = txes [ : lowStart + maxFree ]
}
}
return txes
}
2020-02-29 14:52:09 +00:00
func ( bc * Blockchain ) verifyHeader ( currHeader , prevHeader * block . Header ) error {
if prevHeader . Hash ( ) != currHeader . PrevHash {
return errors . New ( "previous header hash doesn't match" )
2019-10-15 09:52:10 +00:00
}
2020-02-29 14:52:09 +00:00
if prevHeader . Index + 1 != currHeader . Index {
2019-10-15 09:52:10 +00:00
return errors . New ( "previous header index doesn't match" )
}
2020-02-29 14:52:09 +00:00
if prevHeader . Timestamp >= currHeader . Timestamp {
2019-10-15 09:52:10 +00:00
return errors . New ( "block is not newer than the previous one" )
}
2020-02-29 14:52:09 +00:00
return bc . verifyHeaderWitnesses ( currHeader , prevHeader )
2019-10-15 09:52:10 +00:00
}
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
}
2020-02-26 09:30:56 +00:00
if transaction . HaveDuplicateInputs ( t . Inputs ) {
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'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
}
2020-03-06 17:15:01 +00:00
refs , err := bc . References ( t )
if err != nil {
return err
}
results := refsAndOutsToResults ( refs , t . Outputs )
if err := bc . verifyResults ( t , results ) ; err != nil {
2019-10-11 08:42:36 +00:00
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 )
}
}
2020-03-04 10:27:22 +00:00
switch t . Type {
case transaction . ClaimType :
2020-02-26 09:30:56 +00:00
claim := t . Data . ( * transaction . ClaimTX )
if transaction . HaveDuplicateInputs ( claim . Claims ) {
return errors . New ( "duplicate claims" )
}
2020-02-26 09:48:38 +00:00
if bc . dao . IsDoubleClaim ( claim ) {
return errors . New ( "double claim" )
}
2020-03-06 17:15:01 +00:00
if err := bc . verifyClaims ( t , results ) ; err != nil {
2020-02-27 12:45:52 +00:00
return err
}
2020-03-04 10:27:22 +00:00
case transaction . InvocationType :
inv := t . Data . ( * transaction . InvocationTX )
if inv . Gas . FractionalValue ( ) != 0 {
return errors . New ( "invocation gas can only be integer" )
}
2020-03-16 17:14:59 +00:00
case transaction . StateType :
stx := t . Data . ( * transaction . StateTX )
for _ , desc := range stx . Descriptors {
switch desc . Type {
case transaction . Account :
if desc . Field != "Votes" {
return errors . New ( "bad field in account descriptor" )
}
votes := keys . PublicKeys { }
err := votes . DecodeBytes ( desc . Value )
if err != nil {
return err
}
if len ( votes ) > state . MaxValidatorsVoted {
return errors . New ( "voting candidate limit exceeded" )
}
hash , err := util . Uint160DecodeBytesBE ( desc . Key )
if err != nil {
return err
}
account , err := bc . dao . GetAccountStateOrNew ( hash )
if err != nil {
return err
}
if account . IsFrozen {
return errors . New ( "account is frozen" )
}
if votes . Len ( ) > 0 {
balance := account . GetBalanceValues ( ) [ GoverningTokenID ( ) ]
if balance == 0 {
return errors . New ( "no governing tokens available to vote" )
}
validators , err := bc . GetEnrollments ( )
if err != nil {
return err
}
for _ , k := range votes {
var isRegistered bool
for i := range validators {
if k . Equal ( validators [ i ] . PublicKey ) {
isRegistered = true
break
}
}
if ! isRegistered {
return errors . New ( "vote for unregistered validator" )
}
}
}
case transaction . Validator :
if desc . Field != "Registered" {
return errors . New ( "bad field in validator descriptor" )
}
default :
return errors . New ( "bad descriptor type" )
}
}
2020-02-26 09:30:56 +00:00
}
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-03-06 17:15:01 +00:00
func ( bc * Blockchain ) verifyClaims ( tx * transaction . Transaction , results [ ] * transaction . Result ) ( err error ) {
2020-02-27 12:45:52 +00:00
t := tx . Data . ( * transaction . ClaimTX )
var result * transaction . Result
for i := range results {
if results [ i ] . AssetID == UtilityTokenID ( ) {
result = results [ i ]
break
}
}
if result == nil || result . Amount . GreaterThan ( 0 ) {
return errors . New ( "invalid output in claim tx" )
}
bonus , err := bc . calculateBonus ( t . Claims )
if err == nil && bonus != - result . Amount {
return fmt . Errorf ( "wrong bonus calculated in claim tx: %s != %s" ,
bonus . String ( ) , ( - result . Amount ) . String ( ) )
}
return err
}
func ( bc * Blockchain ) calculateBonus ( claims [ ] transaction . Input ) ( util . Fixed8 , error ) {
unclaimed := [ ] * spentCoin { }
inputs := transaction . GroupInputsByPrevHash ( claims )
for _ , group := range inputs {
h := group [ 0 ] . PrevHash
2020-03-09 15:56:24 +00:00
unspent , err := bc . dao . GetUnspentCoinState ( h )
if err != nil {
return 0 , err
2020-02-27 12:45:52 +00:00
}
for _ , c := range group {
2020-03-09 15:56:24 +00:00
if len ( unspent . States ) <= int ( c . PrevIndex ) {
2020-02-27 12:45:52 +00:00
return 0 , fmt . Errorf ( "can't find spent coins for %s (%d)" , c . PrevHash . StringLE ( ) , c . PrevIndex )
}
2020-03-09 15:56:24 +00:00
if unspent . States [ c . PrevIndex ] . State & state . CoinSpent == 0 {
return 0 , fmt . Errorf ( "not spent yet: %s/%d" , c . PrevHash . StringLE ( ) , c . PrevIndex )
}
if unspent . States [ c . PrevIndex ] . State & state . CoinClaimed != 0 {
return 0 , fmt . Errorf ( "already claimed: %s/%d" , c . PrevHash . StringLE ( ) , c . PrevIndex )
}
unclaimed = append ( unclaimed , & spentCoin {
Output : & unspent . States [ c . PrevIndex ] . Output ,
StartHeight : unspent . Height ,
EndHeight : unspent . States [ c . PrevIndex ] . SpendHeight ,
} )
2020-02-27 12:45:52 +00:00
}
}
return bc . calculateBonusInternal ( unclaimed )
}
func ( bc * Blockchain ) calculateBonusInternal ( scs [ ] * spentCoin ) ( util . Fixed8 , error ) {
var claimed util . Fixed8
for _ , sc := range scs {
gen , sys , err := bc . CalculateClaimable ( sc . Output . Amount , sc . StartHeight , sc . EndHeight )
if err != nil {
return 0 , err
}
claimed += gen + sys
}
return claimed , nil
}
2020-02-05 21:23:49 +00:00
// isTxStillRelevant is a callback for mempool transaction filtering after the
// new block addition. It returns false for transactions already present in the
// chain (added by the new block), transactions using some inputs that are
// already used (double spends) and does witness reverification for non-standard
// contracts. It operates under the assumption that full transaction verification
// was already done so we don't need to check basic things like size, input/output
// correctness, etc.
func ( bc * Blockchain ) isTxStillRelevant ( t * transaction . Transaction ) bool {
var recheckWitness bool
if bc . dao . HasTransaction ( t . Hash ( ) ) {
return false
}
if bc . dao . IsDoubleSpend ( t ) {
return false
}
2020-02-26 09:48:38 +00:00
if t . Type == transaction . ClaimType {
claim := t . Data . ( * transaction . ClaimTX )
if bc . dao . IsDoubleClaim ( claim ) {
return false
}
}
2020-02-05 21:23:49 +00:00
for i := range t . Scripts {
if ! vm . IsStandardContract ( t . Scripts [ i ] . VerificationScript ) {
recheckWitness = true
break
}
}
if recheckWitness {
return bc . verifyTxWitnesses ( t , nil ) == nil
}
return true
}
2020-05-29 14:20:00 +00:00
// AddStateRoot add new (possibly unverified) state root to the blockchain.
func ( bc * Blockchain ) AddStateRoot ( r * state . MPTRoot ) error {
our , err := bc . GetStateRoot ( r . Index )
if err == nil {
if our . Flag == state . Verified {
return nil
} else if r . Witness == nil && our . Witness != nil {
r . Witness = our . Witness
}
}
if err := bc . verifyStateRoot ( r ) ; err != nil {
return errors . WithMessage ( err , "invalid state root" )
}
if r . Index > bc . BlockHeight ( ) { // just put it into the store for future checks
return bc . dao . PutStateRoot ( & state . MPTRootState {
MPTRoot : * r ,
Flag : state . Unverified ,
} )
}
flag := state . Unverified
if r . Witness != nil {
if err := bc . verifyStateRootWitness ( r ) ; err != nil {
return errors . WithMessage ( err , "can't verify signature" )
}
flag = state . Verified
}
return bc . dao . PutStateRoot ( & state . MPTRootState {
MPTRoot : * r ,
Flag : flag ,
} )
}
// verifyStateRoot checks if state root is valid.
func ( bc * Blockchain ) verifyStateRoot ( r * state . MPTRoot ) error {
if r . Index == 0 {
return nil
}
prev , err := bc . GetStateRoot ( r . Index - 1 )
if err != nil {
return errors . New ( "can't get previous state root" )
2020-06-04 14:19:30 +00:00
} else if ! r . PrevHash . Equals ( hash . DoubleSha256 ( prev . GetSignedPart ( ) ) ) {
2020-05-29 14:20:00 +00:00
return errors . New ( "previous hash mismatch" )
} else if prev . Version != r . Version {
return errors . New ( "version mismatch" )
}
return nil
}
// verifyStateRootWitness verifies that state root signature is correct.
func ( bc * Blockchain ) verifyStateRootWitness ( r * state . MPTRoot ) error {
b , err := bc . GetBlock ( bc . GetHeaderHash ( int ( r . Index ) ) )
if err != nil {
return err
}
interopCtx := bc . newInteropContext ( trigger . Verification , bc . dao , nil , nil )
return bc . verifyHashAgainstScript ( b . NextConsensus , r . Witness , hash . Sha256 ( r . GetSignedPart ( ) ) , interopCtx , true )
}
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-18 17:16:38 +00:00
// Policying.
if t . Type != transaction . ClaimType {
txSize := io . GetVarSize ( t )
maxFree := bc . config . MaxFreeTransactionSize
if maxFree != 0 && txSize > maxFree {
netFee := bc . NetworkFee ( t )
if bc . IsLowPriority ( netFee ) ||
netFee < util . Fixed8FromFloat ( bc . config . FeePerExtraByte ) * util . Fixed8 ( txSize - maxFree ) {
return ErrPolicy
}
}
}
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
}
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
}
2020-03-06 17:15:01 +00:00
func ( bc * Blockchain ) verifyResults ( t * transaction . Transaction , results [ ] * transaction . Result ) 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
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
}
2020-02-14 14:44:46 +00:00
if len ( resultsDestroy ) == 1 && resultsDestroy [ 0 ] . AssetID != UtilityTokenID ( ) {
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 {
2020-02-14 14:44:46 +00:00
if r . AssetID != UtilityTokenID ( ) {
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 {
2020-02-14 14:44:46 +00:00
if r . AssetID == UtilityTokenID ( ) {
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
}
2020-03-16 15:43:02 +00:00
asset , err := bc . dao . GetAssetState ( r . AssetID )
if asset == nil || err != nil {
return errors . New ( "invalid asset in issue tx" )
}
if asset . Available < r . Amount {
return errors . New ( "trying to issue more than available" )
}
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 {
2020-02-26 07:58:20 +00:00
references , err := bc . References ( t )
if 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 nil
2019-09-03 15:03:13 +00:00
}
2020-03-06 17:15:01 +00:00
return refsAndOutsToResults ( references , t . Outputs )
}
// mapReferencesToResults returns cumulative results of transaction based in its
// references and outputs.
func refsAndOutsToResults ( references [ ] transaction . InOut , outputs [ ] transaction . Output ) [ ] * transaction . Result {
var results [ ] * transaction . Result
tempResult := make ( map [ util . Uint256 ] util . Fixed8 )
2020-02-26 07:58:20 +00:00
for _ , inout := range references {
2020-03-06 16:26:39 +00:00
c := tempResult [ inout . Out . AssetID ]
tempResult [ inout . Out . AssetID ] = c . Add ( inout . Out . Amount )
2019-09-03 15:03:13 +00:00
}
2020-03-06 17:15:01 +00:00
for _ , output := range outputs {
2020-03-06 16:26:39 +00:00
c := tempResult [ output . AssetID ]
tempResult [ output . AssetID ] = c . Sub ( output . Amount )
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.)
2020-03-06 16:26:39 +00:00
for assetID , amount := range tempResult {
2019-09-03 15:03:13 +00:00
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-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 ) {
2020-04-07 09:41:12 +00:00
cache := dao . NewCached ( bc . dao )
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 {
2020-02-28 08:08:46 +00:00
accountState , err := cache . GetAccountStateOrNew ( output . ScriptHash )
2019-11-25 17:39:11 +00:00
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 {
2020-03-09 15:56:24 +00:00
unspent , err := cache . GetUnspentCoinState ( 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 {
2020-03-09 15:56:24 +00:00
prevOutput := & unspent . States [ input . PrevIndex ] . Output
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.
2020-03-09 15:56:24 +00:00
if err = processTXWithValidatorsSubtract ( prevOutput , accountState , cache ) ; err != nil {
2019-12-11 10:10:51 +00:00
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 ( )
2020-02-12 15:22:31 +00:00
sort . Slice ( validators , func ( i , j int ) bool {
// Unregistered validators go to the end of the list.
if validators [ i ] . Registered != validators [ j ] . Registered {
return validators [ i ] . Registered
}
// The most-voted validators should end up in the front of the list.
if validators [ i ] . Votes != validators [ j ] . Votes {
return validators [ i ] . Votes > validators [ j ] . Votes
}
// Ties are broken with public keys.
return validators [ i ] . PublicKey . Cmp ( validators [ j ] . PublicKey ) == - 1
} )
2019-11-18 14:59:43 +00:00
2020-02-12 17:54:48 +00:00
validatorsCount , err := cache . GetValidatorsCount ( )
if err != nil {
return nil , err
}
count := validatorsCount . GetWeightedAverage ( )
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 ( )
2020-02-14 12:51:51 +00:00
result := keys . PublicKeys { }
2019-11-11 15:25:28 +00:00
for _ , validator := range validators {
if validator . RegisteredAndHasVotes ( ) || uniqueSBValidators . Contains ( validator . PublicKey ) {
2020-02-14 12:51:51 +00:00
result = append ( result , validator . PublicKey )
2019-11-11 15:25:28 +00:00
}
}
2020-02-14 12:51:51 +00:00
if result . Len ( ) >= count {
result = result [ : count ]
} else {
for i := 0 ; i < uniqueSBValidators . Len ( ) && result . Len ( ) < count ; i ++ {
if ! result . Contains ( uniqueSBValidators [ i ] ) {
result = append ( result , uniqueSBValidators [ i ] )
}
2020-02-12 17:29:10 +00:00
}
2019-11-11 15:25:28 +00:00
}
2020-02-13 13:53:25 +00:00
sort . Sort ( result )
2019-11-11 15:25:28 +00:00
return result , nil
}
2020-03-05 14:48:30 +00:00
// GetEnrollments returns all registered validators and non-registered SB validators
func ( bc * Blockchain ) GetEnrollments ( ) ( [ ] * state . Validator , error ) {
validators := bc . dao . GetValidators ( )
standByValidators , err := bc . GetStandByValidators ( )
if err != nil {
return nil , err
}
uniqueSBValidators := standByValidators . Unique ( )
var result [ ] * state . Validator
for _ , validator := range validators {
if validator . Registered {
result = append ( result , validator )
}
}
for _ , sBValidator := range uniqueSBValidators {
isAdded := false
for _ , v := range result {
if v . PublicKey == sBValidator {
isAdded = true
break
}
}
if ! isAdded {
result = append ( result , & state . Validator {
PublicKey : sBValidator ,
Registered : false ,
Votes : 0 ,
} )
}
}
return result , nil
}
2020-04-07 09:41:12 +00:00
func processStateTX ( dao * dao . Cached , 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
}
2020-04-07 09:41:12 +00:00
func processEnrollmentTX ( dao * dao . Cached , 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 ) {
2020-02-26 07:58:20 +00:00
references , err := bc . References ( t )
if err != nil {
return nil , 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
}
hashes := make ( map [ util . Uint160 ] bool )
2020-02-26 07:58:20 +00:00
for i := range references {
hashes [ references [ i ] . Out . ScriptHash ] = true
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 . 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
}
}
}
}
2020-02-26 08:10:37 +00:00
switch t . Type {
case transaction . ClaimType :
claim := t . Data . ( * transaction . ClaimTX )
refs , err := bc . references ( claim . Claims )
if err != nil {
return nil , err
}
for i := range refs {
hashes [ refs [ i ] . Out . ScriptHash ] = true
}
case transaction . EnrollmentType :
2020-02-21 17:04:16 +00:00
etx := t . Data . ( * transaction . EnrollmentTX )
hashes [ etx . PublicKey . GetScriptHash ( ) ] = true
2020-03-12 15:06:26 +00:00
case transaction . IssueType :
for _ , res := range refsAndOutsToResults ( references , t . Outputs ) {
if res . Amount < 0 {
asset , err := bc . dao . GetAssetState ( res . AssetID )
if asset == nil || err != nil {
return nil , errors . New ( "invalid asset in issue tx" )
}
hashes [ asset . Issuer ] = true
}
}
2020-03-16 16:17:44 +00:00
case transaction . RegisterType :
reg := t . Data . ( * transaction . RegisterTX )
hashes [ reg . Owner . GetScriptHash ( ) ] = true
2020-03-16 16:52:28 +00:00
case transaction . StateType :
stx := t . Data . ( * transaction . StateTX )
for _ , desc := range stx . Descriptors {
switch desc . Type {
case transaction . Account :
if desc . Field != "Votes" {
return nil , errors . New ( "bad account state descriptor" )
}
hash , err := util . Uint160DecodeBytesBE ( desc . Key )
if err != nil {
return nil , err
}
hashes [ hash ] = true
case transaction . Validator :
if desc . Field != "Registered" {
return nil , errors . New ( "bad validator state descriptor" )
}
key := & keys . PublicKey { }
err := key . DecodeBytes ( desc . Key )
if err != nil {
return nil , err
}
hashes [ key . GetScriptHash ( ) ] = true
}
}
2020-02-21 17:04:16 +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
// 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 15:31:39 +00:00
// GetTestVM returns a VM and a Store setup for a test run of some sort of code.
2020-04-03 06:49:01 +00:00
func ( bc * Blockchain ) GetTestVM ( ) * vm . VM {
systemInterop := bc . newInteropContext ( trigger . Application , bc . dao , nil , nil )
2020-04-07 09:54:43 +00:00
vm := systemInterop . SpawnVM ( )
2020-01-21 12:37:47 +00:00
vm . SetPriceGetter ( getPrice )
2020-04-03 06:49:01 +00:00
return vm
2019-10-29 15:31:39 +00:00
}
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 {
2020-02-03 14:46:51 +00:00
bb := io . NewBufBinWriter ( )
emit . AppCall ( bb . BinWriter , hash , false )
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
}
2020-04-07 09:54:43 +00:00
vm := interopCtx . SpawnVM ( )
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 )
core: protect (*Blockchain).keyCache with a lock
Avoid failures like this:
fatal error: concurrent map writes
goroutine 103 [running]:
runtime.throw(0xca6fe3, 0x15)
/usr/lib64/go/1.12/src/runtime/panic.go:617 +0x72 fp=0xc000687988 sp=0xc000687958 pc=0x42d8d2
runtime.mapassign(0xb9d4a0, 0xc0000b1f80, 0xc000687a6c, 0x13bd940)
/usr/lib64/go/1.12/src/runtime/map.go:590 +0x5e3 fp=0xc000687a10 sp=0xc000687988 pc=0x40e2a3
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHashAgainstScript(0xc0000f8000, 0x1300d1f5a3d348be, 0x78607089e4fe9fab, 0xc0a21e4f71, 0xc000d16070, 0x1e2b8881f8178e92, 0xd589cfa965287bb8, 0x24a4e4f292ebc797, 0xb90d3120d878e619, 0xc0001d01e0, ...)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1866 +0x371 fp=0xc000687ad8 sp=0xc000687a10 pc=0x984ed1
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHeaderWitnesses(0xc0000f8000, 0xc000d16000, 0xc00042d950, 0x1, 0xc00008a6c0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1914 +0x209 fp=0xc000687c90 sp=0xc000687ad8 pc=0x985999
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHeader(0xc0000f8000, 0xc000d16000, 0xc00042d950, 0xf0ee0049d611101f, 0xf8967398a8f9351b)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1254 +0x235 fp=0xc000687d70 sp=0xc000687c90 pc=0x97e4e5
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000f8000, 0x1, 0xc000d12000, 0x7d0, 0x7d0, 0x0, 0x1)
/home/rik/dev/neo-go/pkg/core/blockchain.go:369 +0x266 fp=0xc000687e68 sp=0xc000687d70 pc=0x973f46
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddHeaders(0xc0000f8000, 0xc000d12000, 0x7d0, 0x7d0, 0x0, 0xc0003640c0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:338 +0x51 fp=0xc000687eb0 sp=0xc000687e68 pc=0x973cb1
github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleHeadersCmd(0xc00022c140, 0xdd0ca0, 0xc000374000, 0xc00000c020)
/home/rik/dev/neo-go/pkg/network/server.go:431 +0x74 fp=0xc000687fc0 sp=0xc000687eb0 pc=0x9ce5e4
runtime.goexit()
/usr/lib64/go/1.12/src/runtime/asm_amd64.s:1337 +0x1 fp=0xc000687fc8 sp=0xc000687fc0 pc=0x45ca51
created by github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage
/home/rik/dev/neo-go/pkg/network/server.go:705 +0xa4a
...
2020-03-04 17:26:18 +00:00
if useKeys {
bc . keyCacheLock . RLock ( )
if bc . keyCache [ hash ] != nil {
vm . SetPublicKeys ( bc . keyCache [ hash ] )
}
bc . keyCacheLock . RUnlock ( )
2019-12-10 16:13:29 +00:00
}
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" )
}
core: protect (*Blockchain).keyCache with a lock
Avoid failures like this:
fatal error: concurrent map writes
goroutine 103 [running]:
runtime.throw(0xca6fe3, 0x15)
/usr/lib64/go/1.12/src/runtime/panic.go:617 +0x72 fp=0xc000687988 sp=0xc000687958 pc=0x42d8d2
runtime.mapassign(0xb9d4a0, 0xc0000b1f80, 0xc000687a6c, 0x13bd940)
/usr/lib64/go/1.12/src/runtime/map.go:590 +0x5e3 fp=0xc000687a10 sp=0xc000687988 pc=0x40e2a3
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHashAgainstScript(0xc0000f8000, 0x1300d1f5a3d348be, 0x78607089e4fe9fab, 0xc0a21e4f71, 0xc000d16070, 0x1e2b8881f8178e92, 0xd589cfa965287bb8, 0x24a4e4f292ebc797, 0xb90d3120d878e619, 0xc0001d01e0, ...)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1866 +0x371 fp=0xc000687ad8 sp=0xc000687a10 pc=0x984ed1
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHeaderWitnesses(0xc0000f8000, 0xc000d16000, 0xc00042d950, 0x1, 0xc00008a6c0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1914 +0x209 fp=0xc000687c90 sp=0xc000687ad8 pc=0x985999
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).verifyHeader(0xc0000f8000, 0xc000d16000, 0xc00042d950, 0xf0ee0049d611101f, 0xf8967398a8f9351b)
/home/rik/dev/neo-go/pkg/core/blockchain.go:1254 +0x235 fp=0xc000687d70 sp=0xc000687c90 pc=0x97e4e5
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000f8000, 0x1, 0xc000d12000, 0x7d0, 0x7d0, 0x0, 0x1)
/home/rik/dev/neo-go/pkg/core/blockchain.go:369 +0x266 fp=0xc000687e68 sp=0xc000687d70 pc=0x973f46
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddHeaders(0xc0000f8000, 0xc000d12000, 0x7d0, 0x7d0, 0x0, 0xc0003640c0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:338 +0x51 fp=0xc000687eb0 sp=0xc000687e68 pc=0x973cb1
github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleHeadersCmd(0xc00022c140, 0xdd0ca0, 0xc000374000, 0xc00000c020)
/home/rik/dev/neo-go/pkg/network/server.go:431 +0x74 fp=0xc000687fc0 sp=0xc000687eb0 pc=0x9ce5e4
runtime.goexit()
/usr/lib64/go/1.12/src/runtime/asm_amd64.s:1337 +0x1 fp=0xc000687fc8 sp=0xc000687fc0 pc=0x45ca51
created by github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage
/home/rik/dev/neo-go/pkg/network/server.go:705 +0xa4a
...
2020-03-04 17:26:18 +00:00
if useKeys {
bc . keyCacheLock . RLock ( )
_ , ok := bc . keyCache [ hash ]
bc . keyCacheLock . RUnlock ( )
if ! ok {
bc . keyCacheLock . Lock ( )
bc . keyCache [ hash ] = vm . GetPublicKeys ( )
bc . keyCacheLock . Unlock ( )
}
2019-12-10 16:13:29 +00:00
}
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 ( ) ) } )
2020-04-03 06:49:01 +00:00
interopCtx := bc . newInteropContext ( trigger . Verification , bc . dao , 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
}
2020-02-29 14:52:09 +00:00
// verifyHeaderWitnesses is a block-specific implementation of VerifyWitnesses logic.
func ( bc * Blockchain ) verifyHeaderWitnesses ( currHeader , prevHeader * block . Header ) error {
2019-10-15 09:52:10 +00:00
var hash util . Uint160
2020-02-29 14:52:09 +00:00
if prevHeader == nil && currHeader . PrevHash . Equals ( util . Uint256 { } ) {
hash = currHeader . Script . ScriptHash ( )
2019-10-15 09:52:10 +00:00
} else {
hash = prevHeader . NextConsensus
}
2020-04-03 06:49:01 +00:00
interopCtx := bc . newInteropContext ( trigger . Verification , bc . dao , nil , nil )
2020-02-29 14:52:09 +00:00
return bc . verifyHashAgainstScript ( hash , & currHeader . Script , currHeader . 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-04-07 09:41:12 +00:00
func ( bc * Blockchain ) newInteropContext ( trigger trigger . Type , d dao . DAO , block * block . Block , tx * transaction . Transaction ) * interopContext {
2020-04-03 06:49:01 +00:00
return newInteropContext ( trigger , bc , d , block , tx , bc . log )
2019-12-30 11:01:49 +00:00
}