mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Up to double spending attack in crypto
This commit is contained in:
parent
fb408ab80d
commit
9edccb116e
1 changed files with 387 additions and 12 deletions
399
crypto.py
399
crypto.py
|
@ -3520,18 +3520,393 @@ class TwoBlockChains(DistributedBlockChainScene):
|
|||
self.randy = randy
|
||||
return VGroup(randy)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ReplaceCentralAuthorityWithWork(Scene):
|
||||
def construct(self):
|
||||
trust, central = words = TextMobject("Trust", "central authority")
|
||||
words.scale(1.5)
|
||||
cross = Cross(central)
|
||||
work = TextMobject("computational work")
|
||||
work.scale(1.5)
|
||||
work.move_to(central, LEFT)
|
||||
work.highlight(YELLOW)
|
||||
|
||||
self.play(Write(words))
|
||||
self.play(ShowCreation(cross))
|
||||
central.add(cross)
|
||||
self.play(
|
||||
central.shift, DOWN,
|
||||
Write(work)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class AskAboutTrustingWork(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
mode = "raise_left_hand"
|
||||
self.student_says(
|
||||
"Is trusting work \\\\ really enough?",
|
||||
target_mode = mode,
|
||||
)
|
||||
self.change_student_modes("confused", mode, "erm")
|
||||
self.dither(3)
|
||||
|
||||
class DoubleSpendingAttack(DistributedBlockChainScene):
|
||||
CONFIG = {
|
||||
"fraud_block_height" : 3,
|
||||
}
|
||||
def construct(self):
|
||||
self.initialize_characters()
|
||||
self.show_fraudulent_block()
|
||||
self.send_to_bob()
|
||||
self.dont_send_to_rest_of_network()
|
||||
|
||||
def initialize_characters(self):
|
||||
network = self.get_large_network()
|
||||
network.scale(0.7)
|
||||
block_chains = self.get_distributed_ledgers()
|
||||
self.add(network, block_chains)
|
||||
self.play(self.alice.change, "conniving")
|
||||
self.dither()
|
||||
|
||||
def show_fraudulent_block(self):
|
||||
block = self.get_fraud_block()
|
||||
block.next_to(self.alice, LEFT, LARGE_BUFF)
|
||||
block.remove(block.content)
|
||||
self.play(
|
||||
ShowCreation(block),
|
||||
Write(block.content),
|
||||
self.alice.change, "raise_left_hand"
|
||||
)
|
||||
block.add(block.content)
|
||||
self.dither()
|
||||
|
||||
self.block = block
|
||||
|
||||
def send_to_bob(self):
|
||||
block = self.block.copy()
|
||||
block.generate_target()
|
||||
block.target.replace(
|
||||
self.bob.block_chain.blocks[-1],
|
||||
stretch = True
|
||||
)
|
||||
arrow = self.bob.block_chain.arrows[-1].copy()
|
||||
VGroup(arrow, block.target).next_to(
|
||||
self.bob.block_chain.blocks[-1], RIGHT, buff = 0
|
||||
)
|
||||
|
||||
self.play(
|
||||
MoveToTarget(block),
|
||||
self.alice.change, "happy"
|
||||
)
|
||||
self.play(ShowCreation(arrow))
|
||||
self.dither()
|
||||
|
||||
def dont_send_to_rest_of_network(self):
|
||||
bubble = ThoughtBubble()
|
||||
words = TextMobject("Alice", "never \\\\ paid", "Bob")
|
||||
for name in "Alice", "Bob":
|
||||
words.highlight_by_tex(name, self.get_color_from_name(name))
|
||||
bubble.add_content(words)
|
||||
bubble.resize_to_content()
|
||||
bubble.add(*bubble.content)
|
||||
bubble.move_to(self.you.get_corner(UP+RIGHT), DOWN+LEFT)
|
||||
|
||||
self.play(
|
||||
self.charlie.change, "shruggie",
|
||||
self.you.change, "shruggie",
|
||||
)
|
||||
self.play(LaggedStart(FadeIn, bubble))
|
||||
self.play(self.bob.change, "confused", words)
|
||||
self.dither(2)
|
||||
|
||||
###
|
||||
|
||||
def get_fraud_block(self):
|
||||
block = self.get_block()
|
||||
block.scale_to_fit_height(self.fraud_block_height)
|
||||
content = VGroup()
|
||||
|
||||
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()
|
||||
)
|
||||
content.add(mob)
|
||||
attr = word.lower().replace(" ", "_")
|
||||
setattr(block, attr, mob)
|
||||
|
||||
payment = TextMobject("Alice", "pays", "Bob", "100 LD")
|
||||
for name in "Alice", "Bob":
|
||||
payment.highlight_by_tex(name, self.get_color_from_name(name))
|
||||
payment.highlight_by_tex("LD", YELLOW)
|
||||
payments = VGroup(
|
||||
TexMobject("\\vdots"),
|
||||
payment,
|
||||
TexMobject("\\vdots")
|
||||
)
|
||||
payments.arrange_submobjects(DOWN)
|
||||
payments.scale_to_fit_width(0.9*block.get_width())
|
||||
payments.move_to(block)
|
||||
content.add(payments)
|
||||
|
||||
block.content = content
|
||||
block.add(content)
|
||||
return block
|
||||
|
||||
class AliceRacesOtherMiners(DoubleSpendingAttack):
|
||||
CONFIG = {
|
||||
"n_frames_per_pow" : 3,
|
||||
"fraud_block_height" : 2,
|
||||
"n_miners" : 3,
|
||||
"n_proof_of_work_digits" : 11,
|
||||
"proof_of_work_update_counter" : 0,
|
||||
}
|
||||
def construct(self):
|
||||
self.initialize_characters()
|
||||
self.find_proof_of_work()
|
||||
self.receive_broadcast_from_other_miners()
|
||||
self.race_between_alice_and_miners()
|
||||
|
||||
def initialize_characters(self):
|
||||
alice = self.alice
|
||||
bob = self.bob
|
||||
alice_l = VGroup(alice, alice.label)
|
||||
bob_l = VGroup(bob, bob.label)
|
||||
bob_l.move_to(ORIGIN)
|
||||
alice_l.to_corner(UP+LEFT)
|
||||
alice_l.shift(DOWN)
|
||||
self.add(bob_l, alice_l)
|
||||
|
||||
chain = self.get_block_chain()
|
||||
chain.next_to(bob, UP)
|
||||
self.block_chain = chain
|
||||
self.add(chain)
|
||||
|
||||
fraud_block = self.get_fraud_block()
|
||||
fraud_block.next_to(alice, RIGHT)
|
||||
fraud_block.to_edge(UP)
|
||||
proof_of_work = self.get_rand_int_mob()
|
||||
proof_of_work.replace(fraud_block.proof_of_work, dim_to_match = 1)
|
||||
fraud_block.content.remove(fraud_block.proof_of_work)
|
||||
fraud_block.content.add(proof_of_work)
|
||||
fraud_block.proof_of_work = proof_of_work
|
||||
self.fraud_block = fraud_block
|
||||
self.add(fraud_block)
|
||||
|
||||
miners = VGroup(*[
|
||||
PiCreature(color = GREY)
|
||||
for x in range(self.n_miners)
|
||||
])
|
||||
miners.scale_to_fit_height(alice.get_height())
|
||||
miners.arrange_submobjects(RIGHT, buff = LARGE_BUFF)
|
||||
miners.to_edge(DOWN+LEFT)
|
||||
miners.shift(0.5*UP)
|
||||
miners_word = TextMobject("Miners")
|
||||
miners_word.next_to(miners, DOWN)
|
||||
self.miners = miners
|
||||
self.add(miners_word, miners)
|
||||
|
||||
miner_blocks = VGroup()
|
||||
self.proofs_of_work = VGroup()
|
||||
self.add_foreground_mobject(self.proofs_of_work)
|
||||
for miner in miners:
|
||||
block = self.get_block()
|
||||
block.scale_to_fit_width(1.5*miner.get_width())
|
||||
block.next_to(miner, UP)
|
||||
|
||||
transactions = self.get_block_filler(block)
|
||||
block.add(transactions)
|
||||
|
||||
proof_of_work = self.get_rand_int_mob()
|
||||
prev_hash = TextMobject("Prev hash").highlight(BLUE)
|
||||
for mob, vect in (proof_of_work, DOWN), (prev_hash, UP):
|
||||
mob.scale_to_fit_height(0.1*block.get_height())
|
||||
mob.next_to(
|
||||
block.get_edge_center(vect), -vect,
|
||||
buff = 0.05*block.get_height()
|
||||
)
|
||||
block.add(mob)
|
||||
block.proof_of_work = proof_of_work
|
||||
block.prev_hash = prev_hash
|
||||
self.proofs_of_work.add(proof_of_work)
|
||||
|
||||
miner.block = block
|
||||
miner_blocks.add(block)
|
||||
self.add(miner_blocks)
|
||||
|
||||
def find_proof_of_work(self):
|
||||
fraud_block = self.fraud_block
|
||||
chain = self.block_chain
|
||||
|
||||
self.proofs_of_work.add(self.fraud_block.proof_of_work)
|
||||
self.dither(3)
|
||||
self.proofs_of_work.remove(self.fraud_block.proof_of_work)
|
||||
fraud_block.proof_of_work.highlight(GREEN)
|
||||
self.play(
|
||||
Indicate(fraud_block.proof_of_work),
|
||||
self.alice.change, "hooray"
|
||||
)
|
||||
self.dither()
|
||||
|
||||
block = fraud_block.copy()
|
||||
block.generate_target()
|
||||
block.target.replace(chain.blocks[-1], stretch = True)
|
||||
arrow = chain.arrows[-1].copy()
|
||||
VGroup(arrow, block.target).next_to(
|
||||
chain.blocks[-1], RIGHT, buff = 0
|
||||
)
|
||||
self.remove(fraud_block)
|
||||
self.clean_fraud_block_content()
|
||||
self.fraud_fork_head = block
|
||||
self.fraud_fork_arrow = arrow
|
||||
|
||||
self.play(MoveToTarget(block))
|
||||
self.play(ShowCreation(arrow))
|
||||
self.play(self.alice.change, "happy")
|
||||
self.dither()
|
||||
|
||||
def receive_broadcast_from_other_miners(self):
|
||||
winner = self.miners[-1]
|
||||
proof_of_work = winner.block.proof_of_work
|
||||
self.proofs_of_work.remove(proof_of_work)
|
||||
proof_of_work.highlight(GREEN)
|
||||
self.play(
|
||||
Indicate(proof_of_work),
|
||||
winner.change, "hooray"
|
||||
)
|
||||
block = winner.block.copy()
|
||||
proof_of_work.highlight(WHITE)
|
||||
self.remove(winner.block)
|
||||
|
||||
ff_head = self.fraud_fork_head
|
||||
ff_arrow = self.fraud_fork_arrow
|
||||
arrow = ff_arrow.copy()
|
||||
movers = [ff_head, ff_arrow, block, arrow]
|
||||
for mover in movers:
|
||||
mover.generate_target()
|
||||
block.target.replace(ff_head, stretch = True)
|
||||
|
||||
dist = 0.5*ff_head.get_height() + MED_SMALL_BUFF
|
||||
block.target.shift(dist*DOWN)
|
||||
ff_head.target.shift(dist*UP)
|
||||
arrow.target[1].shift(dist*DOWN)
|
||||
arrow.target.points[-2:] += dist*DOWN
|
||||
ff_arrow.target[1].shift(dist*UP)
|
||||
ff_arrow.target.points[-2:] += dist*UP
|
||||
|
||||
self.revert_to_original_skipping_status()
|
||||
self.play(
|
||||
Broadcast(block),
|
||||
*[
|
||||
MoveToTarget(
|
||||
mover, run_time = 3,
|
||||
rate_func = squish_rate_func(smooth, 0.3, 0.8)
|
||||
)
|
||||
for mover in movers
|
||||
]
|
||||
)
|
||||
self.play(
|
||||
FadeIn(winner.block),
|
||||
winner.change_mode, "plain",
|
||||
self.alice.change, "sassy",
|
||||
)
|
||||
self.proofs_of_work.add(winner.block.proof_of_work)
|
||||
self.dither(2)
|
||||
self.play(
|
||||
self.alice.change, "pondering",
|
||||
FadeIn(self.fraud_block)
|
||||
)
|
||||
self.proofs_of_work.add(self.fraud_block.proof_of_work)
|
||||
|
||||
self.valid_fork_head = block
|
||||
|
||||
def race_between_alice_and_miners(self):
|
||||
last_fraud_block = self.fraud_fork_head
|
||||
last_valid_block = self.valid_fork_head
|
||||
chain = self.block_chain
|
||||
winners = [
|
||||
"Alice", "Alice",
|
||||
"Miners", "Miners", "Miners",
|
||||
"Alice", "Miners", "Miners", "Miners",
|
||||
"Alice", "Miners", "Miners"
|
||||
]
|
||||
|
||||
for winner in winners:
|
||||
self.dither(2)
|
||||
if winner == "Alice":
|
||||
block = self.fraud_block
|
||||
prev_block = last_fraud_block
|
||||
else:
|
||||
block = random.choice(self.miners).block
|
||||
prev_block = last_valid_block
|
||||
block_copy = block.deepcopy()
|
||||
block_copy.proof_of_work.highlight(GREEN)
|
||||
block_copy.generate_target()
|
||||
block_copy.target.replace(chain.blocks[1], stretch = True)
|
||||
arrow = chain.arrows[0].copy()
|
||||
VGroup(arrow, block_copy.target).next_to(
|
||||
prev_block, RIGHT, buff = 0
|
||||
)
|
||||
anims = [
|
||||
MoveToTarget(block_copy, run_time = 2),
|
||||
ShowCreation(
|
||||
arrow,
|
||||
run_time = 2,
|
||||
rate_func = squish_rate_func(smooth, 0.5, 1),
|
||||
),
|
||||
FadeIn(block),
|
||||
]
|
||||
if winner == "Alice":
|
||||
last_fraud_block = block_copy
|
||||
else:
|
||||
last_valid_block = block_copy
|
||||
anims.append(Broadcast(block, run_time = 2))
|
||||
self.play(*anims)
|
||||
|
||||
|
||||
#####
|
||||
|
||||
def dither(self, time = 1):
|
||||
self.play(
|
||||
Animation(VGroup(*self.foreground_mobjects)),
|
||||
run_time = time
|
||||
)
|
||||
|
||||
def update_frame(self, *args, **kwargs):
|
||||
self.update_proofs_of_work()
|
||||
Scene.update_frame(self, *args, **kwargs)
|
||||
|
||||
def update_proofs_of_work(self):
|
||||
self.proof_of_work_update_counter += 1
|
||||
if self.proof_of_work_update_counter%self.n_frames_per_pow != 0:
|
||||
return
|
||||
for proof_of_work in self.proofs_of_work:
|
||||
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)
|
||||
|
||||
def get_rand_int_mob(self):
|
||||
e = self.n_proof_of_work_digits
|
||||
return Integer(random.randint(10**e, 10**(e+1)))
|
||||
|
||||
def clean_fraud_block_content(self):
|
||||
content = self.fraud_block.content
|
||||
payments = content[1]
|
||||
content.remove(payments)
|
||||
transactions = self.get_block_filler(self.fraud_block)
|
||||
content.add(transactions)
|
||||
|
||||
def get_block_filler(self, block):
|
||||
result = TextMobject("$\\langle$Transactions$\\rangle$")
|
||||
result.scale_to_fit_width(0.8*block.get_width())
|
||||
result.move_to(block)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue