2018-03-09 15:55:25 +00:00
|
|
|
package core
|
|
|
|
|
2018-03-17 11:53:21 +00:00
|
|
|
import (
|
2020-08-03 14:07:24 +00:00
|
|
|
"errors"
|
2018-03-25 10:45:54 +00:00
|
|
|
"time"
|
2018-03-17 11:53:21 +00:00
|
|
|
|
2020-03-25 15:30:21 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
2020-06-18 09:00:51 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
2020-07-13 15:04:50 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
|
2020-08-14 10:50:52 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-04-20 17:38:47 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-05-08 17:54:24 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
2020-04-20 17:38:47 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
2018-03-17 11:53:21 +00:00
|
|
|
)
|
2018-03-09 15:55:25 +00:00
|
|
|
|
2020-02-14 14:44:46 +00:00
|
|
|
var (
|
|
|
|
// governingTokenTX represents transaction that is used to create
|
|
|
|
// governing (NEO) token. It's a part of the genesis block.
|
|
|
|
governingTokenTX transaction.Transaction
|
|
|
|
|
|
|
|
// utilityTokenTX represents transaction that is used to create
|
|
|
|
// utility (GAS) token. It's a part of the genesis block. It's mostly
|
|
|
|
// useful for its hash that represents GAS asset ID.
|
|
|
|
utilityTokenTX transaction.Transaction
|
|
|
|
)
|
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// createGenesisBlock creates a genesis block based on the given configuration.
|
2020-01-14 12:32:07 +00:00
|
|
|
func createGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error) {
|
2020-06-23 15:15:55 +00:00
|
|
|
validators, err := validatorsFromConfig(cfg)
|
2018-03-25 10:45:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nextConsensus, err := getNextConsensusAddress(validators)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-01-15 08:29:50 +00:00
|
|
|
base := block.Base{
|
2018-03-25 10:45:54 +00:00
|
|
|
Version: 0,
|
|
|
|
PrevHash: util.Uint256{},
|
2020-06-05 10:05:50 +00:00
|
|
|
Timestamp: uint64(time.Date(2016, 7, 15, 15, 8, 21, 0, time.UTC).Unix()) * 1000, // Milliseconds.
|
2018-03-25 10:45:54 +00:00
|
|
|
Index: 0,
|
|
|
|
NextConsensus: nextConsensus,
|
2019-12-09 14:14:10 +00:00
|
|
|
Script: transaction.Witness{
|
2018-03-25 10:45:54 +00:00
|
|
|
InvocationScript: []byte{},
|
2020-06-05 10:04:20 +00:00
|
|
|
VerificationScript: []byte{byte(opcode.PUSH1)},
|
2018-03-25 10:45:54 +00:00
|
|
|
},
|
2020-06-18 09:00:51 +00:00
|
|
|
Network: cfg.Magic,
|
2018-03-25 10:45:54 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 12:32:07 +00:00
|
|
|
b := &block.Block{
|
2020-01-15 08:29:50 +00:00
|
|
|
Base: base,
|
2018-03-25 10:45:54 +00:00
|
|
|
Transactions: []*transaction.Transaction{
|
2020-06-18 09:00:51 +00:00
|
|
|
deployNativeContracts(cfg.Magic),
|
2018-03-25 10:45:54 +00:00
|
|
|
},
|
2020-04-22 05:57:55 +00:00
|
|
|
ConsensusData: block.ConsensusData{
|
|
|
|
PrimaryIndex: 0,
|
|
|
|
Nonce: 2083236893,
|
|
|
|
},
|
2018-03-25 10:45:54 +00:00
|
|
|
}
|
2020-09-15 15:38:15 +00:00
|
|
|
b.RebuildMerkleRoot()
|
2018-03-25 10:45:54 +00:00
|
|
|
|
2020-01-14 12:32:07 +00:00
|
|
|
return b, nil
|
2018-03-25 10:45:54 +00:00
|
|
|
}
|
|
|
|
|
2020-06-18 09:00:51 +00:00
|
|
|
func deployNativeContracts(magic netmode.Magic) *transaction.Transaction {
|
2020-04-20 17:38:47 +00:00
|
|
|
buf := io.NewBufBinWriter()
|
2020-08-14 10:50:52 +00:00
|
|
|
emit.Syscall(buf.BinWriter, interopnames.NeoNativeDeploy)
|
2020-04-20 17:38:47 +00:00
|
|
|
script := buf.Bytes()
|
2020-06-18 09:00:51 +00:00
|
|
|
tx := transaction.New(magic, script, 0)
|
2020-04-20 17:38:47 +00:00
|
|
|
tx.Nonce = 0
|
2020-07-29 16:57:38 +00:00
|
|
|
tx.Signers = []transaction.Signer{
|
|
|
|
{
|
|
|
|
Account: hash.Hash160([]byte{byte(opcode.PUSH1)}),
|
2020-10-01 12:26:51 +00:00
|
|
|
Scopes: transaction.None,
|
2020-07-29 16:57:38 +00:00
|
|
|
},
|
|
|
|
}
|
2020-04-20 17:38:47 +00:00
|
|
|
tx.Scripts = []transaction.Witness{
|
|
|
|
{
|
|
|
|
InvocationScript: []byte{},
|
|
|
|
VerificationScript: []byte{byte(opcode.PUSH1)},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return tx
|
|
|
|
}
|
|
|
|
|
2020-06-23 15:15:55 +00:00
|
|
|
func validatorsFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
|
2020-08-05 08:30:14 +00:00
|
|
|
vs, err := committeeFromConfig(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return vs[:cfg.ValidatorsCount], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func committeeFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
|
2020-08-03 14:07:24 +00:00
|
|
|
if len(cfg.StandbyCommittee) < cfg.ValidatorsCount {
|
|
|
|
return nil, errors.New("validators count can be less than the size of StandbyCommittee")
|
|
|
|
}
|
2020-08-05 08:30:14 +00:00
|
|
|
validators := make([]*keys.PublicKey, len(cfg.StandbyCommittee))
|
2020-08-03 14:07:24 +00:00
|
|
|
for i := range validators {
|
|
|
|
pubKey, err := keys.NewPublicKeyFromString(cfg.StandbyCommittee[i])
|
2018-03-25 10:45:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
validators[i] = pubKey
|
|
|
|
}
|
|
|
|
return validators, nil
|
2018-03-10 12:04:06 +00:00
|
|
|
}
|
|
|
|
|
2019-08-27 13:29:42 +00:00
|
|
|
func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, err error) {
|
2020-08-10 15:58:11 +00:00
|
|
|
raw, err := smartcontract.CreateDefaultMultiSigRedeemScript(validators)
|
2018-03-25 10:45:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return val, err
|
|
|
|
}
|
2019-08-23 15:50:45 +00:00
|
|
|
return hash.Hash160(raw), nil
|
2018-03-25 10:45:54 +00:00
|
|
|
}
|
|
|
|
|
2018-03-17 11:53:21 +00:00
|
|
|
// headerSliceReverse reverses the given slice of *Header.
|
2020-01-14 12:32:07 +00:00
|
|
|
func headerSliceReverse(dest []*block.Header) {
|
2018-03-17 11:53:21 +00:00
|
|
|
for i, j := 0, len(dest)-1; i < j; i, j = i+1, j-1 {
|
|
|
|
dest[i], dest[j] = dest[j], dest[i]
|
|
|
|
}
|
|
|
|
}
|
2020-05-08 17:54:24 +00:00
|
|
|
|
|
|
|
// CalculateNetworkFee returns network fee for transaction
|
2020-06-23 14:15:35 +00:00
|
|
|
func CalculateNetworkFee(script []byte) (int64, int) {
|
2020-05-08 17:54:24 +00:00
|
|
|
var (
|
2020-06-23 14:15:35 +00:00
|
|
|
netFee int64
|
2020-05-08 17:54:24 +00:00
|
|
|
size int
|
|
|
|
)
|
|
|
|
if vm.IsSignatureContract(script) {
|
|
|
|
size += 67 + io.GetVarSize(script)
|
2020-09-30 10:20:40 +00:00
|
|
|
netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + crypto.ECDSAVerifyPrice
|
2020-07-13 15:05:46 +00:00
|
|
|
} else if m, pubs, ok := vm.ParseMultiSigContract(script); ok {
|
|
|
|
n := len(pubs)
|
2020-05-08 17:54:24 +00:00
|
|
|
sizeInv := 66 * m
|
|
|
|
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
|
2020-06-23 14:15:35 +00:00
|
|
|
netFee += calculateMultisigFee(m) + calculateMultisigFee(n)
|
2020-07-13 15:04:50 +00:00
|
|
|
netFee += opcodePrice(opcode.PUSHNULL) + crypto.ECDSAVerifyPrice*int64(n)
|
2020-05-08 17:54:24 +00:00
|
|
|
} else {
|
|
|
|
// We can support more contract types in the future.
|
|
|
|
}
|
|
|
|
return netFee, size
|
|
|
|
}
|
|
|
|
|
2020-06-23 14:15:35 +00:00
|
|
|
func calculateMultisigFee(n int) int64 {
|
|
|
|
result := opcodePrice(opcode.PUSHDATA1) * int64(n)
|
2020-05-08 17:54:24 +00:00
|
|
|
bw := io.NewBufBinWriter()
|
|
|
|
emit.Int(bw.BinWriter, int64(n))
|
|
|
|
// it's a hack because prices of small PUSH* opcodes are equal
|
2020-06-23 14:15:35 +00:00
|
|
|
result += opcodePrice(opcode.Opcode(bw.Bytes()[0]))
|
2020-05-08 17:54:24 +00:00
|
|
|
return result
|
|
|
|
}
|