CheckAndPushNewBlock implements ChainRPCServer.CheckAndPushNewBlock.
(block *types.Block)
| 930 | |
| 931 | // CheckAndPushNewBlock implements ChainRPCServer.CheckAndPushNewBlock. |
| 932 | func (c *Chain) CheckAndPushNewBlock(block *types.Block) (err error) { |
| 933 | height := c.rt.getHeightFromTime(block.Timestamp()) |
| 934 | head := c.rt.getHead() |
| 935 | peers := c.rt.getPeers() |
| 936 | total := int32(len(peers.Servers)) |
| 937 | next := func() int32 { |
| 938 | if total > 0 { |
| 939 | return (c.rt.getNextTurn() - 1) % total |
| 940 | } |
| 941 | return -1 |
| 942 | }() |
| 943 | le := c.logEntryWithHeadState().WithFields(log.Fields{ |
| 944 | "block": block.BlockHash().String(), |
| 945 | "producer": block.Producer(), |
| 946 | "blocktime": block.Timestamp().Format(time.RFC3339Nano), |
| 947 | "blockheight": height, |
| 948 | "blockparent": block.ParentHash().String(), |
| 949 | }) |
| 950 | le.Debug("checking new block from other peer") |
| 951 | |
| 952 | if head.Height == height && head.Head.IsEqual(block.BlockHash()) { |
| 953 | // Maybe already set by FetchBlock |
| 954 | return nil |
| 955 | } else if !block.ParentHash().IsEqual(&head.Head) { |
| 956 | err = ErrInvalidBlock |
| 957 | le.WithError(err).Error("invalid new block for the current chain") |
| 958 | return ErrInvalidBlock |
| 959 | } |
| 960 | |
| 961 | // Verify block signatures |
| 962 | if err = block.Verify(); err != nil { |
| 963 | le.WithError(err).Error("failed to verify block") |
| 964 | return |
| 965 | } |
| 966 | |
| 967 | // Short circuit the checking process if it's a self-produced block |
| 968 | if block.Producer() == c.rt.server { |
| 969 | return c.pushBlock(block) |
| 970 | } |
| 971 | // Check block producer |
| 972 | index, found := peers.Find(block.Producer()) |
| 973 | if !found { |
| 974 | err = ErrUnknownProducer |
| 975 | le.WithError(err).Error("unknown producer of new block") |
| 976 | return ErrUnknownProducer |
| 977 | } |
| 978 | |
| 979 | if index != next { |
| 980 | err = ErrInvalidProducer |
| 981 | le.WithFields(log.Fields{ |
| 982 | "expected": next, |
| 983 | "actual": index, |
| 984 | }).WithError(err).Error("invalid producer of new block") |
| 985 | return |
| 986 | } |
| 987 | |
| 988 | // TODO(leventeliu): check if too many periods are skipped or store block for future use. |
| 989 | // if height-c.rt.getHead().Height > X { |
no test coverage detected