package utxo_view

import (
	"encoding/hex"

	"github.com/vapor/consensus"
	"github.com/vapor/protocol/bc"
	"github.com/vapor/protocol/bc/types"
	"github.com/vapor/testutil"
)

const utxoPreFix = "UT:"

func calcUtxoKey(hash *bc.Hash) []byte {
	return []byte(utxoPreFix + hash.String())
}

type tx struct {
	Tx *types.Tx
}

func newTx(t *types.Tx) *tx {
	return &tx{
		Tx: t,
	}
}

func (t *tx) getSourceID(outIndex int) *bc.Hash {
	output := t.Tx.Entries[*t.Tx.OutputID(outIndex)].(*bc.IntraChainOutput)
	return output.Source.Ref
}

func (t *tx) getAmount(outIndex int) uint64 {
	output := t.Tx.Entries[*t.Tx.OutputID(outIndex)].(*bc.IntraChainOutput)
	return output.Source.Value.Amount
}

func (t *tx) getSpentOutputID(index int) bc.Hash {
	input, err := t.Tx.Spend(t.Tx.InputIDs[index])
	if err != nil {
		panic(err)
	}

	return *input.SpentOutputId
}

func (t *tx) OutputHash(outIndex int) *bc.Hash {
	return t.Tx.ResultIds[outIndex]
}

func mustDecodeHex(str string) []byte {
	data, err := hex.DecodeString(str)
	if err != nil {
		panic(err)
	}
	return data
}

