OSDN Git Service

feat: add build crosschain input (#91)
authorHAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
Wed, 29 May 2019 10:16:17 +0000 (18:16 +0800)
committerPaladz <yzhu101@uottawa.ca>
Wed, 29 May 2019 10:16:17 +0000 (18:16 +0800)
* wip: init DecodeCrossOutAction

* refactor: move DecodeCrossInAction to AccountMgr

* fix: fix account/builder.go

* fix: fix asset in crossInAction.Build

* update source in crossInAction.Build

* refactor: clean up

* fix: fix sourceID in crossInAction.Build

* init

* feat: serializeAssetDef & checkValidJSON

* fix

* refactor: add asset.Registry into accountManager

* wip: add asset definition comparison

* feat: cheack asset definition mismatch

* wip

* fix: add

* refactor: add lines

* wup

* revert

* clean

* revert

* merge

* wip

* revert

* clean

* fix

* fix

* clean

* fix

* clean

* fix MustDecodeHash

* fix

* clean up

* init saveExternalAssetDefinition

* fix

* fk

* update

* wip

* update

* draft

* update

* draft

* check replay

* clean

* init

* wwww

* draft conseus fed

* clean

* merfe

* clean

* clean

* clean

* fix https://github.com/Bytom/vapor/pull/77#discussion_r286745872

* fix https://github.com/Bytom/vapor/pull/77#discussion_r286742937

* fix https://github.com/Bytom/vapor/pull/77#discussion_r286744128

* fix https://github.com/Bytom/vapor/pull/77#discussion_r286744426

* fix https://github.com/Bytom/vapor/pull/77#discussion_r286744843

* fix https://github.com/Bytom/vapor/pull/77/files#r286744635 & https://github.com/Bytom/vapor/pull/77#discussion_r286744048 & https://github.com/Bytom/vapor/pull/77#discussion_r286743987

* fix https://github.com/Bytom/vapor/pull/77#discussion_r286744322

* minor

* update

* update

* minor

* format code

* fix

* use genesis config

* update

* update

* clean

* utxo database

* utxo database test

* aha

* wip

* wip

* wip

* claimed

* ???

* init

* foix

* dododod

* fk

* add mainchainOutputIDs

* roll back

* dododo

* update

* revert

* fix

* fix

* fk

* dd

* clean

* roll back

* fix detach

* clean up

* fix https://github.com/Bytom/vapor/pull/91#discussion_r287974764

* fix https://github.com/Bytom/vapor/pull/91#discussion_r287975636

* fix https://github.com/Bytom/vapor/pull/91#discussion_r287976043

* rm path

* fix https://github.com/Bytom/vapor/pull/91#discussion_r287974969

* use type for utxo

* uint32

* add iota

* fix https://github.com/Bytom/vapor/pull/91#discussion_r287980844

* modify build

* modify utxo type

* fix

* fix

30 files changed:
api/transact.go
asset/annotate.go
blockchain/txbuilder/actions.go
blockchain/txfeed/txfeed.go
config/genesis.go
consensus/federation/federation.go [new file with mode: 0644]
database/storage/storage.pb.go
database/storage/storage.proto
database/storage/utxo_entry.go
database/store_test.go
database/utxo_view.go
database/utxo_view_test.go
encoding/json/json.go
node/node.go
protocol/bc/tx.go
protocol/bc/types/map.go
protocol/bc/types/transaction.go
protocol/block.go
protocol/protocol.go
protocol/state/utxo_view.go
protocol/state/utxo_view_test.go
protocol/txpool_test.go
protocol/validation/vmcontext.go
test/bench_blockchain_test.go
test/chain_test_util.go
test/utxo_view/utxo_view_test.go
wallet/annotated.go
wallet/indexer.go
wallet/utxo.go
wallet/utxo_test.go

index 350ed85..3f2c0db 100644 (file)
@@ -25,9 +25,10 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro
        decoders := map[string]func([]byte) (txbuilder.Action, error){
                "control_address":              txbuilder.DecodeControlAddressAction,
                "control_program":              txbuilder.DecodeControlProgramAction,
        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,
                "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,
                "spend_account":                a.wallet.AccountMgr.DecodeSpendAction,
                "spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction,
                "unvote":                       a.wallet.AccountMgr.DecodeUnvoteAction,
index 4156202..723e0bb 100644 (file)
@@ -4,21 +4,16 @@ import (
        "encoding/json"
 
        "github.com/vapor/blockchain/query"
        "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.
 //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)
        }
 
                jsonDefinition = json.RawMessage(a.RawDefinitionByte)
        }
 
index d5baf78..99f35bc 100644 (file)
@@ -5,6 +5,8 @@ import (
        stdjson "encoding/json"
        "errors"
 
        stdjson "encoding/json"
        "errors"
 
+       "github.com/vapor/config"
+
        "github.com/vapor/common"
        "github.com/vapor/consensus"
        "github.com/vapor/encoding/json"
        "github.com/vapor/common"
        "github.com/vapor/consensus"
        "github.com/vapor/encoding/json"
@@ -249,3 +251,45 @@ func (a *voteOutputAction) Build(ctx context.Context, b *TemplateBuilder) error
 func (a *voteOutputAction) ActionType() string {
        return "vote_output"
 }
 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"
+}
index 5a0396f..01691eb 100644 (file)
@@ -353,6 +353,11 @@ func buildAnnotatedInput(tx *types.Tx, i uint32) *query.AnnotatedInput {
                in.Type = "spend"
                in.ControlProgram = orig.ControlProgram()
                in.SpentOutputID = e.SpentOutputId
                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
        }
 
        return in
index 61ac41f..e27e733 100644 (file)
@@ -24,7 +24,7 @@ func FederationProgrom(c *Config) []byte {
 
        control, err := vmutil.P2WSHProgram(scriptHash)
        if err != nil {
 
        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
        }
 
        return control
diff --git a/consensus/federation/federation.go b/consensus/federation/federation.go
new file mode 100644 (file)
index 0000000..f4555e1
--- /dev/null
@@ -0,0 +1,78 @@
+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()
+}
index 8303680..04343ee 100644 (file)
@@ -28,7 +28,7 @@ var _ = math.Inf
 const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
 
 type UtxoEntry struct {
 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"`
 }
        BlockHeight uint64 `protobuf:"varint,2,opt,name=blockHeight" json:"blockHeight,omitempty"`
        Spent       bool   `protobuf:"varint,3,opt,name=spent" json:"spent,omitempty"`
 }
