package tests import ( "crypto/sha256" "encoding/hex" "kerma/models" "testing" "time" "github.com/docker/go/canonical/json" . "github.com/smartystreets/goconvey/convey" ) func TestBlock(t *testing.T) { Convey("Given a new block", t, func() { previd := "00000000a420b7cefa2b7730243316921ed59ffe836e111ca3801f82a4f5360e" txid := "1bb37b637d07100cd26fc063dfd4c39a7931cc88dae3417871219715a5e374af" block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: 1649827795114, Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "svatsan", Note: "First block. Yayy, I have 50 bu now!!", } Convey("When GetType is called, 'block' should be returned", func() { So(block.GetType(), ShouldEqual, "block") }) Convey("When GetEntity is called, the block should be returned", func() { So(block.GetEntity(), ShouldResemble, &block) }) Convey("When Validate is called, no error should be returned", func() { So(block.Validate(), ShouldEqual, nil) }) Convey("When ContainsTransaction is called with a correct id, 'true' should be returned", func() { So(block.ContainsTransaction(txid), ShouldEqual, true) }) Convey("When ContainsTransaction is called with an incorrect id, 'false' should be returned", func() { So(block.ContainsTransaction("123"), ShouldEqual, false) }) Convey("When Hash is called, the hash of the cannonical json and no error should be returned", func() { blockJSON, _ := json.MarshalCanonical(block) hashSum := sha256.Sum256(blockJSON) res, err := block.Hash() So(hex.EncodeToString(hashSum[:]), ShouldEqual, res) So(err, ShouldEqual, nil) }) }) Convey("Given the genesis block", t, func() { block := models.GetGenesisBlock() gid := "00000000a420b7cefa2b7730243316921ed59ffe836e111ca3801f82a4f5360e" Convey("When GetID is called, the block id should be correct", func() { bid := block.GetID() So(bid, ShouldEqual, gid) }) Convey("When Validate is called, no error should be returned", func() { So(block.Validate(), ShouldBeNil) }) }) Convey("Given a new incorrect block", t, func() { previd := "00000000a420b7cefa2b7730243316921ed59ffe836e111ca3801f82a4f5360e" txid := "1bb37b637d07100cd26fc063dfd4c39a7931cc88dae3417871219715a5e374af" Convey("When the block is a genesis", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: nil, Created: 1649827795114, Target: "reallyillegalgenesisblock", Miner: "svatsan", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "illegal genesis block detected") }) }) Convey("With an incorrect genesis", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: 1649827795114, Target: "reallyillegalgenesisblock", Miner: "svatsan", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "incorrect target supplied") }) }) Convey("With a timestamp before genesis", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: 0, Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "svatsan", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "timestamp before genesis block") }) }) Convey("With a timestamp in the future", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: time.Now().UnixMilli() + 10000000, Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "svatsan", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "block created in the future") }) }) Convey("With a miner that is a non-ASCII printible string", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: time.Now().UnixMilli(), Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "Not@nħCIIStrIng", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "miner is not an ascii printable string") }) }) Convey("With a miner that is more than 128 characters long", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: time.Now().UnixMilli(), Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "LongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongMinerName", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "miner length incorrect") }) }) Convey("With a note that is a non-ASCII printible string", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: time.Now().UnixMilli(), Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "", Note: "Not@nħCIIStrIng", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "note is not an ascii printable string") }) }) Convey("With a note that is more than 128 characters long", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: time.Now().UnixMilli(), Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "", Note: "LongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongNote", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldEqual, "note length incorrect") }) }) Convey("With a non-hex encoded nonce", func() { block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "AReallyIncorrectNonce", Previd: &previd, Created: time.Now().UnixMilli(), Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldNotBeNil) }) }) Convey("With a non-hex encoded previd", func() { incorrectPrevId := "incorrectprevid" block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &incorrectPrevId, Created: time.Now().UnixMilli(), Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "", Note: "", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldNotBeNil) }) }) Convey("With an incorrect proof-of-work equation", func() { previd := "00000000a420b7cefa2b7730243316921ed59ffe836e111ca3801f82a4f5360e" txid := "1bb37b637d07100cd26fc063dfd4c39a7931cc88dae3417871219715a5e37412" block := models.Block{ Type: "block", Txids: []string{ txid, }, Nonce: "c5ee71be4ca85b160d352923a84f86f44b7fc4fe60002214bc1236ceedc5c615", Previd: &previd, Created: 1649827795114, Target: "00000002af000000000000000000000000000000000000000000000000000000", Miner: "svatsan", Note: "First block. Yayy, I have 50 bu now!!", } Convey("When Validate is called, an error should be returned", func() { So(block.Validate().Error(), ShouldNotBeNil) }) }) }) }