func coinBaseTx(amount uint64, arbitrary string) *types.Tx {
	return types.NewTx(types.TxData{
		Inputs: []*types.TxInput{
			types.NewCoinbaseInput([]byte(arbitrary)),
		},
		Outputs: []*types.TxOutput{
			types.NewIntraChainOutput(*consensus.BTMAssetID, amount, mustDecodeHex("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
		},
	})
}

var mockTransaction = []*tx{}
var mockBlocks = []*block{}

func toHash(hash string) bc.Hash {
	sourceID := bc.Hash{}
	sourceID.UnmarshalText([]byte(hash))
	return sourceID
}

func toAssetID(assetID string) bc.AssetID {
	asset := bc.AssetID{}
	if err := asset.UnmarshalText([]byte(assetID)); err != nil {
		panic(err)
	}
	return asset
}

type block struct {
	types.Block
}

func init() {
	// 0
	mockTransaction = []*tx{}
	t := &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817414d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 41250000000, 0, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("00148c704747e94387fa0b8712b053ed2132d84820ac")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 41150000000, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 1
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[0].getSourceID(1), *consensus.BTMAssetID, 41150000000, 1, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("00148c704747e94387fa0b8712b053ed2132d84820ac")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 41050000000, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 2
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[1].getSourceID(1), *consensus.BTMAssetID, 41050000000, 1, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("00148c704747e94387fa0b8712b053ed2132d84820ac")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40950000000, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 3: 00140b0c5059514c751a80c4e1c94f8ecfe16d80671b -> 0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e
	assetID := toAssetID("5c3b60753fe1f8321298d64ab3881b200fa1d7e56f1b2a2df587233c532c5eb6")
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("453936067da4be89a99bbd78aa8c7eb88cbe92ae0941e1013a58b8d6af65d344"), *consensus.BTMAssetID, 41250000000, 0, []byte("00140b0c5059514c751a80c4e1c94f8ecfe16d80671b")),
				types.NewSpendInput(nil, toHash("50d1c966b3a58f9092a696136a75ceb801ea7da2470784d80ebf3f17a76b8a98"), assetID, 800000000000, 0, []byte("00140b0c5059514c751a80c4e1c94f8ecfe16d80671b")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 41150000000, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("00140b0c5059514c751a80c4e1c94f8ecfe16d80671b")),
				types.NewIntraChainOutput(assetID, 700000000000, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
				types.NewIntraChainOutput(assetID, 100000000000, []byte("00140b0c5059514c751a80c4e1c94f8ecfe16d80671b")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 4
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817514d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 41250000000, 0, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
				types.NewSpendInput(nil, toHash("d9a9b64e4f842060a40b15325d9aae61987776f7748e7e6a2887a474e84294ef"), assetID, 600000000000, 0, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 41150000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
				types.NewIntraChainOutput(assetID, 600000000000, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
				types.NewIntraChainOutput(assetID, 400000000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 5: 0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e -> 00142b248deeffe82f9cd94fab43849468e0dfe97806
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817514d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 41150000000, 1, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
				types.NewSpendInput(nil, toHash("466e6a9261d7b51f227d6c05b7cd3cc36487cc6f0cfb79c58794021e68d4c877"), assetID, 300000000000, 0, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 41050000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
				types.NewIntraChainOutput(assetID, 200000000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
				types.NewIntraChainOutput(assetID, 100000000000, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	//6: 00142b248deeffe82f9cd94fab43849468e0dfe97806 -> 0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817514d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 41050000000, 2, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
				types.NewSpendInput(nil, toHash("e5757774fb46287ebda3479e19c8643d2fcdb5de3b1ac84d4020c1971bb3f531"), assetID, 100000000000, 0, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40950000000, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
				types.NewIntraChainOutput(assetID, 50000000000, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
				types.NewIntraChainOutput(assetID, 50000000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 7: 0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce -> 0014e3bb841fb722d1840a959d86e12a174c54a3a6e8
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817514d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 40950000000, 3, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40850000000, []byte("0014e3bb841fb722d1840a959d86e12a174c54a3a6e8")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 8: 0014e3bb841fb722d1840a959d86e12a174c54a3a6e8 -> 001449601d4cfb6e7a1b990778497b3c364f66bc17d2
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817514d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 40850000000, 4, []byte("0014e3bb841fb722d1840a959d86e12a174c54a3a6e8")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40750000000, []byte("001449601d4cfb6e7a1b990778497b3c364f66bc17d2")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014e3bb841fb722d1840a959d86e12a174c54a3a6e8")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 9: 001449601d4cfb6e7a1b990778497b3c364f66bc17d2 -> 0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817514d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 40750000000, 5, []byte("001449601d4cfb6e7a1b990778497b3c364f66bc17d2")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40650000000, []byte("0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("001449601d4cfb6e7a1b990778497b3c364f66bc17d2")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 10: 0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b -> 0014e809cb6f328db1e624821dec508cbe08fe1ed08d
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817514d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 40650000000, 6, []byte("0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40550000000, []byte("0014e809cb6f328db1e624821dec508cbe08fe1ed08d")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// Chain trading
	// 11: 0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e -> 00142b248deeffe82f9cd94fab43849468e0dfe97806
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[3].getSourceID(0), *consensus.BTMAssetID, 41150000000, 0, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 41050000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014b103d8f2dc10e7bbbe2557ff8b9876524dec0a7e")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	//12: 00142b248deeffe82f9cd94fab43849468e0dfe97806 -> 0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[11].getSourceID(0), *consensus.BTMAssetID, 41050000000, 0, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40950000000, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("00142b248deeffe82f9cd94fab43849468e0dfe97806")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 13: 0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce -> 0014e3bb841fb722d1840a959d86e12a174c54a3a6e8
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[12].getSourceID(0), *consensus.BTMAssetID, 40950000000, 0, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40850000000, []byte("0014e3bb841fb722d1840a959d86e12a174c54a3a6e8")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014492d5b0f09f83bd9bff6a44514dcc9b11c091dce")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 14: 0014e3bb841fb722d1840a959d86e12a174c54a3a6e8 -> 001449601d4cfb6e7a1b990778497b3c364f66bc17d2
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[13].getSourceID(0), *consensus.BTMAssetID, 40850000000, 0, []byte("0014e3bb841fb722d1840a959d86e12a174c54a3a6e8")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40750000000, []byte("001449601d4cfb6e7a1b990778497b3c364f66bc17d2")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014e3bb841fb722d1840a959d86e12a174c54a3a6e8")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 15: 001449601d4cfb6e7a1b990778497b3c364f66bc17d2 -> 0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[14].getSourceID(0), *consensus.BTMAssetID, 40750000000, 0, []byte("001449601d4cfb6e7a1b990778497b3c364f66bc17d2")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40650000000, []byte("0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("001449601d4cfb6e7a1b990778497b3c364f66bc17d2")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	// 16: 0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b -> 0014e809cb6f328db1e624821dec508cbe08fe1ed08d
	t = &tx{
		Tx: types.NewTx(types.TxData{
			Inputs: []*types.TxInput{
				types.NewSpendInput(nil, *mockTransaction[15].getSourceID(0), *consensus.BTMAssetID, 40650000000, 0, []byte("0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b")),
			},
			Outputs: []*types.TxOutput{
				types.NewIntraChainOutput(*consensus.BTMAssetID, 40550000000, []byte("0014e809cb6f328db1e624821dec508cbe08fe1ed08d")),
				types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte("0014bd3d70b1bcd62ece61c06a2fe097a4732e5f006b")),
			},
		}),
	}
	mockTransaction = append(mockTransaction, t)

	mockBlocks = []*block{
		// coinbase tx
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            100,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block0"),
			},
		}},

		// Chain trading 3
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            101,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block1"),
				mockTransaction[0].Tx,
				mockTransaction[1].Tx,
				mockTransaction[2].Tx,
			},
		}},

		// detach block 1, attach block 2
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            102,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block2"),
				mockTransaction[0].Tx,
			},
		}},

		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            102,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block3"),
				mockTransaction[0].Tx,
			},
		}},

		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            103,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block4"),
				mockTransaction[1].Tx,
			},
		}},

		// detach block 5, attach block 2
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            104,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block5"),
				mockTransaction[2].Tx,
			},
		}},
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            105,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block6"),
				mockTransaction[3].Tx,
				mockTransaction[4].Tx,
			},
		}},
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            106,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block7"),
				mockTransaction[5].Tx,
			},
		}},
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            107,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block8"),
				mockTransaction[6].Tx,
				mockTransaction[7].Tx,
				mockTransaction[8].Tx,
			},
		}},
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            108,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block9"),
				mockTransaction[9].Tx,
			},
		}},

		// detach block 5, attach block 2. Chain trading
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            105,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block10"),
				mockTransaction[2].Tx,
				mockTransaction[3].Tx,
				mockTransaction[4].Tx,
				mockTransaction[5].Tx,
				mockTransaction[6].Tx,
			},
		}},

		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            105,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block11"),
				mockTransaction[7].Tx,
				mockTransaction[8].Tx,
				mockTransaction[9].Tx,
			},
		}},

		// detach block 2, attach block 1. Chain trading
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            106,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block12"),
				mockTransaction[11].Tx,
				mockTransaction[12].Tx,
				mockTransaction[13].Tx,
				mockTransaction[14].Tx,
			},
		}},
		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            107,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block13"),
				mockTransaction[15].Tx,
				mockTransaction[16].Tx,
			},
		}},

		&block{Block: types.Block{
			BlockHeader: types.BlockHeader{
				Height:            106,
				PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
				Timestamp:         1522908275000,
			},
			Transactions: []*types.Tx{
				coinBaseTx(41250000000, "arbitrary block14"),
			},
		}},
	}

}
