94672cb9cc
* added publish TX for backwards compat. * lowered the prototick for faster block syncing * print useragent on startup * added createMultiRedeemScript for genesis block generation. * building genesis block from scratch. * implemented merkle tree. * starting blockhain with generated genesis hash * Fixed bug in unspent coin state. * fixed broken tests after genesis block. * removed log line. * bumped version -> 0.34.0
265 lines
6.7 KiB
Go
265 lines
6.7 KiB
Go
package core
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/CityOfZion/neo-go/config"
|
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
|
"github.com/CityOfZion/neo-go/pkg/crypto"
|
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
|
"github.com/CityOfZion/neo-go/pkg/util"
|
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
|
)
|
|
|
|
// Creates a genesis block based on the given configuration.
|
|
func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
|
validators, err := getValidators(cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nextConsensus, err := getNextConsensusAddress(validators)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
base := BlockBase{
|
|
Version: 0,
|
|
PrevHash: util.Uint256{},
|
|
Timestamp: uint32(time.Date(2016, 7, 15, 15, 8, 21, 0, time.UTC).Unix()),
|
|
Index: 0,
|
|
ConsensusData: 2083236893,
|
|
NextConsensus: nextConsensus,
|
|
Script: &transaction.Witness{
|
|
InvocationScript: []byte{},
|
|
VerificationScript: []byte{byte(vm.Opusht)},
|
|
},
|
|
}
|
|
|
|
governingTX := governingTokenTX()
|
|
utilityTX := utilityTokenTX()
|
|
rawScript, err := smartcontract.CreateMultiSigRedeemScript(
|
|
len(cfg.StandbyValidators)/2+1,
|
|
validators,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
scriptOut, err := util.Uint160FromScript(rawScript)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
block := &Block{
|
|
BlockBase: base,
|
|
Transactions: []*transaction.Transaction{
|
|
{
|
|
Type: transaction.MinerType,
|
|
Data: &transaction.MinerTX{
|
|
Nonce: 2083236893,
|
|
},
|
|
Attributes: []*transaction.Attribute{},
|
|
Inputs: []*transaction.Input{},
|
|
Outputs: []*transaction.Output{},
|
|
Scripts: []*transaction.Witness{},
|
|
},
|
|
governingTX,
|
|
utilityTX,
|
|
{
|
|
Type: transaction.IssueType,
|
|
Data: &transaction.IssueTX{}, // no fields.
|
|
Inputs: []*transaction.Input{},
|
|
Outputs: []*transaction.Output{
|
|
{
|
|
AssetID: governingTX.Hash(),
|
|
Amount: governingTX.Data.(*transaction.RegisterTX).Amount,
|
|
ScriptHash: scriptOut,
|
|
},
|
|
},
|
|
Scripts: []*transaction.Witness{
|
|
{
|
|
InvocationScript: []byte{},
|
|
VerificationScript: []byte{byte(vm.Opusht)},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
block.rebuildMerkleRoot()
|
|
|
|
return block, nil
|
|
}
|
|
|
|
func governingTokenTX() *transaction.Transaction {
|
|
admin, _ := util.Uint160FromScript([]byte{byte(vm.Opusht)})
|
|
adminB, _ := crypto.Uint160DecodeAddress("Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt")
|
|
if !admin.Equals(adminB) {
|
|
panic("kdjdkljfkdjfkdjf")
|
|
}
|
|
registerTX := &transaction.RegisterTX{
|
|
AssetType: transaction.GoverningToken,
|
|
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]",
|
|
Amount: util.NewFixed8(100000000),
|
|
Precision: 0,
|
|
Owner: &crypto.PublicKey{},
|
|
Admin: admin,
|
|
}
|
|
|
|
tx := &transaction.Transaction{
|
|
Type: transaction.RegisterType,
|
|
Data: registerTX,
|
|
Attributes: []*transaction.Attribute{},
|
|
Inputs: []*transaction.Input{},
|
|
Outputs: []*transaction.Output{},
|
|
Scripts: []*transaction.Witness{},
|
|
}
|
|
|
|
return tx
|
|
}
|
|
|
|
func utilityTokenTX() *transaction.Transaction {
|
|
admin, _ := util.Uint160FromScript([]byte{byte(vm.Opushf)})
|
|
registerTX := &transaction.RegisterTX{
|
|
AssetType: transaction.UtilityToken,
|
|
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]",
|
|
Amount: calculateUtilityAmount(),
|
|
Precision: 8,
|
|
Owner: &crypto.PublicKey{},
|
|
Admin: admin,
|
|
}
|
|
tx := &transaction.Transaction{
|
|
Type: transaction.RegisterType,
|
|
Data: registerTX,
|
|
Attributes: []*transaction.Attribute{},
|
|
Inputs: []*transaction.Input{},
|
|
Outputs: []*transaction.Output{},
|
|
Scripts: []*transaction.Witness{},
|
|
}
|
|
|
|
return tx
|
|
}
|
|
|
|
func getValidators(cfg config.ProtocolConfiguration) ([]*crypto.PublicKey, error) {
|
|
validators := make([]*crypto.PublicKey, len(cfg.StandbyValidators))
|
|
for i, pubKeyStr := range cfg.StandbyValidators {
|
|
pubKey, err := crypto.NewPublicKeyFromString(pubKeyStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
validators[i] = pubKey
|
|
}
|
|
return validators, nil
|
|
}
|
|
|
|
func getNextConsensusAddress(validators []*crypto.PublicKey) (val util.Uint160, err error) {
|
|
vlen := len(validators)
|
|
raw, err := smartcontract.CreateMultiSigRedeemScript(
|
|
vlen-(vlen-1)/3,
|
|
validators,
|
|
)
|
|
if err != nil {
|
|
return val, err
|
|
}
|
|
return util.Uint160FromScript(raw)
|
|
}
|
|
|
|
func calculateUtilityAmount() util.Fixed8 {
|
|
sum := 0
|
|
for i := 0; i < len(genAmount); i++ {
|
|
sum += genAmount[i]
|
|
}
|
|
return util.NewFixed8(sum * decrementInterval)
|
|
}
|
|
|
|
// headerSliceReverse reverses the given slice of *Header.
|
|
func headerSliceReverse(dest []*Header) {
|
|
for i, j := 0, len(dest)-1; i < j; i, j = i+1, j-1 {
|
|
dest[i], dest[j] = dest[j], dest[i]
|
|
}
|
|
}
|
|
|
|
// storeAsCurrentBlock stores the given block witch prefix
|
|
// SYSCurrentBlock.
|
|
func storeAsCurrentBlock(batch storage.Batch, block *Block) {
|
|
buf := new(bytes.Buffer)
|
|
buf.Write(block.Hash().BytesReverse())
|
|
b := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(b, block.Index)
|
|
buf.Write(b)
|
|
batch.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes())
|
|
}
|
|
|
|
// storeAsBlock stores the given block as DataBlock.
|
|
func storeAsBlock(batch storage.Batch, block *Block, sysFee uint32) error {
|
|
var (
|
|
key = storage.AppendPrefix(storage.DataBlock, block.Hash().BytesReverse())
|
|
buf = new(bytes.Buffer)
|
|
)
|
|
|
|
b := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(b, sysFee)
|
|
|
|
b, err := block.Trim()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf.Write(b)
|
|
batch.Put(key, buf.Bytes())
|
|
return nil
|
|
}
|
|
|
|
// storeAsTransaction stores the given TX as DataTransaction.
|
|
func storeAsTransaction(batch storage.Batch, tx *transaction.Transaction, index uint32) error {
|
|
key := storage.AppendPrefix(storage.DataTransaction, tx.Hash().BytesReverse())
|
|
buf := new(bytes.Buffer)
|
|
if err := tx.EncodeBinary(buf); err != nil {
|
|
return err
|
|
}
|
|
|
|
dest := make([]byte, buf.Len()+4)
|
|
binary.LittleEndian.PutUint32(dest[:4], index)
|
|
copy(dest[4:], buf.Bytes())
|
|
batch.Put(key, dest)
|
|
|
|
return nil
|
|
}
|
|
|
|
// readStoredHeaderHashes returns a sorted list of header hashes
|
|
// retrieved from the given Store.
|
|
func readStoredHeaderHashes(store storage.Store) ([]util.Uint256, error) {
|
|
hashMap := make(map[uint32][]util.Uint256)
|
|
store.Seek(storage.IXHeaderHashList.Bytes(), func(k, v []byte) {
|
|
storedCount := binary.LittleEndian.Uint32(k[1:])
|
|
hashes, err := util.Read2000Uint256Hashes(v)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
hashMap[storedCount] = hashes
|
|
})
|
|
|
|
var (
|
|
i = 0
|
|
sortedKeys = make([]int, len(hashMap))
|
|
)
|
|
|
|
for k, _ := range hashMap {
|
|
sortedKeys[i] = int(k)
|
|
i++
|
|
}
|
|
sort.Ints(sortedKeys)
|
|
|
|
hashes := []util.Uint256{}
|
|
for _, key := range sortedKeys {
|
|
values := hashMap[uint32(key)]
|
|
for _, hash := range values {
|
|
hashes = append(hashes, hash)
|
|
}
|
|
}
|
|
|
|
return hashes, nil
|
|
}
|