Ejemplo n.º 1
0
Archivo: blks.go Proyecto: wchh/gocoin
func (c *one_net_conn) block(d []byte) {
	atomic.AddUint64(&DlBytesDownloaded, uint64(len(d)))

	BlocksMutex.Lock()
	defer BlocksMutex.Unlock()
	h := btc.NewSha2Hash(d[:80])

	c.Lock()
	c.last_blk_rcvd = time.Now()
	c.Unlock()

	bip := BlocksInProgress[h.Hash]
	if bip == nil || !bip.Conns[c.id] {
		COUNTER("BNOT")
		//fmt.Println(h.String(), "- already received", bip)
		return
	}
	//fmt.Println(h.String(), "- new", bip.Height)
	COUNTER("BYES")

	delete(bip.Conns, c.id)
	c.Lock()
	c.inprogress--
	c.Unlock()
	blocksize_update(len(d))

	bl, er := btc.NewBlock(d)
	if er != nil {
		fmt.Println(c.Ip(), "-", er.Error())
		c.setbroken(true)
		return
	}

	bl.BuildTxList()
	if !bytes.Equal(btc.GetMerkel(bl.Txs), bl.MerkleRoot()) {
		fmt.Println(c.Ip(), " - MerkleRoot mismatch at block", bip.Height)
		c.setbroken(true)
		return
	}

	delete(BlocksToGet, bip.Height)
	delete(BlocksInProgress, h.Hash)
	if len(BlocksInProgress) == 0 {
		EmptyInProgressCnt++
	}

	//println("got-", bip.Height, BlocksComplete+1)
	if BlocksComplete+1 == bip.Height {
		BlocksComplete++
		BlockQueue <- bl
		for {
			bl = BlocksCached[BlocksComplete+1]
			if bl == nil {
				break
			}
			BlocksComplete++
			delete(BlocksCached, BlocksComplete)
			BlocksCachedSize -= uint64(len(bl.Raw))
			BlockQueue <- bl
		}
	} else {
		BlocksCached[bip.Height] = bl
		BlocksCachedSize += uint64(len(d))
	}
}
Ejemplo n.º 2
0
func (ch *Chain) CheckBlock(bl *btc.Block) (er error, dos bool, maybelater bool) {
	// Size limits
	if len(bl.Raw) < 81 || len(bl.Raw) > btc.MAX_BLOCK_SIZE {
		er = errors.New("CheckBlock() : size limits failed")
		dos = true
		return
	}

	if bl.Version() == 0 {
		er = errors.New("CheckBlock() : Block version 0 not allowed")
		dos = true
		return
	}

	// Check timestamp (must not be higher than now +2 hours)
	if int64(bl.BlockTime()) > time.Now().Unix()+2*60*60 {
		er = errors.New("CheckBlock() : block timestamp too far in the future")
		dos = true
		return
	}

	if prv, pres := ch.BlockIndex[bl.Hash.BIdx()]; pres {
		if prv.Parent == nil {
			// This is genesis block
			er = errors.New("Genesis")
			return
		} else {
			er = errors.New("CheckBlock: " + bl.Hash.String() + " already in")
			return
		}
	}

	prevblk, ok := ch.BlockIndex[btc.NewUint256(bl.ParentHash()).BIdx()]
	if !ok {
		er = errors.New("CheckBlock: " + bl.Hash.String() + " parent not found")
		maybelater = true
		return
	}

	height := prevblk.Height + 1

	// Reject the block if it reaches into the chain deeper than our unwind buffer
	if prevblk != ch.BlockTreeEnd && int(ch.BlockTreeEnd.Height)-int(height) >= MovingCheckopintDepth {
		er = errors.New(fmt.Sprint("CheckBlock: btc.Block ", bl.Hash.String(),
			" hooks too deep into the chain: ", height, "/", ch.BlockTreeEnd.Height, " ",
			btc.NewUint256(bl.ParentHash()).String()))
		return
	}

	// Check proof of work
	gnwr := ch.GetNextWorkRequired(prevblk, bl.BlockTime())
	if bl.Bits() != gnwr {
		println("AcceptBlock() : incorrect proof of work ", bl.Bits, " at block", height, " exp:", gnwr)

		// Here is a "solution" for whatever shit there is in testnet3, that nobody can explain me:
		if !ch.testnet() || (height%2016) != 0 {
			er = errors.New("CheckBlock: incorrect proof of work")
			dos = true
			return
		}
	}

	// Count block versions within the Majority Window
	var majority_v2, majority_v3 uint
	n := prevblk
	for cnt := uint(0); cnt < ch.Consensus.Window && n != nil; cnt++ {
		ver := binary.LittleEndian.Uint32(n.BlockHeader[0:4])
		if ver >= 2 {
			majority_v2++
			if ver >= 3 {
				majority_v3++
			}
		}
		n = n.Parent
	}

	if bl.Version() < 2 && majority_v2 >= ch.Consensus.RejectBlock {
		er = errors.New("CheckBlock() : Rejected nVersion=1 block")
		dos = true
		return
	}

	if bl.Version() < 3 && majority_v3 >= ch.Consensus.RejectBlock {
		er = errors.New("CheckBlock() : Rejected nVersion=2 block")
		dos = true
		return
	}

	if bl.Txs == nil {
		er = bl.BuildTxList()
		if er != nil {
			dos = true
			return
		}
	}

	if !bl.Trusted {
		if bl.Version() >= 2 && majority_v2 >= ch.Consensus.EnforceUpgrade {
			var exp []byte
			if height >= 0x800000 {
				if height >= 0x80000000 {
					exp = []byte{5, byte(height), byte(height >> 8), byte(height >> 16), byte(height >> 24), 0}
				} else {
					exp = []byte{4, byte(height), byte(height >> 8), byte(height >> 16), byte(height >> 24)}
				}
			} else {
				exp = []byte{3, byte(height), byte(height >> 8), byte(height >> 16)}
			}
			if len(bl.Txs[0].TxIn[0].ScriptSig) < len(exp) || !bytes.Equal(exp, bl.Txs[0].TxIn[0].ScriptSig[:len(exp)]) {
				er = errors.New("CheckBlock() : Unexpected block number in coinbase: " + bl.Hash.String())
				dos = true
				return
			}
		}

		// This is a stupid check, but well, we need to be satoshi compatible
		if len(bl.Txs) == 0 || !bl.Txs[0].IsCoinBase() {
			er = errors.New("CheckBlock() : first tx is not coinbase: " + bl.Hash.String())
			dos = true
			return
		}

		// Check Merkle Root - that's importnant
		if !bytes.Equal(btc.GetMerkel(bl.Txs), bl.MerkleRoot()) {
			er = errors.New("CheckBlock() : Merkle Root mismatch")
			dos = true
			return
		}

		// Check transactions - this is the most time consuming task
		if !CheckTransactions(bl.Txs, height, bl.BlockTime()) {
			er = errors.New("CheckBlock() : CheckTransactions() failed")
			dos = true
			return
		}
	}

	if bl.BlockTime() >= BIP16SwitchTime {
		bl.VerifyFlags = script.VER_P2SH
	} else {
		bl.VerifyFlags = 0
	}

	if majority_v3 >= ch.Consensus.EnforceUpgrade {
		bl.VerifyFlags |= script.VER_DERSIG
	}

	return
}