Example #1
0
        private Snapshot Apply(Snapshot original, List <BlockHeader> headers, ulong epoch)
        {
            // Allow passing in no headers for cleaner code
            if (headers.Count == 0)
            {
                return(original);
            }

            // Sanity check that the headers can be applied
            for (int i = 0; i < headers.Count - 1; i++)
            {
                if (headers[i].Number != original.Number + i + 1)
                {
                    throw new InvalidOperationException("Invalid voting chain");
                }
            }

            // Iterate through the headers and create a new snapshot
            Snapshot snapshot = (Snapshot)original.Clone();

            foreach (BlockHeader header in headers)
            {
                // Remove any votes on checkpoint blocks
                long number = header.Number;
                if ((ulong)number % epoch == 0)
                {
                    snapshot.Votes.Clear();
                    snapshot.Tally.Clear();
                }

                // Resolve the authorization key and check against signers
                Address signer = header.Author;
                if (!snapshot.Signers.ContainsKey(signer))
                {
                    throw new InvalidOperationException("Unauthorized signer");
                }
                if (HasSignedRecently(snapshot, number, signer))
                {
                    throw new InvalidOperationException($"Recently signed (trying to sign {number} when last signed {snapshot.Signers[signer]} with {snapshot.Signers.Count} signers)");
                }

                snapshot.Signers[signer] = number;

                // Header authorized, discard any previous votes for the signer
                for (int i = 0; i < snapshot.Votes.Count; i++)
                {
                    Vote vote = snapshot.Votes[i];
                    if (vote.Signer == signer && vote.Address == header.Beneficiary)
                    {
                        // Uncast the vote from the cached tally
                        Uncast(snapshot, vote.Address, vote.Authorize);
                        // Uncast the vote from the chronological list
                        snapshot.Votes.RemoveAt(i);
                        break;
                    }
                }

                // Tally up the new vote from the signer
                bool authorize = header.Nonce == Clique.NonceAuthVote;
                if (Cast(snapshot, header.Beneficiary, authorize))
                {
                    Vote vote = new Vote(signer, number, header.Beneficiary, authorize);
                    snapshot.Votes.Add(vote);
                }

                // If the vote passed, update the list of signers
                Tally tally = snapshot.Tally[header.Beneficiary];
                if (tally.Votes > snapshot.Signers.Count / 2)
                {
                    if (tally.Authorize)
                    {
                        snapshot.Signers.Add(header.Beneficiary, 0);
                    }
                    else
                    {
                        snapshot.Signers.Remove(header.Beneficiary);
                    }

                    // Discard any previous votes the deauthorized signer cast
                    for (int i = 0; i < snapshot.Votes.Count; i++)
                    {
                        if (snapshot.Votes[i].Signer == header.Beneficiary)
                        {
                            // Uncast the vote from the cached tally
                            if (Uncast(snapshot, snapshot.Votes[i].Address, snapshot.Votes[i].Authorize))
                            {
                                // Uncast the vote from the chronological list
                                snapshot.Votes.RemoveAt(i);
                                i--;
                            }
                        }
                    }

                    // Discard any previous votes around the just changed account
                    for (int i = 0; i < snapshot.Votes.Count; i++)
                    {
                        if (snapshot.Votes[i].Address == header.Beneficiary)
                        {
                            snapshot.Votes.RemoveAt(i);
                            i--;
                        }
                    }

                    snapshot.Tally.Remove(header.Beneficiary);
                }
            }

            snapshot.Number += headers.Count;

            // was this needed?
//            snapshot.Hash = BlockHeader.CalculateHash(headers[headers.Count - 1]);
            snapshot.Hash = headers[headers.Count - 1].Hash;
            return(snapshot);
        }
Example #2
0
        public Snapshot Apply(List <BlockHeader> headers)
        {
            // Allow passing in no headers for cleaner code
            if (headers.Count == 0)
            {
                return(this);
            }

            // Sanity check that the headers can be applied
            for (int i = 0; i < headers.Count - 1; i++)
            {
                if (headers[i].Number != Number + (UInt256)i + 1)
                {
                    throw new InvalidOperationException("Invalid voting chain");
                }
            }

            // Iterate through the headers and create a new snapshot
            Snapshot snapshot = Clone();

            foreach (BlockHeader header in headers)
            {
                // Remove any votes on checkpoint blocks
                UInt256 number = header.Number;
                if ((ulong)number % Config.Epoch == 0)
                {
                    snapshot.Votes.Clear();
                    snapshot.Tally = new Dictionary <Address, Tally>();
                }

                // Resolve the authorization key and check against signers
                Address signer = header.Author;
                if (!snapshot.Signers.ContainsKey(signer))
                {
                    throw new InvalidOperationException("Unauthorized signer");
                }

                if (HasSignedRecently(snapshot, number, signer))
                {
                    throw new InvalidOperationException("Recently signed");
                }

                snapshot.Signers[signer] = number;

                // Header authorized, discard any previous votes from the signer
                for (int i = 0; i < snapshot.Votes.Count; i++)
                {
                    Vote vote = snapshot.Votes[i];
                    if (vote.Signer == signer && vote.Address == header.Beneficiary)
                    {
                        // Uncast the vote from the cached tally
                        snapshot.Uncast(vote.Address, vote.Authorize);
                        // Uncast the vote from the chronological list
                        snapshot.Votes.RemoveAt(i);
                        break;
                    }
                }

                // Tally up the new vote from the signer
                bool authorize = header.Nonce == Clique.NonceAuthVote;
                if (snapshot.Cast(header.Beneficiary, authorize))
                {
                    Vote vote = new Vote(signer, number, header.Beneficiary, authorize);
                    snapshot.Votes.Add(vote);
                }

                // If the vote passed, update the list of signers
                Tally tally = snapshot.Tally[header.Beneficiary];
                if (tally.Votes > snapshot.Signers.Count / 2)
                {
                    if (tally.Authorize)
                    {
                        snapshot.Signers.Add(header.Beneficiary, 0);
                    }
                    else
                    {
                        snapshot.Signers.Remove(header.Beneficiary);
                    }

                    // Discard any previous votes the deauthorized signer cast
                    for (int i = 0; i < snapshot.Votes.Count; i++)
                    {
                        if (snapshot.Votes[i].Signer == header.Beneficiary)
                        {
                            // Uncast the vote from the cached tally
                            snapshot.Uncast(snapshot.Votes[i].Address, snapshot.Votes[i].Authorize);

                            // Uncast the vote from the chronological list
                            snapshot.Votes.RemoveAt(i);
                            i--;
                        }
                    }

                    // Discard any previous votes around the just changed account
                    for (int i = 0; i < snapshot.Votes.Count; i++)
                    {
                        if (snapshot.Votes[i].Address == header.Beneficiary)
                        {
                            snapshot.Votes.RemoveAt(i);
                            i--;
                        }
                    }

                    snapshot.Tally.Remove(header.Beneficiary);
                }
            }

            snapshot.Number += (ulong)headers.Count;
            snapshot.Hash    = BlockHeader.CalculateHash(headers[headers.Count - 1]);
            return(snapshot);
        }