@@ -38,11 +38,11 @@ func (m *UtxoEntry) String() string            { return proto.CompactTextString(
 func (*UtxoEntry) ProtoMessage()               {}
 func (*UtxoEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 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 {
        if m != nil {
-               return m.IsCoinBase
+               return m.Type
        }
        }
-       return false
+       return 0
 }
 
 func (m *UtxoEntry) GetBlockHeight() uint64 {
 }
 
 func (m *UtxoEntry) GetBlockHeight() uint64 {
@@ -66,15 +66,15 @@ func init() {
 func init() { proto.RegisterFile("storage.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
 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,
        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,
 }
 }
index 5e36b1c..24146ec 100644 (file)
@@ -3,7 +3,7 @@ option go_package = "storage";
 package chain.core.txdb.internal.storage;
 
 message UtxoEntry {
 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;
 }
 }
index 33637d4..b0edbdb 100644 (file)
@@ -1,9 +1,15 @@
 package storage
 
 package storage
 
+const (
+       NormalUTXOType uint32 = iota
+       CoinbaseUTXOType
+       CrosschainUTXOType
+)
+
 // NewUtxoEntry will create a new utxo entry
 // 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{
        return &UtxoEntry{
-               IsCoinBase:  isCoinBase,
+               Type:        utxoType,
                BlockHeight: blockHeight,
                Spent:       spent,
        }
                BlockHeight: blockHeight,
                Spent:       spent,
        }
index 8b1b443..e9d7527 100644 (file)
@@ -151,6 +151,7 @@ func TestLoadBlockIndexEquals(t *testing.T) {
                t.Errorf("got block index:%v, expect block index:%v", index, expectBlockIndex)
        }
 }
                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() {
 func TestSaveChainStatus(t *testing.T) {
        testDB := dbm.NewDB("testdb", "leveldb", "temp")
        defer func() {
@@ -163,9 +164,11 @@ func TestSaveChainStatus(t *testing.T) {
        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{
        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},
                },
        }
 
                },
        }
 
@@ -179,7 +182,10 @@ func TestSaveChainStatus(t *testing.T) {
        }
 
        for hash, utxo := range view.Entries {
        }
 
        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
                }
 
                        continue
                }
 
