mirror of
https://github.com/3b1b/manim.git
synced 2025-11-15 20:37:45 +00:00
VariableProofOfWork in crypto
This commit is contained in:
parent
9edccb116e
commit
1951457b89
2 changed files with 334 additions and 14 deletions
347
crypto.py
347
crypto.py
|
|
@ -159,11 +159,11 @@ class AskQuestion(Scene):
|
||||||
self.dither(self.time_per_char*n_spaces)
|
self.dither(self.time_per_char*n_spaces)
|
||||||
self.dither(2)
|
self.dither(2)
|
||||||
|
|
||||||
class BitcoinPaperHighlightTitle(ExternallyAnimatedScene):
|
# class BitcoinPaperHighlightTitle(ExternallyAnimatedScene):
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
class TimeBitcoinCover(ExternallyAnimatedScene):
|
# class TimeBitcoinCover(ExternallyAnimatedScene):
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
class ListOfAttributes(Scene):
|
class ListOfAttributes(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
|
@ -217,14 +217,85 @@ class UnknownAuthor(Scene):
|
||||||
)
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
class NameCryptoCurrencies(TeacherStudentsScene):
|
class DisectQuestion(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
words = TextMobject("It's called a", "``cryptocurrency''")
|
self.hold_up_question()
|
||||||
words.highlight_by_tex("cryptocurrency", YELLOW)
|
self.list_topics()
|
||||||
self.teacher_says(words)
|
self.isolate_you()
|
||||||
|
|
||||||
|
def hold_up_question(self):
|
||||||
|
question = TextMobject(
|
||||||
|
"What does it mean to", "have", "a", "Bitcoin?"
|
||||||
|
)
|
||||||
|
question.highlight_by_tex("have", YELLOW)
|
||||||
|
question.next_to(self.teacher, UP)
|
||||||
|
question.to_edge(RIGHT, buff = LARGE_BUFF)
|
||||||
|
question.save_state()
|
||||||
|
question.shift(DOWN)
|
||||||
|
question.set_fill(opacity = 0)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
self.teacher.change, "raise_right_hand",
|
||||||
|
question.restore
|
||||||
|
)
|
||||||
self.change_student_modes(*["pondering"]*3)
|
self.change_student_modes(*["pondering"]*3)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
self.bitcoin_word = question.get_part_by_tex("Bitcoin")
|
||||||
|
|
||||||
|
def list_topics(self):
|
||||||
|
topics = TextMobject(
|
||||||
|
"Digital signatures, ",
|
||||||
|
"Proof of work, ",
|
||||||
|
"Cryptographic hash functions, \\dots"
|
||||||
|
)
|
||||||
|
topics.scale_to_fit_width(2*SPACE_WIDTH - LARGE_BUFF)
|
||||||
|
topics.to_edge(UP)
|
||||||
|
topics.highlight_by_tex("Digital", BLUE)
|
||||||
|
topics.highlight_by_tex("Proof", GREEN)
|
||||||
|
topics.highlight_by_tex("hash", YELLOW)
|
||||||
|
|
||||||
|
for word in topics:
|
||||||
|
anims = [Write(word, run_time = 1)]
|
||||||
|
self.change_student_modes(
|
||||||
|
*["confused"]*3,
|
||||||
|
added_anims = anims,
|
||||||
|
look_at_arg = word
|
||||||
|
)
|
||||||
|
|
||||||
|
def isolate_you(self):
|
||||||
|
self.pi_creatures = VGroup()
|
||||||
|
you = self.students[1]
|
||||||
|
rect = FullScreenFadeRectangle()
|
||||||
|
words = TextMobject("Invent your own")
|
||||||
|
arrow = Arrow(UP, DOWN)
|
||||||
|
arrow.next_to(you, UP)
|
||||||
|
words.next_to(arrow, UP)
|
||||||
|
|
||||||
|
self.play(FadeIn(rect), Animation(you))
|
||||||
|
self.play(
|
||||||
|
Write(words),
|
||||||
|
ShowCreation(arrow),
|
||||||
|
you.change, "erm", words
|
||||||
|
)
|
||||||
|
self.play(Blink(you))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class CryptocurrencyEquation(Scene):
|
||||||
|
def construct(self):
|
||||||
|
parts = TextMobject(
|
||||||
|
"Ledger",
|
||||||
|
"- Trust",
|
||||||
|
"+ Cryptography",
|
||||||
|
"= Cryptocurrency"
|
||||||
|
)
|
||||||
|
VGroup(*parts[-1][1:]).highlight(YELLOW)
|
||||||
|
parts.scale_to_fit_width(2*SPACE_WIDTH - LARGE_BUFF)
|
||||||
|
|
||||||
|
for part in parts:
|
||||||
|
self.play(FadeIn(part))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
class CryptocurrencyMarketCaps(ExternallyAnimatedScene):
|
class CryptocurrencyMarketCaps(ExternallyAnimatedScene):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -250,9 +321,6 @@ class Hype(TeacherStudentsScene):
|
||||||
)
|
)
|
||||||
self.dither(3)
|
self.dither(3)
|
||||||
|
|
||||||
class AskQuestionCopy(AskQuestion):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class LedgerScene(PiCreatureScene):
|
class LedgerScene(PiCreatureScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"ledger_width" : 6,
|
"ledger_width" : 6,
|
||||||
|
|
@ -3800,7 +3868,6 @@ class AliceRacesOtherMiners(DoubleSpendingAttack):
|
||||||
ff_arrow.target[1].shift(dist*UP)
|
ff_arrow.target[1].shift(dist*UP)
|
||||||
ff_arrow.target.points[-2:] += dist*UP
|
ff_arrow.target.points[-2:] += dist*UP
|
||||||
|
|
||||||
self.revert_to_original_skipping_status()
|
|
||||||
self.play(
|
self.play(
|
||||||
Broadcast(block),
|
Broadcast(block),
|
||||||
*[
|
*[
|
||||||
|
|
@ -3837,8 +3904,9 @@ class AliceRacesOtherMiners(DoubleSpendingAttack):
|
||||||
"Alice", "Miners", "Miners"
|
"Alice", "Miners", "Miners"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
self.revert_to_original_skipping_status()
|
||||||
for winner in winners:
|
for winner in winners:
|
||||||
self.dither(2)
|
self.dither()
|
||||||
if winner == "Alice":
|
if winner == "Alice":
|
||||||
block = self.fraud_block
|
block = self.fraud_block
|
||||||
prev_block = last_fraud_block
|
prev_block = last_fraud_block
|
||||||
|
|
@ -3867,7 +3935,9 @@ class AliceRacesOtherMiners(DoubleSpendingAttack):
|
||||||
else:
|
else:
|
||||||
last_valid_block = block_copy
|
last_valid_block = block_copy
|
||||||
anims.append(Broadcast(block, run_time = 2))
|
anims.append(Broadcast(block, run_time = 2))
|
||||||
|
self.proofs_of_work.remove(block.proof_of_work)
|
||||||
self.play(*anims)
|
self.play(*anims)
|
||||||
|
self.proofs_of_work.add(block.proof_of_work)
|
||||||
|
|
||||||
|
|
||||||
#####
|
#####
|
||||||
|
|
@ -3907,6 +3977,257 @@ class AliceRacesOtherMiners(DoubleSpendingAttack):
|
||||||
result.scale_to_fit_width(0.8*block.get_width())
|
result.scale_to_fit_width(0.8*block.get_width())
|
||||||
result.move_to(block)
|
result.move_to(block)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
class WhenToTrustANewBlock(DistributedBlockChainScene):
|
||||||
|
def construct(self):
|
||||||
|
chain = self.block_chain = self.get_block_chain()
|
||||||
|
chain.scale(2)
|
||||||
|
chain.to_edge(LEFT)
|
||||||
|
self.add(chain)
|
||||||
|
|
||||||
|
words = map(TextMobject, [
|
||||||
|
"Don't trust yet",
|
||||||
|
"Still don't trust",
|
||||||
|
"...a little more...",
|
||||||
|
"Maybe trust",
|
||||||
|
"Probably safe",
|
||||||
|
"Alright, you're good."
|
||||||
|
])
|
||||||
|
colors = [RED, RED, YELLOW, YELLOW, GREEN, GREEN]
|
||||||
|
self.add_new_block()
|
||||||
|
arrow = Arrow(UP, DOWN, color = RED)
|
||||||
|
arrow.next_to(chain.blocks[-1], UP)
|
||||||
|
for word, color in zip(words, colors):
|
||||||
|
word.highlight(color)
|
||||||
|
word.next_to(arrow, UP)
|
||||||
|
word = words[0]
|
||||||
|
self.play(
|
||||||
|
FadeIn(word),
|
||||||
|
ShowCreation(arrow)
|
||||||
|
)
|
||||||
|
for new_word in words[1:]:
|
||||||
|
kwargs = {
|
||||||
|
"run_time" : 3,
|
||||||
|
"rate_func" : squish_rate_func(smooth, 0.7, 1)
|
||||||
|
}
|
||||||
|
self.add_new_block(
|
||||||
|
Transform(word, new_word, **kwargs),
|
||||||
|
ApplyMethod(
|
||||||
|
arrow.highlight, new_word.get_color(),
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
def get_block(self):
|
||||||
|
block = DistributedBlockChainScene.get_block(self)
|
||||||
|
tuples = [
|
||||||
|
("Prev hash", UP, BLUE),
|
||||||
|
("Proof of work", DOWN, GREEN),
|
||||||
|
]
|
||||||
|
for word, vect, color in tuples:
|
||||||
|
mob = TextMobject(word)
|
||||||
|
mob.highlight(color)
|
||||||
|
mob.scale_to_fit_height(0.07*block.get_height())
|
||||||
|
mob.next_to(
|
||||||
|
block.get_edge_center(vect), -vect,
|
||||||
|
buff = 0.06*block.get_height()
|
||||||
|
)
|
||||||
|
block.add(mob)
|
||||||
|
attr = word.lower().replace(" ", "_")
|
||||||
|
setattr(block, attr, mob)
|
||||||
|
transactions = TextMobject("$\\langle$Transactions$\\rangle$")
|
||||||
|
transactions.scale_to_fit_width(0.8*block.get_width())
|
||||||
|
transactions.move_to(block)
|
||||||
|
block.add(transactions)
|
||||||
|
return block
|
||||||
|
|
||||||
|
def add_new_block(self, *added_anims):
|
||||||
|
blocks = self.block_chain.blocks
|
||||||
|
arrows = self.block_chain.arrows
|
||||||
|
block = blocks[-1].copy()
|
||||||
|
arrow = arrows[-1].copy()
|
||||||
|
VGroup(block, arrow).next_to(blocks[-1], RIGHT, buff = 0)
|
||||||
|
corner = SPACE_WIDTH*RIGHT + SPACE_HEIGHT*UP
|
||||||
|
block.save_state()
|
||||||
|
block.next_to(corner, UP+RIGHT)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Broadcast(block),
|
||||||
|
ApplyMethod(
|
||||||
|
block.restore,
|
||||||
|
run_time = 3,
|
||||||
|
rate_func = squish_rate_func(smooth, 0.3, 0.8),
|
||||||
|
),
|
||||||
|
ShowCreation(
|
||||||
|
arrow,
|
||||||
|
run_time = 3,
|
||||||
|
rate_func = squish_rate_func(smooth, 0.7, 1),
|
||||||
|
),
|
||||||
|
*added_anims
|
||||||
|
)
|
||||||
|
arrows.add(arrow)
|
||||||
|
blocks.add(block)
|
||||||
|
|
||||||
|
class VariableProofOfWork(WhenToTrustANewBlock):
|
||||||
|
CONFIG = {
|
||||||
|
"block_height" : 3,
|
||||||
|
"block_width" : 3,
|
||||||
|
"n_guesses" : 60,
|
||||||
|
"n_proof_of_work_digits" : 11,
|
||||||
|
"n_miners" : 6,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.add_miner_and_hash()
|
||||||
|
self.change_requirement()
|
||||||
|
self.add_more_miners()
|
||||||
|
|
||||||
|
def add_miner_and_hash(self):
|
||||||
|
miner = PiCreature(color = GREY)
|
||||||
|
miner.scale(0.7)
|
||||||
|
miner.to_edge(LEFT)
|
||||||
|
|
||||||
|
block = self.get_block()
|
||||||
|
block.next_to(miner, RIGHT)
|
||||||
|
old_proof_of_work = block.proof_of_work
|
||||||
|
proof_of_work = self.get_rand_int_mob()
|
||||||
|
proof_of_work.replace(old_proof_of_work, dim_to_match = 1)
|
||||||
|
block.remove(old_proof_of_work)
|
||||||
|
block.add(proof_of_work)
|
||||||
|
block.proof_of_work = proof_of_work
|
||||||
|
|
||||||
|
arrow = Arrow(LEFT, RIGHT)
|
||||||
|
arrow.next_to(block)
|
||||||
|
sha_tex = TextMobject("SHA256")
|
||||||
|
sha_tex.scale(0.7)
|
||||||
|
sha_tex.next_to(arrow, UP, SMALL_BUFF)
|
||||||
|
sha_tex.highlight(YELLOW)
|
||||||
|
arrow.add(sha_tex)
|
||||||
|
|
||||||
|
digest = sha256_tex_mob("Random")
|
||||||
|
digest.next_to(arrow.get_end(), RIGHT)
|
||||||
|
|
||||||
|
miner.change("pondering", digest)
|
||||||
|
|
||||||
|
self.add(miner, block, arrow, digest)
|
||||||
|
for x in range(self.n_guesses):
|
||||||
|
new_pow = self.get_rand_int_mob()
|
||||||
|
new_pow.replace(proof_of_work, dim_to_match = 1)
|
||||||
|
Transform(proof_of_work, new_pow).update(1)
|
||||||
|
if x == self.n_guesses-1:
|
||||||
|
n_zeros = 60
|
||||||
|
else:
|
||||||
|
n_zeros = 0
|
||||||
|
new_digest = sha256_tex_mob(str(x+1), n_zeros)
|
||||||
|
new_digest.replace(digest)
|
||||||
|
Transform(digest, new_digest).update(1)
|
||||||
|
self.dither(1./20)
|
||||||
|
proof_of_work.highlight(GREEN)
|
||||||
|
VGroup(*digest[:60]).highlight(YELLOW)
|
||||||
|
|
||||||
|
self.miner = miner
|
||||||
|
self.block = block
|
||||||
|
self.arrow = arrow
|
||||||
|
self.digest = digest
|
||||||
|
|
||||||
|
def change_requirement(self):
|
||||||
|
digest = self.digest
|
||||||
|
requirement = TextMobject(
|
||||||
|
"Must start with \\\\",
|
||||||
|
"60", "zeros"
|
||||||
|
)
|
||||||
|
requirement.next_to(digest, UP, MED_LARGE_BUFF)
|
||||||
|
self.n_zeros_mob = requirement.get_part_by_tex("60")
|
||||||
|
self.n_zeros_mob.highlight(YELLOW)
|
||||||
|
|
||||||
|
self.play(Write(requirement, run_time = 2))
|
||||||
|
self.dither(2)
|
||||||
|
for n_zeros in 30, 32, 35, 37, 42:
|
||||||
|
self.change_challenge(n_zeros)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def add_more_miners(self):
|
||||||
|
miner = self.miner
|
||||||
|
block = self.block
|
||||||
|
miner_block = VGroup(miner, block)
|
||||||
|
target = miner_block.copy()
|
||||||
|
target[1].scale(
|
||||||
|
0.5, about_point = miner.get_right()
|
||||||
|
)
|
||||||
|
copies = VGroup(*[
|
||||||
|
target.copy()
|
||||||
|
for x in range(self.n_miners - 1)
|
||||||
|
])
|
||||||
|
everyone = VGroup(target, *copies)
|
||||||
|
everyone.arrange_submobjects(DOWN)
|
||||||
|
everyone.scale_to_fit_height(2*SPACE_HEIGHT - LARGE_BUFF)
|
||||||
|
everyone.to_corner(UP+LEFT)
|
||||||
|
|
||||||
|
self.play(Transform(miner_block, target))
|
||||||
|
self.play(LaggedStart(FadeIn, copies))
|
||||||
|
self.change_challenge(72)
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
###
|
||||||
|
def change_challenge(self, n_zeros):
|
||||||
|
digest = self.digest
|
||||||
|
proof_of_work = self.block.proof_of_work
|
||||||
|
n_zeros_mob = self.n_zeros_mob
|
||||||
|
|
||||||
|
new_digest = sha256_tex_mob(str(n_zeros), n_zeros)
|
||||||
|
new_digest.move_to(digest)
|
||||||
|
VGroup(*new_digest[:n_zeros]).highlight(YELLOW)
|
||||||
|
new_n_zeros_mob = TexMobject(str(n_zeros))
|
||||||
|
new_n_zeros_mob.move_to(n_zeros_mob)
|
||||||
|
new_n_zeros_mob.highlight(n_zeros_mob.get_color())
|
||||||
|
new_pow = self.get_rand_int_mob()
|
||||||
|
new_pow.replace(proof_of_work, dim_to_match = 1)
|
||||||
|
new_pow.highlight(proof_of_work.get_color())
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Transform(n_zeros_mob, new_n_zeros_mob),
|
||||||
|
Transform(
|
||||||
|
digest, new_digest,
|
||||||
|
submobject_mode = "lagged_start"
|
||||||
|
),
|
||||||
|
Transform(proof_of_work, new_pow),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_rand_int_mob(self):
|
||||||
|
e = self.n_proof_of_work_digits
|
||||||
|
return Integer(random.randint(10**e, 10**(e+1)))
|
||||||
|
|
||||||
|
class CompareBLockTimes(Scene):
|
||||||
|
def construct(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,6 @@ class Mobject(object):
|
||||||
mob.points += total_vector
|
mob.points += total_vector
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def scale(self, scale_factor, about_point = None):
|
def scale(self, scale_factor, about_point = None):
|
||||||
if about_point is not None:
|
if about_point is not None:
|
||||||
self.shift(-about_point)
|
self.shift(-about_point)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue