decoders := map[string]func([]byte) (txbuilder.Action, error){
"control_address": txbuilder.DecodeControlAddressAction,
"control_program": txbuilder.DecodeControlProgramAction,
- "retire": txbuilder.DecodeRetireAction,
"cross_chain_out": txbuilder.DecodeCrossOutAction,
"vote_output": txbuilder.DecodeVoteOutputAction,
+ "retire": txbuilder.DecodeRetireAction,
+ "cross_chain_in": txbuilder.DecodeCrossInAction,
"spend_account": a.wallet.AccountMgr.DecodeSpendAction,
"spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction,
"unvote": a.wallet.AccountMgr.DecodeUnvoteAction,
"encoding/json"
"github.com/vapor/blockchain/query"
+ chainjson "github.com/vapor/encoding/json"
)
-func isValidJSON(b []byte) bool {
- var v interface{}
- err := json.Unmarshal(b, &v)
- return err == nil
-}
-
//Annotated annotate the asset
func Annotated(a *Asset) (*query.AnnotatedAsset, error) {
jsonDefinition := json.RawMessage(`{}`)
// a.RawDefinitionByte is the asset definition as it appears on the
// blockchain, so it's untrusted and may not be valid json.
- if isValidJSON(a.RawDefinitionByte) {
+ if chainjson.IsValidJSON(a.RawDefinitionByte) {
jsonDefinition = json.RawMessage(a.RawDefinitionByte)
}
stdjson "encoding/json"
"errors"
+ "github.com/vapor/config"
+
"github.com/vapor/common"
"github.com/vapor/consensus"
"github.com/vapor/encoding/json"
func (a *voteOutputAction) ActionType() string {
return "vote_output"
}
+
+// DecodeCrossInAction convert input data to action struct
+func DecodeCrossInAction(data []byte) (Action, error) {
+ a := new(crossInAction)
+ err := stdjson.Unmarshal(data, a)
+ return a, err
+}
+
+type crossInAction struct {
+ bc.AssetAmount
+ SourceID bc.Hash `json:"source_id"`
+ SourcePos uint64 `json:"source_pos"`
+ RawDefinitionByte json.HexBytes `json:"raw_definition_byte"`
+}
+
+func (a *crossInAction) Build(ctx context.Context, builder *TemplateBuilder) error {
+ var missing []string
+ if a.SourceID.IsZero() {
+ missing = append(missing, "source_id")
+ }
+ if a.AssetId.IsZero() {
+ missing = append(missing, "asset_id")
+ }
+ if a.Amount == 0 {
+ missing = append(missing, "amount")
+ }
+ if len(missing) > 0 {
+ return MissingFieldsError(missing...)
+ }
+
+ // arguments will be set when materializeWitnesses
+ fedProg := config.FederationProgrom(config.CommonConfig)
+ txin := types.NewCrossChainInput(nil, a.SourceID, *a.AssetId, a.Amount, a.SourcePos, fedProg, a.RawDefinitionByte)
+ tplIn := &SigningInstruction{}
+ fed := config.CommonConfig.Federation
+ tplIn.AddRawWitnessKeys(fed.Xpubs, nil, fed.Quorum)
+ return builder.AddInput(txin, tplIn)
+}
+
+func (a *crossInAction) ActionType() string {
+ return "cross_chain_in"
+}
in.Type = "spend"
in.ControlProgram = orig.ControlProgram()
in.SpentOutputID = e.SpentOutputId
+
+ case *bc.CrossChainInput:
+ in.Type = "cross_chain_in"
+ in.ControlProgram = orig.ControlProgram()
+ in.SpentOutputID = e.MainchainOutputId
}
return in
control, err := vmutil.P2WSHProgram(scriptHash)
if err != nil {
- log.Panicf("Fail converts scriptHash to program on GenesisArguments: %v", err)
+ log.Panicf("Fail converts scriptHash to program on FederationProgrom: %v", err)
}
return control
--- /dev/null
+package federation
+
+import (
+ "encoding/json"
+ "errors"
+
+ log "github.com/sirupsen/logrus"
+
+ "github.com/vapor/crypto/ed25519"
+ "github.com/vapor/crypto/ed25519/chainkd"
+ "github.com/vapor/protocol/vm/vmutil"
+)
+
+const fedCfgJson = `
+{
+ "xpubs" : [
+ "7f23aae65ee4307c38d342699e328f21834488e18191ebd66823d220b5a58303496c9d09731784372bade78d5e9a4a6249b2cfe2e3a85464e5a4017aa5611e47",
+ "585e20143db413e45fbc82f03cb61f177e9916ef1df0012daa8cbf6dbb1025ce8f98e51ae319327b63505b64fdbbf6d36ef916d79e6dd67d51b0bfe76fe544c5",
+ "b58170b51ca61604028ba1cb412377dfc2bc6567c0afc84c83aae1c0c297d0227ccf568561df70851f4144bbf069b525129f2434133c145e35949375b22a6c9d",
+ "983705ae71949c1a5d0fcf953658dd9ecc549f02c63e197b4d087ae31148097ece816bbc60d9012c316139fc550fa0f4b00beb0887f6b152f7a69bc8f392b9fa",
+ "d72fb92fa13bf3e0deb39de3a47c8d6eef5584719f7877c82a4c009f78fddf924d9706d48f15b2c782ec80b6bdd621a1f7ba2a0044b0e6f92245de9436885cb9",
+ "6798460919e8dc7095ee8b9f9d65033ef3da8c2334813149da5a1e52e9c6da07ba7d0e7379baaa0c8bdcb21890a54e6b7290bee077c645ee4b74b0c1ae9da59a"
+ ],
+ "quorum" : 4
+}
+`
+
+type federation struct {
+ XPubs []chainkd.XPub `json:"xpubs"`
+ Quorum int `json:"quorum"`
+ ControlProgram []byte
+}
+
+func parseFedConfig() *federation {
+ fed := &federation{}
+ if err := json.Unmarshal([]byte(fedCfgJson), fed); err != nil {
+ log.Fatalln("invalid federation config json")
+ }
+
+ return fed
+}
+
+// CheckFedConfig checks the high-level rule for federation config, whereas
+// signers.Create checks the low-level rule
+func CheckFedConfig() error {
+ fed := parseFedConfig()
+ if len(fed.XPubs) <= 1 {
+ return errors.New("federation should have more than 1 member")
+ }
+ if fed.Quorum < 1 {
+ return errors.New("federation quorum should be >= 1")
+ }
+
+ return nil
+}
+
+func GetFederation() *federation {
+ fed := parseFedConfig()
+ PublicKeys := chainkd.XPubKeys(fed.XPubs)
+ if controlProgram, err := fed.buildPegInControlProgram(PublicKeys); err == nil {
+ fed.ControlProgram = controlProgram
+ } else {
+ log.Fatalf("fail to build peg-in script: %v", err)
+ }
+
+ return fed
+}
+
+func (f *federation) buildPegInControlProgram(pubkeys []ed25519.PublicKey) (program []byte, err error) {
+ controlProg, err := vmutil.P2SPMultiSigProgram(pubkeys, f.Quorum)
+ if err != nil {
+ return nil, err
+ }
+
+ builder := vmutil.NewBuilder()
+ builder.AddRawBytes(controlProg)
+ return builder.Build()
+}
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type UtxoEntry struct {
- IsCoinBase bool `protobuf:"varint,1,opt,name=isCoinBase" json:"isCoinBase,omitempty"`
+ Type uint32 `protobuf:"varint,1,opt,name=type" json:"type,omitempty"`
BlockHeight uint64 `protobuf:"varint,2,opt,name=blockHeight" json:"blockHeight,omitempty"`
Spent bool `protobuf:"varint,3,opt,name=spent" json:"spent,omitempty"`
}
func (*UtxoEntry) ProtoMessage() {}
func (*UtxoEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
-func (m *UtxoEntry) GetIsCoinBase() bool {
+func (m *UtxoEntry) GetType() uint32 {
if m != nil {
- return m.IsCoinBase
+ return m.Type
}
- return false
+ return 0
}
func (m *UtxoEntry) GetBlockHeight() uint64 {
func init() { proto.RegisterFile("storage.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
- // 154 bytes of a gzipped FileDescriptorProto
+ // 151 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0x2e, 0xc9, 0x2f,
0x4a, 0x4c, 0x4f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0x48, 0xce, 0x48, 0xcc, 0xcc,
0xd3, 0x4b, 0xce, 0x2f, 0x4a, 0xd5, 0x2b, 0xa9, 0x48, 0x49, 0xd2, 0xcb, 0xcc, 0x2b, 0x49, 0x2d,
- 0xca, 0x4b, 0xcc, 0xd1, 0x83, 0xaa, 0x53, 0x4a, 0xe6, 0xe2, 0x0c, 0x2d, 0xa9, 0xc8, 0x77, 0xcd,
- 0x2b, 0x29, 0xaa, 0x14, 0x92, 0xe3, 0xe2, 0xca, 0x2c, 0x76, 0xce, 0xcf, 0xcc, 0x73, 0x4a, 0x2c,
- 0x4e, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x08, 0x42, 0x12, 0x11, 0x52, 0xe0, 0xe2, 0x4e, 0xca,
- 0xc9, 0x4f, 0xce, 0xf6, 0x48, 0xcd, 0x4c, 0xcf, 0x28, 0x91, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x09,
- 0x42, 0x16, 0x12, 0x12, 0xe1, 0x62, 0x2d, 0x2e, 0x48, 0xcd, 0x2b, 0x91, 0x60, 0x06, 0x6b, 0x86,
- 0x70, 0x9c, 0x38, 0xa3, 0xd8, 0xa1, 0xf6, 0x25, 0xb1, 0x81, 0x1d, 0x66, 0x0c, 0x08, 0x00, 0x00,
- 0xff, 0xff, 0xcf, 0xe4, 0x5a, 0x5c, 0xa9, 0x00, 0x00, 0x00,
+ 0xca, 0x4b, 0xcc, 0xd1, 0x83, 0xaa, 0x53, 0x0a, 0xe7, 0xe2, 0x0c, 0x2d, 0xa9, 0xc8, 0x77, 0xcd,
+ 0x2b, 0x29, 0xaa, 0x14, 0x12, 0xe2, 0x62, 0x29, 0xa9, 0x2c, 0x48, 0x95, 0x60, 0x54, 0x60, 0xd4,
+ 0xe0, 0x0d, 0x02, 0xb3, 0x85, 0x14, 0xb8, 0xb8, 0x93, 0x72, 0xf2, 0x93, 0xb3, 0x3d, 0x52, 0x33,
+ 0xd3, 0x33, 0x4a, 0x24, 0x98, 0x14, 0x18, 0x35, 0x58, 0x82, 0x90, 0x85, 0x84, 0x44, 0xb8, 0x58,
+ 0x8b, 0x0b, 0x52, 0xf3, 0x4a, 0x24, 0x98, 0x15, 0x18, 0x35, 0x38, 0x82, 0x20, 0x1c, 0x27, 0xce,
+ 0x28, 0x76, 0xa8, 0x1d, 0x49, 0x6c, 0x60, 0xc7, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x61,
+ 0x0a, 0x61, 0x8f, 0x9d, 0x00, 0x00, 0x00,
}
package chain.core.txdb.internal.storage;
message UtxoEntry {
- bool isCoinBase = 1;
- uint64 blockHeight = 2;
- bool spent = 3;
+ uint32 type = 1;
+ uint64 blockHeight = 2;
+ bool spent = 3;
}
package storage
+const (
+ NormalUTXOType uint32 = iota
+ CoinbaseUTXOType
+ CrosschainUTXOType
+)
+
// NewUtxoEntry will create a new utxo entry
-func NewUtxoEntry(isCoinBase bool, blockHeight uint64, spent bool) *UtxoEntry {
+func NewUtxoEntry(utxoType uint32, blockHeight uint64, spent bool) *UtxoEntry {
return &UtxoEntry{
- IsCoinBase: isCoinBase,
+ Type: utxoType,
BlockHeight: blockHeight,
Spent: spent,
}
t.Errorf("got block index:%v, expect block index:%v", index, expectBlockIndex)
}
}
+
func TestSaveChainStatus(t *testing.T) {
testDB := dbm.NewDB("testdb", "leveldb", "temp")
defer func() {
node := &state.BlockNode{Height: 100, Hash: bc.Hash{V0: 0, V1: 1, V2: 2, V3: 3}}
view := &state.UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 1, V1: 2, V2: 3, V3: 4}: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 100, Spent: false},
- bc.Hash{V0: 1, V1: 2, V2: 3, V3: 4}: &storage.UtxoEntry{IsCoinBase: true, BlockHeight: 100, Spent: true},
- bc.Hash{V0: 1, V1: 1, V2: 3, V3: 4}: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 100, Spent: true},
+ bc.Hash{V0: 1, V1: 2, V2: 3, V3: 4}: &storage.UtxoEntry{Type: storage.NormalUTXOType, BlockHeight: 100, Spent: false},
+ bc.Hash{V0: 1, V1: 2, V2: 3, V3: 4}: &storage.UtxoEntry{Type: storage.CoinbaseUTXOType, BlockHeight: 100, Spent: true},
+ bc.Hash{V0: 1, V1: 1, V2: 3, V3: 4}: &storage.UtxoEntry{Type: storage.NormalUTXOType, BlockHeight: 100, Spent: true},
+ bc.Hash{V0: 1, V1: 1, V2: 3, V3: 5}: &storage.UtxoEntry{Type: storage.CrosschainUTXOType, BlockHeight: 100, Spent: false},
+ bc.Hash{V0: 1, V1: 1, V2: 3, V3: 6}: &storage.UtxoEntry{Type: storage.CrosschainUTXOType, BlockHeight: 100, Spent: true},
},
}
}
for hash, utxo := range view.Entries {
- if utxo.Spent && !utxo.IsCoinBase {
+ if (utxo.Type == storage.NormalUTXOType) && utxo.Spent {
+ continue
+ }
+ if (utxo.Type == storage.CrosschainUTXOType) && (!utxo.Spent) {
continue
}
view.Entries[prevout] = &utxo
}
+
+ for _, prevout := range tx.MainchainOutputIDs {
+ if view.HasUtxo(&prevout) {
+ continue
+ }
+
+ data := db.Get(calcUtxoKey(&prevout))
+ if data == nil {
+ view.Entries[prevout] = storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false)
+ continue
+ }
+
+ var utxo storage.UtxoEntry
+ if err := proto.Unmarshal(data, &utxo); err != nil {
+ return errors.Wrap(err, "unmarshaling mainchain ouput entry")
+ }
+
+ view.Entries[prevout] = &utxo
+ }
}
return nil
func saveUtxoView(batch dbm.Batch, view *state.UtxoViewpoint) error {
for key, entry := range view.Entries {
- if entry.Spent && !entry.IsCoinBase {
+ if (entry.Type == storage.CrosschainUTXOType) && (!entry.Spent) {
+ batch.Delete(calcUtxoKey(&key))
+ continue
+ }
+
+ if (entry.Type == storage.NormalUTXOType) && (entry.Spent) {
batch.Delete(calcUtxoKey(&key))
continue
}
}{
{
hash: bc.Hash{V0: 0},
- utxoEntry: storage.NewUtxoEntry(true, 0, true),
+ utxoEntry: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
exist: true,
},
{
hash: bc.Hash{V0: 1},
- utxoEntry: storage.NewUtxoEntry(true, 0, false),
+ utxoEntry: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
exist: true,
},
{
hash: bc.Hash{V0: 2},
- utxoEntry: storage.NewUtxoEntry(false, 0, false),
+ utxoEntry: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
exist: true,
},
{
hash: bc.Hash{V0: 3},
- utxoEntry: storage.NewUtxoEntry(false, 0, true),
+ utxoEntry: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
+ exist: false,
+ },
+ {
+ hash: bc.Hash{V0: 4},
+ utxoEntry: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, true),
+ exist: true,
+ },
+ {
+ hash: bc.Hash{V0: 5},
+ utxoEntry: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false),
exist: false,
},
}
batch := testDB.NewBatch()
inputView := state.NewUtxoViewpoint()
for i := 0; i <= 2; i++ {
- inputView.Entries[bc.Hash{V0: uint64(i)}] = storage.NewUtxoEntry(false, uint64(i), false)
+ inputView.Entries[bc.Hash{V0: uint64(i)}] = storage.NewUtxoEntry(storage.NormalUTXOType, uint64(i), false)
}
saveUtxoView(batch, inputView)
batch.Write()
inputView: state.NewUtxoViewpoint(),
fetchView: &state.UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
err: false,
inputView: state.NewUtxoViewpoint(),
fetchView: &state.UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
- bc.Hash{V0: 1}: storage.NewUtxoEntry(false, 1, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
+ bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 1, false),
},
},
err: false,
inputView: state.NewUtxoViewpoint(),
fetchView: &state.UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
- bc.Hash{V0: 1}: storage.NewUtxoEntry(false, 1, false),
- bc.Hash{V0: 2}: storage.NewUtxoEntry(false, 2, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
+ bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 1, false),
+ bc.Hash{V0: 2}: storage.NewUtxoEntry(storage.NormalUTXOType, 2, false),
},
},
err: false,
},
inputView: &state.UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 1, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 1, false),
},
},
fetchView: &state.UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 1, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 1, false),
},
},
err: false,
"encoding/json"
)
+func IsValidJSON(b []byte) bool {
+ var v interface{}
+ err := json.Unmarshal(b, &v)
+ return err == nil
+}
+
type HexBytes []byte
func (h HexBytes) MarshalText() ([]byte, error) {
import (
"context"
+ "encoding/hex"
"errors"
"net"
"net/http"
dbm "github.com/vapor/database/leveldb"
"github.com/vapor/env"
"github.com/vapor/event"
- "github.com/vapor/proposal/blockproposer"
"github.com/vapor/net/websocket"
"github.com/vapor/netsync"
+ "github.com/vapor/proposal/blockproposer"
"github.com/vapor/protocol"
w "github.com/vapor/wallet"
)
// NewNode create bytom node
func NewNode(config *cfg.Config) *Node {
ctx := context.Background()
+
if err := lockDataDirectory(config); err != nil {
cmn.Exit("Error: " + err.Error())
}
+
if err := cfg.LoadFederationFile(config.FederationFile(), config); err != nil {
cmn.Exit(cmn.Fmt("Failed to load federated information:[%s]", err.Error()))
}
+
+ log.WithFields(log.Fields{
+ "module": logModule,
+ "fed_xpubs": config.Federation.Xpubs,
+ "fed_quorum": config.Federation.Quorum,
+ "fed_controlprogram": hex.EncodeToString(cfg.FederationProgrom(config)),
+ }).Info()
+
initLogFile(config)
initActiveNetParams(config)
initCommonConfig(config)
Entries map[Hash]Entry
InputIDs []Hash // 1:1 correspondence with TxData.Inputs
- SpentOutputIDs []Hash
- GasInputIDs []Hash
+ SpentOutputIDs []Hash
+ MainchainOutputIDs []Hash
+ GasInputIDs []Hash
}
// SigHash ...
}
spentOutputIDs := make(map[bc.Hash]bool)
+ mainchainOutputIDs := make(map[bc.Hash]bool)
for id, e := range entries {
var ord uint64
switch e := e.(type) {
case *bc.CrossChainInput:
ord = e.Ordinal
+ mainchainOutputIDs[*e.MainchainOutputId] = true
if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
tx.GasInputIDs = append(tx.GasInputIDs, id)
}
for id := range spentOutputIDs {
tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
}
+ for id := range mainchainOutputIDs {
+ tx.MainchainOutputIDs = append(tx.MainchainOutputIDs, id)
+ }
return tx
}
spends = append(spends, spend)
case *CrossChainInput:
+ // TODO: fed peg script
prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
src := &bc.ValueSource{
Ref: &inp.SourceID,
Value: &inp.AssetAmount,
Position: inp.SourcePosition,
}
- prevout := bc.NewCrossChainOutput(src, prog, 0) // ordinal doesn't matter
+ prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter
outputID := bc.EntryID(prevout)
crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, prog, uint64(i))
crossIn.WitnessArguments = inp.Arguments
Value: &inp.AssetAmount,
}
crossIns = append(crossIns, crossIn)
-
}
}
switch e := e.(type) {
case *bc.Spend:
e.WitnessArguments = args
+ case *bc.CrossChainInput:
+ e.WitnessArguments = args
}
}
utxoView := state.NewUtxoViewpoint()
voteResultMap := make(map[uint64]*state.VoteResult)
irreversibleNode := c.bestIrreversibleNode
-
+
for _, detachNode := range detachNodes {
b, err := c.store.GetBlock(&detachNode.Hash)
if err != nil {
if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
return err
}
+
txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
if err != nil {
return err
}
+
if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
return err
}
-
+
if err := c.bbft.DetachBlock(voteResultMap, b); err != nil {
return err
}
if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
return err
}
+
txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
if err != nil {
return err
}
+
if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
return err
}
if block.Height <= c.bestIrreversibleNode.Height {
return false, errors.New("the height of block below the height of irreversible block")
}
-
+
blockHash := block.Hash()
if c.BlockExist(&blockHash) {
log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
if err != nil {
return err
}
+
return c.store.SaveChainStatus(node, node, utxoView, map[uint64]*state.VoteResult{})
}
}
func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFail bool) error {
+ for _, prevout := range tx.MainchainOutputIDs {
+ entry, ok := view.Entries[prevout]
+ if !ok {
+ return errors.New("fail to find mainchain output entry")
+ }
+
+ if entry.Type != storage.CrosschainUTXOType {
+ return errors.New("look up mainchainOutputID but find utxo not from mainchain")
+ }
+
+ if entry.Spent {
+ return errors.New("mainchain output has been spent")
+ }
+
+ entry.BlockHeight = block.Height
+ entry.SpendOutput()
+ }
+
for _, prevout := range tx.SpentOutputIDs {
assetID := bc.AssetID{}
entryOutput, err := tx.Entry(prevout)
if !ok {
return errors.New("fail to find utxo entry")
}
+ if entry.Type == storage.CrosschainUTXOType {
+ return errors.New("look up spentOutputID but find utxo from mainchain")
+ }
if entry.Spent {
return errors.New("utxo has been spent")
}
- if entry.IsCoinBase && entry.BlockHeight+consensus.CoinbasePendingBlockNumber > block.Height {
+ if (entry.Type == storage.CoinbaseUTXOType) && ((entry.BlockHeight + consensus.CoinbasePendingBlockNumber) > block.Height) {
return errors.New("coinbase utxo is not ready for use")
}
entry.SpendOutput()
continue
}
- isCoinbase := false
+ utxoType := storage.NormalUTXOType
if block != nil && len(block.Transactions) > 0 && block.Transactions[0].ID == tx.ID {
- isCoinbase = true
+ utxoType = storage.CoinbaseUTXOType
}
- view.Entries[*id] = storage.NewUtxoEntry(isCoinbase, block.Height, false)
+ view.Entries[*id] = storage.NewUtxoEntry(utxoType, block.Height, false)
}
return nil
}
}
func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error {
+ for _, prevout := range tx.MainchainOutputIDs {
+ // don't simply delete(view.Entries, prevout), because we need to delete from db in saveUtxoView()
+ entry, ok := view.Entries[prevout]
+ if ok && (entry.Type != storage.CrosschainUTXOType) {
+ return errors.New("look up mainchainOutputID but find utxo not from mainchain")
+ }
+
+ if ok && !entry.Spent {
+ return errors.New("try to revert an unspent utxo")
+ }
+
+ if !ok {
+ view.Entries[prevout] = storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false)
+ continue
+ }
+ entry.UnspendOutput()
+ }
+
for _, prevout := range tx.SpentOutputIDs {
assetID := bc.AssetID{}
entryOutput, err := tx.Entry(prevout)
}
entry, ok := view.Entries[prevout]
+ if ok && (entry.Type == storage.CrosschainUTXOType) {
+ return errors.New("look up SpentOutputIDs but find mainchain utxo")
+ }
+
if ok && !entry.Spent {
return errors.New("try to revert an unspent utxo")
}
+
if !ok {
- view.Entries[prevout] = storage.NewUtxoEntry(false, 0, false)
+ view.Entries[prevout] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, false)
continue
}
entry.UnspendOutput()
continue
}
- view.Entries[*id] = storage.NewUtxoEntry(false, 0, true)
+ view.Entries[*id] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, true)
}
return nil
}
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
fetchView: NewUtxoViewpoint(),
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, true),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
},
},
err: true,
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, true),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
},
},
err: false,
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
},
},
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, true),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
},
},
err: false,
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
},
},
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, true),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
},
},
err: true,
inputView: NewUtxoViewpoint(),
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
},
},
err: false,
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V1: 0}: storage.NewUtxoEntry(false, 0, false),
- bc.Hash{V1: 1}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
+ bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V1: 0}: storage.NewUtxoEntry(false, 0, true),
- bc.Hash{V1: 1}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
+ bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
gasOnlyTx: true,
inputView: NewUtxoViewpoint(),
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V1: 0}: storage.NewUtxoEntry(true, 0, false),
+ bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
},
},
gasOnlyTx: true,
inputView: NewUtxoViewpoint(),
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
err: false,
inputView: NewUtxoViewpoint(),
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, true),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
},
},
err: false,
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
err: true,
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, true),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
},
},
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V0: 0}: storage.NewUtxoEntry(false, 0, false),
+ bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
},
},
err: false,
},
inputView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V1: 0}: storage.NewUtxoEntry(false, 0, true),
- bc.Hash{V1: 1}: storage.NewUtxoEntry(false, 0, true),
+ bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
+ bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
},
},
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V1: 0}: storage.NewUtxoEntry(false, 0, false),
- bc.Hash{V1: 1}: storage.NewUtxoEntry(false, 0, true),
+ bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
+ bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
},
},
gasOnlyTx: true,
inputView: NewUtxoViewpoint(),
fetchView: &UtxoViewpoint{
Entries: map[bc.Hash]*storage.UtxoEntry{
- bc.Hash{V1: 0}: storage.NewUtxoEntry(false, 0, true),
+ bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
},
},
gasOnlyTx: true,
func (s *mockStore) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil }
func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
-func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error { return nil }
+func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error {
+ return nil
+}
func (s *mockStore) SaveChainNodeStatus(*state.BlockNode, *state.BlockNode) error { return nil }
func TestAddOrphan(t *testing.T) {
func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
+ // TODO:
for _, hash := range testTxs[2].SpentOutputIDs {
- utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
+ utxoView.Entries[hash] = &storage.UtxoEntry{Type: storage.NormalUTXOType, Spent: false}
}
return nil
}
-func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
-func (s *mockStore1) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil }
-func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
-func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
-func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error { return nil }
+func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
+func (s *mockStore1) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil }
+func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
+func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
+func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error {
+ return nil
+}
func (s *mockStore1) SaveChainNodeStatus(*state.BlockNode, *state.BlockNode) error { return nil }
func TestProcessTransaction(t *testing.T) {
destPos = &e.WitnessDestination.Position
s := e.SpentOutputId.Bytes()
spentOutputID = &s
+
case *bc.VoteOutput:
a1 := spentOutput.Source.Value.AssetId.Bytes()
assetID = &a1
// init UtxoViewpoint
utxoView := state.NewUtxoViewpoint()
- utxoEntry := storage.NewUtxoEntry(false, 1, false)
+ utxoEntry := storage.NewUtxoEntry(storage.NormalUTXOType, 1, false)
for _, tx := range txs {
for _, id := range tx.SpentOutputIDs {
utxoView.Entries[id] = utxoEntry
func (ctx *chainTestContext) validateExecution(block *types.Block) error {
for _, tx := range block.Transactions {
+ for _, mainchainOutputID := range tx.MainchainOutputIDs {
+ utxoEntry, _ := ctx.Store.GetUtxo(&mainchainOutputID)
+ if utxoEntry == nil {
+ continue
+ }
+ if utxoEntry.Type != storage.CrosschainUTXOType {
+ return fmt.Errorf("found non-mainchain utxo entry")
+ }
+ if !utxoEntry.Spent {
+ return fmt.Errorf("utxo entry status should be spent")
+ }
+ }
+
for _, spentOutputID := range tx.SpentOutputIDs {
utxoEntry, _ := ctx.Store.GetUtxo(&spentOutputID)
if utxoEntry == nil {
continue
}
- if !utxoEntry.IsCoinBase {
- return fmt.Errorf("found non-coinbase spent utxo entry")
+ if utxoEntry.Type == storage.NormalUTXOType {
+ return fmt.Errorf("found normal utxo entry")
}
if !utxoEntry.Spent {
return fmt.Errorf("utxo entry status should be spent")
{
desc: "coinbase tx",
before: make(map[bc.Hash]*storage.UtxoEntry),
- want: map[bc.Hash]*storage.UtxoEntry{*newTx(mockBlocks[0].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[0].Block.Height, false)},
+ want: map[bc.Hash]*storage.UtxoEntry{*newTx(mockBlocks[0].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[0].Block.Height, false)},
attachBlock: []*bc.Block{
types.MapBlock(&mockBlocks[0].Block),
},
{
desc: "Chain trading 3",
before: map[bc.Hash]*storage.UtxoEntry{
- newTx(mockBlocks[1].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(false, mockBlocks[1].Height-1, false),
+ newTx(mockBlocks[1].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height-1, false),
},
want: map[bc.Hash]*storage.UtxoEntry{
- *newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[1].Height, false),
- *newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
- *newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
- *newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
- *newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
+ *newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[1].Height, false),
+ *newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
+ *newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
+ *newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
+ *newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
},
attachBlock: []*bc.Block{
types.MapBlock(&mockBlocks[1].Block),
{
desc: "detach 1 block, attach 2 block",
before: map[bc.Hash]*storage.UtxoEntry{
- *newTx(mockBlocks[2].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[2].Height, false),
- *newTx(mockBlocks[2].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[2].Height, false),
- *newTx(mockBlocks[2].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[2].Height, false),
+ *newTx(mockBlocks[2].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[2].Height, false),
+ *newTx(mockBlocks[2].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false),
+ *newTx(mockBlocks[2].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false),
},
want: map[bc.Hash]*storage.UtxoEntry{
- *newTx(mockBlocks[3].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[3].Height, false),
- *newTx(mockBlocks[3].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[3].Height, false),
+ *newTx(mockBlocks[3].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[3].Height, false),
+ *newTx(mockBlocks[3].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[3].Height, false),
- *newTx(mockBlocks[4].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[4].Height, false),
- *newTx(mockBlocks[4].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[4].Height, false),
- *newTx(mockBlocks[4].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[4].Height, false),
+ *newTx(mockBlocks[4].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[4].Height, false),
+ *newTx(mockBlocks[4].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false),
+ *newTx(mockBlocks[4].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false),
},
attachBlock: []*bc.Block{
types.MapBlock(&mockBlocks[3].Block),
{
desc: "detach block 5, attach block 2",
before: map[bc.Hash]*storage.UtxoEntry{
- *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[5].Height, false),
- *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
- *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
-
- *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
-
- *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[7].Height, false),
- *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
- *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
- *newTx(mockBlocks[7].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
- *newTx(mockBlocks[7].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
-
- *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
-
- *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[9].Height, false),
- *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
- *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
+ *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[5].Height, false),
+ *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false),
+ *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false),
+
+ *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+
+ *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[7].Height, false),
+ *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
+ *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
+ *newTx(mockBlocks[7].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
+ *newTx(mockBlocks[7].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
+
+ *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+
+ *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[9].Height, false),
+ *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false),
+ *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false),
},
want: map[bc.Hash]*storage.UtxoEntry{
- *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
-
- *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+
+ *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
},
attachBlock: []*bc.Block{
types.MapBlock(&mockBlocks[10].Block),
{
desc: "detach block 5, attach block 2. Other asset deals failed.",
before: map[bc.Hash]*storage.UtxoEntry{
- *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[5].Height, false),
- *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
- *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
-
- *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- newTx(mockBlocks[6].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[6].Height-1, false),
-
- *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
- newTx(mockBlocks[6].Transactions[2]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[6].Height-1, false),
-
- *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[7].Height, false),
- *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
- *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
- newTx(mockBlocks[7].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[7].Height-1, false),
-
- *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- newTx(mockBlocks[8].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[8].Height-1, false),
-
- *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
- *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
-
- *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[9].Height, false),
- *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
- *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
+ *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[5].Height, false),
+ *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false),
+ *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false),
+
+ *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ newTx(mockBlocks[6].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height-1, false),
+
+ *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
+ newTx(mockBlocks[6].Transactions[2]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height-1, false),
+
+ *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[7].Height, false),
+ *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
+ *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
+ newTx(mockBlocks[7].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height-1, false),
+
+ *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ newTx(mockBlocks[8].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height-1, false),
+
+ *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+ *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
+
+ *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[9].Height, false),
+ *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false),
+ *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false),
},
want: map[bc.Hash]*storage.UtxoEntry{
- *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
-
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
-
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
-
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
- *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
-
- *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
- *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+ *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
+
+ *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
+ *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
},
attachBlock: []*bc.Block{
types.MapBlock(&mockBlocks[10].Block),
desc: "detach block 2, attach block 1. Chain trading",
before: map[bc.Hash]*storage.UtxoEntry{
// coinbase tx
- *newTx(mockBlocks[12].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[12].Height, false),
- *newTx(mockBlocks[12].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
- *newTx(mockBlocks[12].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
- *newTx(mockBlocks[12].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
- *newTx(mockBlocks[12].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
-
- *newTx(mockBlocks[13].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[13].Height, false),
- *newTx(mockBlocks[13].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
- *newTx(mockBlocks[13].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
- *newTx(mockBlocks[13].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
+ *newTx(mockBlocks[12].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[12].Height, false),
+ *newTx(mockBlocks[12].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
+ *newTx(mockBlocks[12].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
+ *newTx(mockBlocks[12].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
+ *newTx(mockBlocks[12].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
+
+ *newTx(mockBlocks[13].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[13].Height, false),
+ *newTx(mockBlocks[13].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false),
+ *newTx(mockBlocks[13].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false),
+ *newTx(mockBlocks[13].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false),
},
want: map[bc.Hash]*storage.UtxoEntry{
- newTx(mockBlocks[12].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(false, 0, false),
- *newTx(mockBlocks[14].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[14].Height, false),
+ newTx(mockBlocks[12].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
+ *newTx(mockBlocks[14].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[14].Height, false),
},
attachBlock: []*bc.Block{
types.MapBlock(&mockBlocks[14].Block),
var emptyJSONObject = json.RawMessage(`{}`)
-func isValidJSON(b []byte) bool {
- var v interface{}
- err := json.Unmarshal(b, &v)
- return err == nil
-}
-
func (w *Wallet) buildAnnotatedTransaction(orig *types.Tx, b *types.Block, statusFail bool, indexInBlock int) *query.AnnotatedTx {
tx := &query.AnnotatedTx{
ID: orig.ID,
in.InputID = id
e := tx.Entries[id]
switch e := e.(type) {
+ case *bc.CrossChainInput:
+ in.Type = "cross_chain_in"
+ in.ControlProgram = orig.ControlProgram()
+ in.Address = w.getAddressFromControlProgram(in.ControlProgram)
+ in.SpentOutputID = e.MainchainOutputId
+ arguments := orig.Arguments()
+ for _, arg := range arguments {
+ in.WitnessArguments = append(in.WitnessArguments, arg)
+ }
+
case *bc.Spend:
in.Type = "spend"
in.ControlProgram = orig.ControlProgram()
for _, arg := range arguments {
in.WitnessArguments = append(in.WitnessArguments, arg)
}
+
case *bc.Coinbase:
in.Type = "coinbase"
in.Arbitrary = e.Arbitrary
log "github.com/sirupsen/logrus"
"github.com/vapor/account"
+ "github.com/vapor/asset"
"github.com/vapor/blockchain/query"
"github.com/vapor/crypto/sha3pool"
dbm "github.com/vapor/database/leveldb"
defer storeBatch.Write()
for _, tx := range b.Transactions {
- for _, _ = range tx.Inputs {
- // handle cross chain input here
+ for _, orig := range tx.Inputs {
+ if cci, ok := orig.TypedInput.(*types.CrossChainInput); ok {
+ assetID := cci.AssetId
+ if assetExist := walletDB.Get(asset.ExtAssetKey(assetID)); assetExist == nil {
+ storeBatch.Set(asset.ExtAssetKey(assetID), cci.AssetDefinition)
+ }
+ }
}
}
}
}
default:
- log.WithFields(log.Fields{"module": logModule}).Error("txOutToUtxos fail on get bcOut")
+ log.WithFields(log.Fields{"module": logModule}).Warn("txOutToUtxos fail on get bcOut")
continue
}
tx: types.NewTx(types.TxData{
Inputs: []*types.TxInput{
types.NewCrossChainInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 5, 1, []byte{0x51}, []byte("asset1")),
- types.NewCrossChainInput([][]byte{}, bc.Hash{V0: 2}, *consensus.BTMAssetID, 7, 1, []byte{0x51}, []byte("assetbtm")),
- },
+ types.NewCrossChainInput([][]byte{}, bc.Hash{V0: 2}, *consensus.BTMAssetID, 7, 1, []byte{0x51}, []byte("assetbtm"))},
Outputs: []*types.TxOutput{
types.NewIntraChainOutput(bc.AssetID{V0: 1}, 2, []byte{0x51}),
types.NewIntraChainOutput(bc.AssetID{V0: 1}, 3, []byte{0x52}),
vaildHeight: 0,
wantUtxos: []*account.UTXO{
&account.UTXO{
- OutputID: bc.Hash{V0: 5017869556807322455, V1: 10783536743298812154, V2: 16502849815258393708, V3: 17463924228237024089},
+ OutputID: bc.Hash{V0: 396952592194652166, V1: 9806684391645699244, V2: 484243382648745315, V3: 16988093808435014689},
AssetID: bc.AssetID{V0: 1},
Amount: 2,
ControlProgram: []byte{0x51},
- SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940},
+ SourceID: bc.Hash{V0: 15256474482236132139, V1: 14615963227748152009, V2: 1392768713126269609, V3: 3435801067785833027},
SourcePos: 0,
},
&account.UTXO{
- OutputID: bc.Hash{V0: 8442687171321510229, V1: 178047204952239580, V2: 14256661948207077650, V3: 3922576028594028500},
+ OutputID: bc.Hash{V0: 10880631720641638863, V1: 7783872056988487492, V2: 10925792818362846534, V3: 16483659407709834456},
AssetID: bc.AssetID{V0: 1},
Amount: 3,
ControlProgram: []byte{0x52},
- SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940},
+ SourceID: bc.Hash{V0: 15256474482236132139, V1: 14615963227748152009, V2: 1392768713126269609, V3: 3435801067785833027},
SourcePos: 1,
},
&account.UTXO{
- OutputID: bc.Hash{V0: 15236227421929631619, V1: 17681725875373715927, V2: 6774865146044108440, V3: 2227522355677716485},
+ OutputID: bc.Hash{V0: 6688768820716928311, V1: 7640171490156205612, V2: 6082620342644961312, V3: 6194446985740174532},
AssetID: *consensus.BTMAssetID,
Amount: 2,
ControlProgram: []byte{0x53},
- SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940},
+ SourceID: bc.Hash{V0: 15256474482236132139, V1: 14615963227748152009, V2: 1392768713126269609, V3: 3435801067785833027},
SourcePos: 2,
},
&account.UTXO{
- OutputID: bc.Hash{V0: 6086763013160396583, V1: 9766912420896403386, V2: 15586229129198962584, V3: 11214218750546954166},
+ OutputID: bc.Hash{V0: 13540722642395030514, V1: 15412939347183859286, V2: 9545016219428105666, V3: 11940603522975438116},
AssetID: *consensus.BTMAssetID,
Amount: 5,
ControlProgram: []byte{0x54},
- SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940},
+ SourceID: bc.Hash{V0: 15256474482236132139, V1: 14615963227748152009, V2: 1392768713126269609, V3: 3435801067785833027},
SourcePos: 3,
},
},