index f8576df..b4bfa45 100644 (file)
@@ -34,6 +34,25 @@ func getTransactionsUtxo(db dbm.DB, view *state.UtxoViewpoint, txs []*bc.Tx) err
 
                        view.Entries[prevout] = &utxo
                }
 
                        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
        }
 
        return nil
@@ -53,7 +72,12 @@ func getUtxo(db dbm.DB, hash *bc.Hash) (*storage.UtxoEntry, error) {
 
 func saveUtxoView(batch dbm.Batch, view *state.UtxoViewpoint) error {
        for key, entry := range view.Entries {
 
 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
                }
                        batch.Delete(calcUtxoKey(&key))
                        continue
                }
index 525624a..a59f07e 100644 (file)
@@ -23,22 +23,32 @@ func TestSaveUtxoView(t *testing.T) {
        }{
                {
                        hash:      bc.Hash{V0: 0},
        }{
                {
                        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},
                        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},
                        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},
                        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,
                },
        }
                        exist:     false,
                },
        }
@@ -74,7 +84,7 @@ func TestGetTransactionsUtxo(t *testing.T) {
        batch := testDB.NewBatch()
        inputView := state.NewUtxoViewpoint()
        for i := 0; i <= 2; i++ {
        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()
        }
        saveUtxoView(batch, inputView)
        batch.Write()
@@ -105,7 +115,7 @@ func TestGetTransactionsUtxo(t *testing.T) {
                        inputView: state.NewUtxoViewpoint(),
                        fetchView: &state.UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        err: false,
@@ -122,8 +132,8 @@ func TestGetTransactionsUtxo(t *testing.T) {
                        inputView: state.NewUtxoViewpoint(),
                        fetchView: &state.UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        err: false,
@@ -145,9 +155,9 @@ func TestGetTransactionsUtxo(t *testing.T) {
                        inputView: state.NewUtxoViewpoint(),
                        fetchView: &state.UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        err: false,
@@ -160,12 +170,12 @@ func TestGetTransactionsUtxo(t *testing.T) {
                        },
                        inputView: &state.UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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{
                                },
                        },
                        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,
                                },
                        },
                        err: false,
index 0ad7b6a..02b8078 100644 (file)
@@ -5,6 +5,12 @@ import (
        "encoding/json"
 )
 
        "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) {
 type HexBytes []byte
 
 func (h HexBytes) MarshalText() ([]byte, error) {
index 4d32a59..8f05938 100644 (file)
@@ -2,6 +2,7 @@ package node
 
 import (
        "context"
 
 import (
        "context"
+       "encoding/hex"
        "errors"
        "net"
        "net/http"
        "errors"
        "net"
        "net/http"
@@ -26,9 +27,9 @@ import (
        dbm "github.com/vapor/database/leveldb"
        "github.com/vapor/env"
        "github.com/vapor/event"
        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/net/websocket"
        "github.com/vapor/netsync"
+       "github.com/vapor/proposal/blockproposer"
        "github.com/vapor/protocol"
        w "github.com/vapor/wallet"
 )
        "github.com/vapor/protocol"
        w "github.com/vapor/wallet"
 )
@@ -59,12 +60,22 @@ type Node struct {
 // NewNode create bytom node
 func NewNode(config *cfg.Config) *Node {
        ctx := context.Background()
 // 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 := 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()))
        }
        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)
        initLogFile(config)
        initActiveNetParams(config)
        initCommonConfig(config)
index a01eea5..fd76ddd 100644 (file)
@@ -12,8 +12,9 @@ type Tx struct {
        Entries  map[Hash]Entry
        InputIDs []Hash // 1:1 correspondence with TxData.Inputs
 
        Entries  map[Hash]Entry
        InputIDs []Hash // 1:1 correspondence with TxData.Inputs
 
-       SpentOutputIDs []Hash
-       GasInputIDs    []Hash
+       SpentOutputIDs     []Hash
+       MainchainOutputIDs []Hash
+       GasInputIDs        []Hash
 }
 
 // SigHash ...
 }
 
 // SigHash ...
index 8d6a86b..1568119 100644 (file)
@@ -21,11 +21,13 @@ func MapTx(oldTx *TxData) *bc.Tx {
        }
 
        spentOutputIDs := make(map[bc.Hash]bool)
        }
 
        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
        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)
                        }
                        if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
                                tx.GasInputIDs = append(tx.GasInputIDs, id)
                        }
@@ -54,6 +56,9 @@ func MapTx(oldTx *TxData) *bc.Tx {
        for id := range spentOutputIDs {
                tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
        }
        for id := range spentOutputIDs {
                tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
        }
+       for id := range mainchainOutputIDs {
+               tx.MainchainOutputIDs = append(tx.MainchainOutputIDs, id)
+       }
        return tx
 }
 
        return tx
 }
 
@@ -127,13 +132,14 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash
                        spends = append(spends, spend)
 
                case *CrossChainInput:
                        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,
                        }
                        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
                        outputID := bc.EntryID(prevout)
                        crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, prog, uint64(i))
                        crossIn.WitnessArguments = inp.Arguments
@@ -143,7 +149,6 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash
                                Value: &inp.AssetAmount,
                        }
                        crossIns = append(crossIns, crossIn)
                                Value: &inp.AssetAmount,
                        }
                        crossIns = append(crossIns, crossIn)
-
                }
        }
 
                }
        }
 
index 383ea30..08e6f6c 100644 (file)
@@ -51,6 +51,8 @@ func (tx *Tx) SetInputArguments(n uint32, args [][]byte) {
        switch e := e.(type) {
        case *bc.Spend:
                e.WitnessArguments = args
        switch e := e.(type) {
        case *bc.Spend:
                e.WitnessArguments = args
+       case *bc.CrossChainInput:
+               e.WitnessArguments = args
        }
 }
 
        }
 }
 
index dca8b4d..cfb9417 100644 (file)
@@ -114,7 +114,7 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error {
        utxoView := state.NewUtxoViewpoint()
        voteResultMap := make(map[uint64]*state.VoteResult)
        irreversibleNode := c.bestIrreversibleNode
        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 {
        for _, detachNode := range detachNodes {
                b, err := c.store.GetBlock(&detachNode.Hash)
                if err != nil {
@@ -129,14 +129,16 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error {
                if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
                        return err
                }
                if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
                        return err
                }
+
                txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
                if 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 := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
                        return err
                }
-               
+
                if err := c.bbft.DetachBlock(voteResultMap, b); err != nil {
                        return err
                }
                if err := c.bbft.DetachBlock(voteResultMap, b); err != nil {
                        return err
                }
@@ -154,10 +156,12 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error {
                if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); 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
                }
                txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
                if err != nil {
                        return err
                }
+
                if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
                        return err
                }
                if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
                        return err
                }
@@ -269,7 +273,7 @@ func (c *Chain) processBlock(block *types.Block) (bool, error) {
        if block.Height <= c.bestIrreversibleNode.Height {
                return false, errors.New("the height of block below the height of irreversible block")
        }
        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")
        blockHash := block.Hash()
        if c.BlockExist(&blockHash) {
                log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
index 9eac945..183f95a 100644 (file)
@@ -81,6 +81,7 @@ func (c *Chain) initChainStatus() error {
        if err != nil {
                return err
        }
        if err != nil {
                return err
        }
+
        return c.store.SaveChainStatus(node, node, utxoView, map[uint64]*state.VoteResult{})
 }
 
        return c.store.SaveChainStatus(node, node, utxoView, map[uint64]*state.VoteResult{})
 }
 
index d105178..c807144 100644 (file)
@@ -20,6 +20,24 @@ func NewUtxoViewpoint() *UtxoViewpoint {
 }
 
 func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFail bool) error {
 }
 
 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)
        for _, prevout := range tx.SpentOutputIDs {
                assetID := bc.AssetID{}
                entryOutput, err := tx.Entry(prevout)
@@ -44,10 +62,13 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa
                if !ok {
                        return errors.New("fail to find utxo entry")
                }
                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.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()
                        return errors.New("coinbase utxo is not ready for use")
                }
                entry.SpendOutput()
@@ -74,11 +95,11 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa
                        continue
                }
 
                        continue
                }
 
-               isCoinbase := false
+               utxoType := storage.NormalUTXOType
                if block != nil && len(block.Transactions) > 0 && block.Transactions[0].ID == tx.ID {
                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
 }
        }
        return nil
 }
@@ -102,6 +123,24 @@ func (view *UtxoViewpoint) CanSpend(hash *bc.Hash) bool {
 }
 
 func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error {
 }
 
 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)
        for _, prevout := range tx.SpentOutputIDs {
                assetID := bc.AssetID{}
                entryOutput, err := tx.Entry(prevout)
@@ -123,11 +162,16 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error {
                }
 
                entry, ok := view.Entries[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 && !entry.Spent {
                        return errors.New("try to revert an unspent utxo")
                }
+
                if !ok {
                if !ok {
-                       view.Entries[prevout] = storage.NewUtxoEntry(false, 0, false)
+                       view.Entries[prevout] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, false)
                        continue
                }
                entry.UnspendOutput()
                        continue
                }
                entry.UnspendOutput()
@@ -154,7 +198,7 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error {
                        continue
                }
 
                        continue
                }
 
-               view.Entries[*id] = storage.NewUtxoEntry(false, 0, true)
+               view.Entries[*id] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, true)
        }
        return nil
 }
        }
        return nil
 }
index db96d84..cf4935f 100644 (file)
@@ -61,7 +61,7 @@ func TestApplyBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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(),
                                },
                        },
                        fetchView: NewUtxoViewpoint(),
@@ -101,7 +101,7 @@ func TestApplyBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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,
                                },
                        },
                        err: true,
@@ -125,12 +125,12 @@ func TestApplyBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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{
                                },
                        },
                        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,
                                },
                        },
                        err: false,
@@ -155,12 +155,12 @@ func TestApplyBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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{
                                },
                        },
                        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,
                                },
                        },
                        err: false,
@@ -185,12 +185,12 @@ func TestApplyBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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{
                                },
                        },
                        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,
                                },
                        },
                        err: true,
@@ -216,7 +216,7 @@ func TestApplyBlock(t *testing.T) {
                        inputView: NewUtxoViewpoint(),
                        fetchView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        err: false,
@@ -242,14 +242,14 @@ func TestApplyBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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{
                                },
                        },
                        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,
                                },
                        },
                        gasOnlyTx: true,
@@ -277,7 +277,7 @@ func TestApplyBlock(t *testing.T) {
                        inputView: NewUtxoViewpoint(),
                        fetchView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        gasOnlyTx: true,
@@ -327,7 +327,7 @@ func TestDetachBlock(t *testing.T) {
                        inputView: NewUtxoViewpoint(),
                        fetchView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        err: false,
@@ -352,7 +352,7 @@ func TestDetachBlock(t *testing.T) {
                        inputView: NewUtxoViewpoint(),
                        fetchView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        err: false,
@@ -376,7 +376,7 @@ func TestDetachBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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,
                                },
                        },
                        err: true,
@@ -400,12 +400,12 @@ func TestDetachBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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{
                                },
                        },
                        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,
                                },
                        },
                        err: false,
