ec7e17ffa6
Simplifies a lot of code and removes some duplication. Unfortunately I had to move test_util random functions in same commit to avoid cycle dependencies. One of these random functions was also used in core/transaction testing, to simplify things I've just dropped it there and used a static string (which is nice to have for a test anyway). There is still sha256 left in wallet (but it needs to pass Hash structure into the signing function).
225 lines
5.8 KiB
Go
225 lines
5.8 KiB
Go
package core
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"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/crypto/hash"
|
|
"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.PUSHT)},
|
|
},
|
|
}
|
|
|
|
governingTX := governingTokenTX()
|
|
utilityTX := utilityTokenTX()
|
|
rawScript, err := smartcontract.CreateMultiSigRedeemScript(
|
|
len(cfg.StandbyValidators)/2+1,
|
|
validators,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
scriptOut := hash.Hash160(rawScript)
|
|
|
|
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.PUSHT)},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if err = block.rebuildMerkleRoot(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return block, nil
|
|
}
|
|
|
|
func governingTokenTX() *transaction.Transaction {
|
|
admin := hash.Hash160([]byte{byte(vm.PUSHT)})
|
|
registerTX := &transaction.RegisterTX{
|
|
AssetType: transaction.GoverningToken,
|
|
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]",
|
|
Amount: util.Fixed8FromInt64(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 := hash.Hash160([]byte{byte(vm.PUSHF)})
|
|
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 hash.Hash160(raw), nil
|
|
}
|
|
|
|
func calculateUtilityAmount() util.Fixed8 {
|
|
sum := 0
|
|
for i := 0; i < len(genAmount); i++ {
|
|
sum += genAmount[i]
|
|
}
|
|
return util.Fixed8FromInt64(int64(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
|
|
}
|