@@ -430,14 +430,14 @@ func TestDetachBlock(t *testing.T) {
                        },
                        inputView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        },
                        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{
                                },
                        },
                        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,
                                },
                        },
                        gasOnlyTx: true,
@@ -464,7 +464,7 @@ func TestDetachBlock(t *testing.T) {
                        inputView: NewUtxoViewpoint(),
                        fetchView: &UtxoViewpoint{
                                Entries: map[bc.Hash]*storage.UtxoEntry{
                        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,
                                },
                        },
                        gasOnlyTx: true,
index a9e4583..c389133 100644 (file)
@@ -120,7 +120,9 @@ func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)
 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) 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 *mockStore) SaveChainNodeStatus(*state.BlockNode, *state.BlockNode) error { return nil }
 
 func TestAddOrphan(t *testing.T) {
@@ -657,16 +659,19 @@ func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error)
 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 {
 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 {
        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
 }
        }
        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) {
 func (s *mockStore1) SaveChainNodeStatus(*state.BlockNode, *state.BlockNode) error { return nil }
 
 func TestProcessTransaction(t *testing.T) {
index 610a8eb..37cbd5c 100644 (file)
@@ -34,6 +34,7 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args
                        destPos = &e.WitnessDestination.Position
                        s := e.SpentOutputId.Bytes()
                        spentOutputID = &s
                        destPos = &e.WitnessDestination.Position
                        s := e.SpentOutputId.Bytes()
                        spentOutputID = &s
+
                case *bc.VoteOutput:
                        a1 := spentOutput.Source.Value.AssetId.Bytes()
                        assetID = &a1
                case *bc.VoteOutput:
                        a1 := spentOutput.Source.Value.AssetId.Bytes()
                        assetID = &a1
index f5f7783..dad704b 100644 (file)
@@ -127,7 +127,7 @@ func GenerateChainData(dirPath string, testDB dbm.DB, txNumber, otherAssetNum in
 
        // init UtxoViewpoint
        utxoView := state.NewUtxoViewpoint()
 
        // 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
        for _, tx := range txs {
                for _, id := range tx.SpentOutputIDs {
                        utxoView.Entries[id] = utxoEntry
index 443f788..9181053 100644 (file)
@@ -62,13 +62,26 @@ func (ctx *chainTestContext) validateStatus(block *types.Block) error {
 
 func (ctx *chainTestContext) validateExecution(block *types.Block) error {
        for _, tx := range block.Transactions {
 
 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
                        }
                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")
                        }
                        if !utxoEntry.Spent {
                                return fmt.Errorf("utxo entry status should be spent")
index 77d7f36..ac7cfff 100644 (file)
@@ -29,7 +29,7 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                {
                        desc:   "coinbase tx",
                        before: make(map[bc.Hash]*storage.UtxoEntry),
                {
                        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),
                        },
                        attachBlock: []*bc.Block{
                                types.MapBlock(&mockBlocks[0].Block),
                        },
@@ -42,14 +42,14 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                {
                        desc: "Chain trading 3",
                        before: map[bc.Hash]*storage.UtxoEntry{
                {
                        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{
                        },
                        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),
                        },
                        attachBlock: []*bc.Block{
                                types.MapBlock(&mockBlocks[1].Block),
@@ -66,17 +66,17 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                {
                        desc: "detach 1 block, attach 2 block",
                        before: map[bc.Hash]*storage.UtxoEntry{
                {
                        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{
                        },
                        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),
                        },
                        attachBlock: []*bc.Block{
                                types.MapBlock(&mockBlocks[3].Block),
@@ -105,68 +105,68 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                {
                        desc: "detach block 5, attach block 2",
                        before: map[bc.Hash]*storage.UtxoEntry{
                {
                        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{
                        },
                        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),
                        },
                        attachBlock: []*bc.Block{
                                types.MapBlock(&mockBlocks[10].Block),
@@ -226,70 +226,70 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                {
                        desc: "detach block 5, attach block 2. Other asset deals failed.",
                        before: map[bc.Hash]*storage.UtxoEntry{
                {
                        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{
 
                        },
                        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),
                        },
                        attachBlock: []*bc.Block{
                                types.MapBlock(&mockBlocks[10].Block),
@@ -349,20 +349,20 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                        desc: "detach block 2, attach block 1. Chain trading",
                        before: map[bc.Hash]*storage.UtxoEntry{
                                // coinbase tx
                        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{
                        },
                        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),
                        },
                        attachBlock: []*bc.Block{
                                types.MapBlock(&mockBlocks[14].Block),
index 4d25ce8..5696e34 100644 (file)
@@ -138,12 +138,6 @@ func getAccountFromACP(program []byte, walletDB dbm.DB) (*account.Account, error
 
 var emptyJSONObject = json.RawMessage(`{}`)
 
 
 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,
 func (w *Wallet) buildAnnotatedTransaction(orig *types.Tx, b *types.Block, statusFail bool, indexInBlock int) *query.AnnotatedTx {
        tx := &query.AnnotatedTx{
                ID:                     orig.ID,
@@ -181,6 +175,16 @@ func (w *Wallet) BuildAnnotatedInput(tx *types.Tx, i uint32) *query.AnnotatedInp
        in.InputID = id
        e := tx.Entries[id]
        switch e := e.(type) {
        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()
        case *bc.Spend:
                in.Type = "spend"
                in.ControlProgram = orig.ControlProgram()
@@ -190,6 +194,7 @@ func (w *Wallet) BuildAnnotatedInput(tx *types.Tx, i uint32) *query.AnnotatedInp
                for _, arg := range arguments {
                        in.WitnessArguments = append(in.WitnessArguments, arg)
                }
                for _, arg := range arguments {
                        in.WitnessArguments = append(in.WitnessArguments, arg)
                }
+
        case *bc.Coinbase:
                in.Type = "coinbase"
                in.Arbitrary = e.Arbitrary
        case *bc.Coinbase:
                in.Type = "coinbase"
                in.Arbitrary = e.Arbitrary
index ddf7248..f3b7d57 100644 (file)
@@ -9,6 +9,7 @@ import (
        log "github.com/sirupsen/logrus"
 
        "github.com/vapor/account"
        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"
        "github.com/vapor/blockchain/query"
        "github.com/vapor/crypto/sha3pool"
        dbm "github.com/vapor/database/leveldb"
@@ -86,8 +87,13 @@ func saveExternalAssetDefinition(b *types.Block, walletDB dbm.DB) {
        defer storeBatch.Write()
 
        for _, tx := range b.Transactions {
        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)
+                               }
+                       }
                }
        }
 }
                }
        }
 }
index c5d106c..77c956c 100644 (file)
@@ -261,7 +261,7 @@ func txOutToUtxos(tx *types.Tx, statusFail bool, vaildHeight uint64) []*account.
                        }
 
                default:
                        }
 
                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
                }
 
                        continue
                }
 
index 5f9928d..e5fb1b8 100644 (file)
@@ -672,8 +672,7 @@ func TestTxOutToUtxos(t *testing.T) {
                        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")),
                        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}),
                                Outputs: []*types.TxOutput{
                                        types.NewIntraChainOutput(bc.AssetID{V0: 1}, 2, []byte{0x51}),
                                        types.NewIntraChainOutput(bc.AssetID{V0: 1}, 3, []byte{0x52}),
@@ -685,35 +684,35 @@ func TestTxOutToUtxos(t *testing.T) {
                        vaildHeight: 0,
                        wantUtxos: []*account.UTXO{
                                &account.UTXO{
                        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},
                                        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{
                                        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},
                                        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{
                                        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},
                                        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{
                                        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},
                                        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,
                                },
                        },
                                        SourcePos:      3,
                                },
                        },